--- title: Entity Effects type: docs weight: 3 --- Entity effects are status effects that can include visual components, stat modifiers, and duration-based behaviors. ## EntityEffect Configuration ```java public class EntityEffect { protected String id; protected String name; // Localization key protected ApplicationEffects applicationEffects; // Visual/audio effects protected String modelChange; // Change entity model protected float duration; // Default duration (seconds) protected boolean infinite; // Never expires? protected boolean debuff; // Is a negative effect? protected String statusEffectIcon; // UI icon // Damage and stats protected Int2FloatMap entityStats; // Stat modifiers protected ValueType valueType; // Absolute or Percent // Behavior protected OverlapBehavior overlapBehavior; // EXTEND, OVERWRITE, IGNORE protected RemovalBehavior removalBehavior; // COMPLETE, DURATION, INFINITE protected boolean invulnerable; // Grant invulnerability } ``` ## Accessing Effect Assets ```java // Get effect by ID EntityEffect effect = EntityEffect.getAssetMap().getAsset("fire_resistance"); // Get effect index for operations int effectIndex = EntityEffect.getAssetMap().getIndex(effect.getId()); ``` ## EffectControllerComponent The `EffectControllerComponent` manages active effects on an entity: ```java import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent; // Get effect controller from entity EffectControllerComponent controller = store.getComponent( entityRef, EffectControllerComponent.getComponentType() ); ``` ## Adding Effects ### Basic Addition ```java EntityEffect effect = EntityEffect.getAssetMap().getAsset("speed_boost"); // Add with default parameters controller.addEffect( entityRef, effect, componentAccessor ); ``` ### With Custom Duration ```java // Add with custom duration and overlap behavior controller.addEffect( entityRef, effect, 100.0f, // Duration in seconds OverlapBehavior.EXTEND, // How to handle overlap componentAccessor ); ``` ### Infinite Effects ```java // Add an effect that never expires controller.addInfiniteEffect( entityRef, EntityEffect.getAssetMap().getIndex(effect.getId()), effect, componentAccessor ); ``` ## Removing Effects ```java // Remove specific effect controller.removeEffect( entityRef, EntityEffect.getAssetMap().getIndex(effect.getId()), componentAccessor ); ``` ## Overlap Behaviors ```java public enum OverlapBehavior { EXTEND, // Add duration to existing effect OVERWRITE, // Replace existing effect IGNORE // Don't apply if already active } ``` ### Usage Examples ```java // Extend duration if already applied controller.addEffect( entityRef, effect, 30.0f, OverlapBehavior.EXTEND, componentAccessor ); // Replace with fresh duration controller.addEffect( entityRef, effect, 30.0f, OverlapBehavior.OVERWRITE, componentAccessor ); // Only apply if not already active controller.addEffect( entityRef, effect, 30.0f, OverlapBehavior.IGNORE, componentAccessor ); ``` ## Removal Behaviors ```java public enum RemovalBehavior { COMPLETE, // Remove when complete DURATION, // Remove after duration INFINITE // Never remove automatically } ``` ## Value Types for Stats ```java public enum ValueType { Absolute, // Add/subtract flat value Percent // Multiply by percentage } ``` ## Practical Examples ### Buff on Command ```java public class BuffCommand extends AbstractCommand { private final RequiredArg playerArg; private final RequiredArg effectArg; private final RequiredArg durationArg; // Would be set during plugin initialization private Store store; private ComponentAccessor componentAccessor; public BuffCommand() { super("buff", "effects.command.buff.description"); this.playerArg = withRequiredArg("player", "Target player", ArgTypes.PLAYER_REF); this.effectArg = withRequiredArg("effect", "Effect ID", ArgTypes.STRING); this.durationArg = withRequiredArg("duration", "Duration in seconds", ArgTypes.INTEGER); } @Override protected CompletableFuture execute(CommandContext ctx) { PlayerRef target = playerArg.get(ctx); String effectId = effectArg.get(ctx); int duration = durationArg.get(ctx); Ref entityRef = target.getReference(); if (entityRef == null || !entityRef.isValid()) { ctx.sender().sendMessage(Message.raw("Player not found")); return null; } EntityEffect effect = EntityEffect.getAssetMap().getAsset(effectId); if (effect == null) { ctx.sender().sendMessage(Message.raw("Unknown effect: " + effectId)); return null; } EffectControllerComponent controller = store.getComponent( entityRef, EffectControllerComponent.getComponentType() ); if (controller != null) { controller.addEffect( entityRef, effect, (float) duration, OverlapBehavior.EXTEND, componentAccessor ); } ctx.sender().sendMessage(Message.raw("Applied " + effectId + " to " + target.getUsername())); return null; } } ``` {{< callout type="warning" >}} **API Notes:** - Use `withRequiredArg()` to define arguments, not `addArgument()` - Use `arg.get(ctx)` to retrieve values, not `ctx.getArg()` - Use `ctx.sender()` not `ctx.getSender()` - Use `target.getUsername()` not `target.getName()` - Use `target.getReference()` to get entity reference (PlayerRef doesn't have `getPlayer()`) {{< /callout >}} ### Damage Over Time Effect ```java public void applyPoison(Player player, float duration, Store store, ComponentAccessor componentAccessor) { EntityEffect poison = EntityEffect.getAssetMap().getAsset("poison"); Ref entityRef = player.getReference(); EffectControllerComponent controller = store.getComponent( entityRef, EffectControllerComponent.getComponentType() ); if (controller != null && poison != null) { controller.addEffect( entityRef, poison, duration, OverlapBehavior.EXTEND, componentAccessor ); } player.sendMessage(Message.raw("You have been poisoned!")); } ``` ### Temporary Invulnerability ```java public void grantInvulnerability(Player player, float seconds, Store store, ComponentAccessor componentAccessor) { EntityEffect invuln = EntityEffect.getAssetMap().getAsset("invulnerability"); Ref entityRef = player.getReference(); EffectControllerComponent controller = store.getComponent( entityRef, EffectControllerComponent.getComponentType() ); if (controller != null && invuln != null) { controller.addEffect( entityRef, invuln, seconds, OverlapBehavior.OVERWRITE, // Fresh duration componentAccessor ); } } ``` ### Clear All Effects ```java public void clearAllEffects(Player player, Store store, ComponentAccessor componentAccessor) { Ref entityRef = player.getReference(); EffectControllerComponent controller = store.getComponent( entityRef, EffectControllerComponent.getComponentType() ); if (controller != null) { // Use the built-in clearEffects method controller.clearEffects( entityRef, componentAccessor ); } player.sendMessage(Message.raw("All effects cleared!")); } ``` ## Combining with Other Effects Entity effects work well with particles and dynamic lights: ```java public void applyMagicBuff(Player player, Store store, ComponentAccessor componentAccessor) { Ref entityRef = player.getReference(); // Apply status effect EntityEffect buff = EntityEffect.getAssetMap().getAsset("magic_power"); EffectControllerComponent controller = store.getComponent( entityRef, EffectControllerComponent.getComponentType() ); if (controller != null && buff != null) { controller.addEffect(entityRef, buff, componentAccessor); } // Add visual glow ColorLight glow = new ColorLight((byte) 10, (byte) 200, (byte) 50, (byte) 255); DynamicLight light = new DynamicLight(glow); componentAccessor.putComponent( entityRef, DynamicLight.getComponentType(), light ); // Get position from TransformComponent for particle spawn TransformComponent transform = store.getComponent(entityRef, TransformComponent.getComponentType()); if (transform != null) { ParticleUtil.spawnParticleEffect( "magic_aura", transform.getPosition(), componentAccessor ); } } ``` {{< callout type="info" >}} **Note:** Use `player.getReference()` to get the entity reference. Position must be obtained from `TransformComponent`, not directly from Player. {{< /callout >}} ## Best Practices {{< callout type="info" >}} **Effect Guidelines:** - Use `EXTEND` for stackable buffs to reward repeated application - Use `OVERWRITE` for effects that should reset duration - Use `IGNORE` to prevent effect stacking when undesired - Always check if effect exists before applying - Consider performance with many simultaneous effects {{< /callout >}}