diff --git a/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffect.java b/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffect.java index 40c55eac0..d998f5aa9 100644 --- a/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffect.java +++ b/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffect.java @@ -13,7 +13,6 @@ import com.robertx22.mine_and_slash.database.data.value_calc.LeveledValue; import com.robertx22.mine_and_slash.database.registry.ExileDB; import com.robertx22.mine_and_slash.database.registry.ExileRegistryTypes; -import com.robertx22.mine_and_slash.event_hooks.my_events.EffectUtils; import com.robertx22.mine_and_slash.mmorpg.DebugHud; import com.robertx22.mine_and_slash.mmorpg.SlashRef; import com.robertx22.mine_and_slash.saveclasses.ExactStatData; @@ -271,40 +270,15 @@ public void onRemove(LivingEntity target) { if (spell != null && caster != null) { SpellCtx ctx = SpellCtx.onExpire(caster, target, data.calcSpell); ctx.expiringEffectId = this.GUID(); - ctx.onExpireEffectDurationTicks = (data.onExpireEffectDurationTicks == null) - ? java.util.Collections.emptyMap() - : java.util.Collections.unmodifiableMap(data.onExpireEffectDurationTicks); + // datapack-driven expire logic: handled entirely by attached spell components spell.tryActivate(Spell.DEFAULT_EN_NAME, ctx); // source is default name at all times if (DebugHud.ON_EXPIRE && target instanceof ServerPlayer sp2) { DebugHud.send(sp2, "expire_dispatched_" + GUID(), "[EFFECT][EXPIRE] Dispatched attached spell for " + GUID(), 400); - } - - if (!target.level().isClientSide && data.onExpireEffectDurationTicks != null && !data.onExpireEffectDurationTicks.isEmpty()) { - boolean anyApplied = false; - for (var entry : data.onExpireEffectDurationTicks.entrySet()) { - String effId = entry.getKey(); - int durTicks = Math.max(1, entry.getValue()); - if (ctx.onExpireApplied != null && ctx.onExpireApplied.contains(effId)) { - continue; - } - var extraEff = ExileDB.ExileEffects().get(effId); - if (extraEff == null) { - continue; - } - var instT = EffectUtils.applyEffect(target, extraEff, durTicks, 1, false); - if (instT != null) { - instT.is_infinite = false; - instT.caster_uuid = caster.getStringUUID(); - if (DebugHud.ON_EXPIRE && target instanceof ServerPlayer spx) { - DebugHud.send(spx, "expire_extra_" + effId, "[EFFECT][EXPIRE] Extra-applied " + effId + " tl=" + instT.ticks_left, 400); - } - anyApplied = true; - } - } - if (anyApplied) { - var unitT = Load.Unit(target); - unitT.sync.setDirty(); - } + try { + var comps = spell.getDataForEntity(Spell.DEFAULT_EN_NAME); + int compCount = (comps == null) ? 0 : comps.size(); + DebugHud.send(sp2, "expire_components_" + GUID(), "[EFFECT][EXPIRE] Components=" + compCount, 400); + } catch (Exception ignored) {} } } } diff --git a/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffectInstanceData.java b/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffectInstanceData.java index 041b1fb19..ef9db62de 100644 --- a/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffectInstanceData.java +++ b/src/main/java/com/robertx22/mine_and_slash/database/data/exile_effects/ExileEffectInstanceData.java @@ -9,8 +9,6 @@ import java.text.DecimalFormat; import java.util.UUID; -import java.util.Map; -import java.util.HashMap; public class ExileEffectInstanceData { @@ -24,7 +22,6 @@ public class ExileEffectInstanceData { public float str_multi = 1; public int ticks_left = 0; - public Map onExpireEffectDurationTicks = new HashMap<>(); public boolean isSpellNoLongerAllocated(LivingEntity en) { if (self_cast) { diff --git a/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/ComponentPart.java b/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/ComponentPart.java index 7dbc8b7e0..943fc331e 100644 --- a/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/ComponentPart.java +++ b/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/ComponentPart.java @@ -4,8 +4,6 @@ import com.robertx22.mine_and_slash.database.data.spells.components.conditions.EffectCondition; import com.robertx22.mine_and_slash.database.data.spells.components.selectors.BaseTargetSelector; import com.robertx22.mine_and_slash.database.data.spells.components.selectors.TargetSelector; -import com.robertx22.mine_and_slash.database.registry.ExileDB; -import com.robertx22.mine_and_slash.database.data.spells.components.actions.ExileEffectAction; import com.robertx22.mine_and_slash.database.data.spells.map_fields.MapField; import com.robertx22.mine_and_slash.database.data.spells.spell_classes.SpellCtx; import com.robertx22.mine_and_slash.mmorpg.DebugHud; @@ -141,46 +139,6 @@ public void tryActivate(SpellCtx ctx) { DebugHud.send(spc, "expire_action_" + part.type, "[EFFECT][EXPIRE] Action=" + part.type + " targets=" + list.size(), 400); } } - - if (!ctx.world.isClientSide && ctx.activation == EntityActivation.ON_EXPIRE - && part.type.equals(SpellAction.EXILE_EFFECT.GUID())) { - try { - String actionType = part.get(MapField.POTION_ACTION); - if (actionType == null || !actionType.equals(ExileEffectAction.GiveOrTake.GIVE_STACKS.name())) { - continue; - } - String effId = part.get(MapField.EXILE_POTION_ID); - Double durD = part.getOrDefault(MapField.POTION_DURATION, 0D); - Double cntD = part.getOrDefault(MapField.COUNT, 1D); - int duration = Math.max(1, durD.intValue()); - if (ctx.onExpireEffectDurationTicks != null && ctx.onExpireEffectDurationTicks.containsKey(effId)) { - int override = ctx.onExpireEffectDurationTicks.get(effId); - if (override > 0) { - duration = override; - } - } - int stacks = Math.max(1, cntD.intValue()); - var effect = ExileDB.ExileEffects().get(effId); - if (effect != null) { - for (LivingEntity tgt : list) { - var unit = com.robertx22.mine_and_slash.uncommon.datasaving.Load.Unit(tgt); - var store = unit.getStatusEffectsData(); - var inst = store.getOrCreate(effect); - inst.stacks = Math.max(inst.stacks, stacks); - inst.ticks_left = Math.max(inst.ticks_left, duration); - inst.is_infinite = false; - inst.caster_uuid = ctx.caster.getStringUUID(); - try { effect.onApply(tgt); } catch (Exception ignored) {} - unit.equipmentCache.STATUS.setDirty(); - unit.sync.setDirty(); - if (ctx.caster instanceof ServerPlayer spc) { - DebugHud.send(spc, "expire_fallback_direct_" + effId, "[EFFECT][EXPIRE] Direct-applied " + effId + " tl=" + inst.ticks_left + " x" + inst.stacks, 400); - } - } - ctx.onExpireApplied.add(effId); - } - } catch (Exception ignored) {} - } } } diff --git a/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/actions/ExileEffectAction.java b/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/actions/ExileEffectAction.java index fef387aa7..7e181e670 100644 --- a/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/actions/ExileEffectAction.java +++ b/src/main/java/com/robertx22/mine_and_slash/database/data/spells/components/actions/ExileEffectAction.java @@ -59,10 +59,13 @@ public void tryActivate(Collection targets, SpellCtx ctx, MapHolde targets.forEach(t -> { if (RandomUtils.roll(chance)) { - // If ON_EXPIRE, skip only GIVE_STACKS (handled upstream to avoid same-tick races), - // but DO allow REMOVE_STACKS so consumptions like Overheat work on entity-expire. + // If ON_EXPIRE and we're trying to re-apply the very same expiring effect, skip to avoid + // same-tick reapplication races. Allow GIVE_STACKS for other effects (e.g., Burnout after WOTJ). if (ctx.activation == com.robertx22.mine_and_slash.database.data.spells.components.EntityActivation.ON_EXPIRE - && action == GiveOrTake.GIVE_STACKS) { + && action == GiveOrTake.GIVE_STACKS + && ctx.expiringEffectId != null + && potion != null + && ctx.expiringEffectId.equals(potion.GUID())) { return; } ExilePotionEvent potionEvent = EventBuilder.ofEffect(ctx.calculatedSpellData, ctx.caster, t, Load.Unit(ctx.caster) diff --git a/src/main/java/com/robertx22/mine_and_slash/database/data/spells/spell_classes/SpellCtx.java b/src/main/java/com/robertx22/mine_and_slash/database/data/spells/spell_classes/SpellCtx.java index 677cab702..688444d49 100644 --- a/src/main/java/com/robertx22/mine_and_slash/database/data/spells/spell_classes/SpellCtx.java +++ b/src/main/java/com/robertx22/mine_and_slash/database/data/spells/spell_classes/SpellCtx.java @@ -30,8 +30,6 @@ public class SpellCtx { public String expiringEffectId = null; - public java.util.Map onExpireEffectDurationTicks = java.util.Collections.emptyMap(); - public java.util.Set onExpireApplied = new java.util.HashSet<>(); public SpellCtx setSourceEntity(Entity en) { diff --git a/src/main/java/com/robertx22/mine_and_slash/mechanics/thresholds/datapack/SpendThresholdDef.java b/src/main/java/com/robertx22/mine_and_slash/mechanics/thresholds/datapack/SpendThresholdDef.java index aabccd1df..0a26f329b 100644 --- a/src/main/java/com/robertx22/mine_and_slash/mechanics/thresholds/datapack/SpendThresholdDef.java +++ b/src/main/java/com/robertx22/mine_and_slash/mechanics/thresholds/datapack/SpendThresholdDef.java @@ -90,8 +90,6 @@ public SpendThresholdSpec toSpec() { public void onProc(ServerPlayer sp, int procs) { if (onProc == null || onProc.isEmpty()) return; - var unit = com.robertx22.mine_and_slash.uncommon.datasaving.Load.Unit(sp); - var store = unit.getStatusEffectsData(); for (ProcAction a : onProc) { if (!"exile_effect".equalsIgnoreCase(a.action) || a.effectId == null) continue; @@ -100,19 +98,8 @@ public void onProc(ServerPlayer sp, int procs) { int durTicks = Math.max(1, a.durationTicks); int stacks = Math.max(1, a.stacks); - var inst = EffectUtils.applyEffect(sp, effect, durTicks, stacks); - - if (a.onExpire != null && !a.onExpire.isEmpty()) { - if (inst.onExpireEffectDurationTicks == null) { - inst.onExpireEffectDurationTicks = new java.util.HashMap<>(); - } - for (var e : a.onExpire.entrySet()) { - int ticks = Math.max(0, e.getValue()); - if (ticks > 0) { - inst.onExpireEffectDurationTicks.put(e.getKey(), ticks); - } - } - } + EffectUtils.applyEffect(sp, effect, durTicks, stacks); + } }