package com.mythlane.chainlightning.sceptre; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.server.core.asset.type.entityeffect.config.EntityEffect; import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.mythlane.chainlightning.chain.ChainHit; import javax.annotation.Nonnull; import java.util.List; import java.util.logging.Logger; /** * Phase 4 — Adapter VFX/SFX qui applique un EntityEffect custom à chaque cible touchée. * *
Pivot 14:52 (POC EntityEffect bridge) : les tentatives précédentes via * {@code ParticleUtil.spawnParticleEffect("Splash", ...)} ne rendaient pas les particles côté * client (asset sync plugin custom + budget client → 0/5 visible). On utilise maintenant le * pattern canonique Cleric-Rod : on déclare un {@code EntityEffect} JSON (Server/Entity/Effects/ * Chain_Hit_Effect.json) qui contient des particles vanilla inline + EntityTopTint/BottomTint, * et on applique cet effect à chaque target via {@link EffectControllerComponent#addEffect}. * *
Le rendu passe par la réplication ECS (le ECS state du target propage l'effet aux clients * automatiquement), pas par un packet SpawnParticleSystem standalone. C'est le path éprouvé. * *
Fallback : si le lookup de l'EntityEffect échoue (asset pas chargé), on log et skip. * Pas de propagation : damage déjà appliqué côté caller, l'emit failure ne doit pas crash. * *
Hop-index ignoré pour POC : l'EntityEffect est uniforme sur les 5 cibles. La courbe
* de volume (VFX-02) reste implémentée dans {@code VolumeCurve} mais n'est pas utilisée ici --
* une variante future pourrait définir 5 EntityEffects {@code Chain_Hit_Effect_0..4} avec des
* intensités décroissantes, ou patcher l'EntityEffect existant runtime (non supporté par l'API).
*/
public final class HytaleVfxEmitter {
private static final Logger LOGGER = Logger.getLogger(HytaleVfxEmitter.class.getName());
/** Asset id du EntityEffect appliqué à chaque target touchée par la chaîne. */
private static final String EFFECT_ID = "Chain_Hit_Effect";
private HytaleVfxEmitter() {}
/**
* Applique l'EntityEffect {@code Chain_Hit_Effect} à chaque hit de la chaîne.
*
* @param hits liste résolue par ChainResolver, ordre BFS
* @param playerRef ref du caster (présent pour symétrie d'API future, non utilisé ici --
* l'EntityEffect rend automatiquement à tous les viewers en range)
* @param commandBuffer le CommandBuffer du tick courant (sert pour {@code getComponent} et
* pour propager les changes d'état ECS au tick end)
*/
public static void playChainEffects(@Nonnull List