Skip to content

EffectControllerComponent

The EffectControllerComponent manages status effects on entities - buffs, debuffs, damage over time, stat modifiers, and visual changes.

EffectControllerComponent effects = store.getComponent(ref, EffectControllerComponent.getComponentType());

Effects are defined as JSON assets loaded from Entity/Effects/. Get the effect asset by ID, then apply it:

// get effect by asset ID
EntityEffect slow = EntityEffect.getAssetMap().getAsset("Slow");
// apply with default duration from asset
effects.addEffect(ref, slow, store);
// apply with custom duration (seconds) and overlap behavior
effects.addEffect(ref, slow, 30.0f, OverlapBehavior.OVERWRITE, store);

For permanent effects that don’t expire:

String effectId = "Immunity_Fire";
int effectIndex = EntityEffect.getAssetMap().getIndex(effectId);
EntityEffect effect = EntityEffect.getAssetMap().getAsset(effectId);
effects.addInfiniteEffect(ref, effectIndex, effect, store);

Controls what happens when applying an effect the entity already has:

BehaviorDescription
EXTENDAdd new duration to existing remaining time
OVERWRITEReplace with new duration
IGNOREKeep existing, ignore new application
// stack durations - 10s + 10s = 20s total
effects.addEffect(ref, effect, 10.0f, OverlapBehavior.EXTEND, store);
// reset to fresh duration
effects.addEffect(ref, effect, 10.0f, OverlapBehavior.OVERWRITE, store);
// only apply if not already active
effects.addEffect(ref, effect, 10.0f, OverlapBehavior.IGNORE, store);
int effectIndex = EntityEffect.getAssetMap().getIndex("Slow");
// remove with default behavior from asset
effects.removeEffect(ref, effectIndex, store);
// remove with specific behavior
effects.removeEffect(ref, effectIndex, RemovalBehavior.COMPLETE, store);
BehaviorDescription
COMPLETEFully remove the effect immediately
INFINITERemove infinite flag only (starts counting down)
DURATIONSet remaining duration to 0 (removed on next tick)
effects.clearEffects(ref, store);

Effects are also automatically cleared on death and respawn.

// get all active effects (index -> ActiveEntityEffect)
Int2ObjectMap<ActiveEntityEffect> active = effects.getActiveEffects();
// check if specific effect is active
int effectIndex = EntityEffect.getAssetMap().getIndex("Poison");
boolean hasPosion = active.containsKey(effectIndex);
// get active effect indexes as array
int[] indexes = effects.getActiveEffectIndexes();
// check invulnerability (any effect granting it)
boolean invulnerable = effects.isInvulnerable();

Each active effect instance provides:

ActiveEntityEffect active = effects.getActiveEffects().get(effectIndex);
float remaining = active.getRemainingDuration(); // seconds left
float initial = active.getInitialDuration(); // original duration
boolean infinite = active.isInfinite(); // never expires
boolean debuff = active.isDebuff(); // negative effect
boolean invuln = active.isInvulnerable(); // grants damage immunity
int index = active.getEntityEffectIndex(); // asset index

Effects are defined as JSON assets loaded from Entity/Effects/. Key properties:

{
"Duration": 10.0,
"Infinite": false,
"Debuff": false,
"StatusEffectIcon": "UI/StatusEffects/MyEffect.png",
"OverlapBehavior": "Extend",
"RemovalBehavior": "Complete",
"Invulnerable": false
}

Effects can inherit from a parent:

{
"Parent": "Poison",
"Duration": 8.0
}
PropertyDefault
Duration0.0 (instant)
Infinitefalse
Debufffalse
Invulnerablefalse
OverlapBehaviorIgnore
RemovalBehaviorComplete
ValueTypeAbsolute

Stat modifiers adjust a stat’s min or max bound for the duration of the effect. For a list of available stats and the programmatic modifier API, see Entity Stats.

Simple stat modifiers with a value type:

{
"StatModifiers": {
"Health": 5,
"Stamina": 1.5
},
"ValueType": "Percent"
}
ValueTypeDescription
PercentModifier is a percentage
AbsoluteModifier is an absolute value

For more control, use RawStatModifiers with per-stat modifier arrays:

{
"RawStatModifiers": {
"Health": [
{ "Amount": 30, "CalculationType": "Additive", "Target": "Max" }
]
}
}

CalculationType can be Additive or Multiplicative.

For poison, burning, etc. BaseDamage maps damage causes to values:

{
"DamageCalculator": {
"BaseDamage": {
"Fire": 5
}
},
"DamageCalculatorCooldown": 1.0,
"DamageEffects": {
"WorldSoundEventId": "SFX_Effect_Burn_World",
"PlayerSoundEventId": "SFX_Effect_Burn_Local"
}
}

DamageCalculatorCooldown sets seconds between damage ticks.

{
"ApplicationEffects": {
"EntityBottomTint": "#100600",
"EntityTopTint": "#cf2302",
"EntityAnimationId": "Hurt",
"Particles": [
{ "SystemId": "Effect_Fire", "TargetEntityPart": "Entity", "TargetNodeName": "Head" }
],
"ScreenEffect": "ScreenEffects/Fire.png",
"LocalSoundEventId": "SFX_Effect_Burn_Local",
"WorldSoundEventId": "SFX_Effect_Burn_World",
"ModelVFXId": "Burn"
}
}

Tint values are hex color strings. Particles support SystemId, TargetEntityPart, TargetNodeName, PositionOffset, and Color.

{
"ApplicationEffects": {
"HorizontalSpeedMultiplier": 0.5,
"KnockbackMultiplier": 0,
"MovementEffects": { "DisableAll": true },
"MouseSensitivityAdjustmentTarget": 0.25,
"MouseSensitivityAdjustmentDuration": 0.1
}
}

MovementEffects supports DisableAll (freezes entity) and DisableSprint.

Temporarily replace entity model (uses entity type IDs):

{
"ModelChange": "Corgi"
}

Or override model, texture, and animations:

{
"ModelOverride": {
"Model": "VFX/Spells/Roots/Model.blockymodel",
"Texture": "VFX/Spells/Roots/Model.png",
"AnimationSets": {
"Spawn": {
"Animations": [{ "Animation": "VFX/Spells/Roots/Spawn.blockyanim", "Looping": false }]
}
}
}
}

Disable specific interaction types while effect is active:

{
"ApplicationEffects": {
"AbilityEffects": {
"Disabled": ["Primary", "Secondary", "Ability1", "Ability3"]
}
}
}

Available interaction types: Primary, Secondary, Ability1, Ability2, Ability3, Use, Pick, Pickup, Dodge, Held, HeldOffhand, Equipped, etc.

Grant resistance to damage causes:

{
"DamageResistance": {
"Fire": [{ "Amount": 1.0, "CalculationType": "Multiplicative" }],
"Environmental": [{ "Amount": 1.0, "CalculationType": "Multiplicative" }]
}
}

CalculationType can be Additive or Multiplicative. Amount of 1.0 with multiplicative = full immunity.

Effects are loaded from Entity/Effects/ in the asset directory. The asset ID is the filename without .json.

Effect IDDurationDebuffDescription
Burn3sYesFire damage (5/sec), cancelled in water
Lava_Burn5s-Lava-specific burn variant
Poison16sYesPoison damage (10 per 5s), extends on reapply
Poison_T1 / T216s-Tiered poison (spider, scarak)
Poison_T331s-Strong poison (snapdragon)
Stun10s-Disables movement (DisableAll) and abilities
Freezeinstant-Disables all movement, ice visuals
Slow10s-50% horizontal speed reduction
Root10s-Disables movement, 0 knockback, model override
Immune20sNoInvulnerability with green tint
Antidote120sNoPoison cure
Effect IDDescription
Stamina_BrokenApplied when stamina depleted (hardcoded default)
Stamina_Broken_ImmuneBrief immunity after stamina break
Stamina_Error_StateVisual flash when stamina insufficient
Stamina_Regen_Delay_ActionDelays stamina regen after actions
Dodge_InvulnerabilityBrief invulnerability during dodge
Dodge_Left / Dodge_RightDodge movement effects
Red_FlashRed tint on damage hit
Effect IDDescription
Food_Instant_Heal_T1 / T2 / T3Tiered instant healing
Food_Health_Regen_Tiny / Small / Medium / LargeHealth regeneration
Food_Health_Boost_Tiny / Small / Medium / LargeMax health boost (RawStatModifiers)
Food_Stamina_Regen_Tiny / Small / Medium / LargeStamina regeneration
Food_Stamina_Boost_Tiny / Small / Medium / LargeMax stamina boost (RawStatModifiers)
Potion_Health_Instant_Lesser / GreaterHealth potions
Potion_Stamina_Instant_Lesser / GreaterStamina potions
Potion_Morph_Dog / Frog / Mouse / Pigeon / MosshornMorph potions (60s, ModelChange)
Effect IDDescription
Mana / Mana_High / Mana_LowMana regeneration (varying rates)
Mana_DrainMana drain (negative stat modifier)
Mana_Regen / Mana_Regen_High / Mana_Regen_LowMana regen buffs
Effect IDDescription
Immunity_EnvironmentalFull environmental damage resistance
Immunity_FireFull fire damage resistance
Effect IDDescription
Mace_SignatureMace signature ability
Battleaxe_WhirlwindBattleaxe spin attack
Battleaxe_Downstrike_JumpBattleaxe downstrike jump
Dagger_Signature / Dash / PounceDagger abilities
Sword_Signature_SpinStabSword spin-stab
FlamethrowerSourceFire staff secondary
Flame_Staff_BurnFire staff projectile burn
Intangible_Dark / Intangible_SmolIntangibility effects
Effect IDDescription
Bomb_Explode_StunBomb explosion stun
Crossbow_Combo_1 / Combo_2Crossbow combo stages
Two_Handed_Bow_Ability2_SlowTwo-handed bow ability slow
Rubble_Hit / Rubble_MissRubble impact particles
Effect IDDescription
Healing_Totem_HealHealing totem area heal
Slowness_Totem_SlowSlowness totem area slow
Npc_Heal_LowNPC low heal
Return_Home_HealingNPC returning home heal
Death (NPC)NPC death effect
Effect IDDescription
Drop_Uncommon / Rare / Epic / LegendaryDrop rarity visuals
Effect IDDescription
BlockPlaceSuccess / BlockPlaceFailBlock placement feedback
CreativeCreative mode activation visual
Portal_TeleportPortal teleportation effect
EffectControllerComponent effects = store.getComponent(ref, EffectControllerComponent.getComponentType());
if (effects == null) return;
EntityEffect slow = EntityEffect.getAssetMap().getAsset("Slow");
effects.addEffect(ref, slow, 10.0f, OverlapBehavior.OVERWRITE, store);
int poisonIndex = EntityEffect.getAssetMap().getIndex("Poison");
if (effects.getActiveEffects().containsKey(poisonIndex)) {
effects.removeEffect(ref, poisonIndex, RemovalBehavior.COMPLETE, store);
}
int effectIndex = EntityEffect.getAssetMap().getIndex(effectId);
ActiveEntityEffect active = effects.getActiveEffects().get(effectIndex);
if (active != null && active.isInfinite()) {
// remove infinite flag - effect starts counting down
effects.removeEffect(ref, effectIndex, RemovalBehavior.INFINITE, store);
}
CommandDescription
/player effect apply <player> <effect> [duration]Apply effect to player
/player effect clear <player>Remove all effects from player
/entity effect <entity> <effect> [duration]Apply effect to any entity

The “Burn” effect is automatically cancelled when the entity enters water. This is handled by LivingEntityEffectSystem.canApplyEffect().

All effects are automatically cleared when an entity dies or a player respawns.

Effect changes are synced to clients via ComponentUpdateType.EntityEffects. The client receives:

  • Effect index
  • Remaining duration
  • Whether infinite
  • Whether debuff
  • Status icon for UI

No effect events: There are no dedicated events for effect application or removal. Monitor effects by checking getActiveEffects() or use the interaction system’s EffectConditionInteraction for conditional logic.

Death messages: Effects that deal damage can customize death messages via the Locale property. The effect implements Damage.Source internally. See Death for how death processing works.

Effect conditions: The LivingEntityEffectSystem.canApplyEffect() method handles special cases - currently only the “Burn” effect is cancelled when the entity is in water.