diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyLifespanData.java b/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyLifespanData.java index cce2a8283..a0e6835f6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyLifespanData.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyLifespanData.java @@ -47,6 +47,10 @@ public class EnergyLifespanData implements IEnergyLifespanData { public void readNBT(NBTTagCompound nbt) { maxDistance = nbt.getFloat("maxDistance"); maxLifetime = nbt.getInteger("maxLifetime"); + + // Sanitize: ensure minimum values so entities don't die instantly or live forever + if (Float.isNaN(maxDistance) || Float.isInfinite(maxDistance) || maxDistance <= 0) maxDistance = 150.0f; + if (maxLifetime <= 0) maxLifetime = 200; } public EnergyLifespanData copy() { diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBeam.java index ca1e1ac47..10643e7f2 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityBeam.java @@ -184,12 +184,12 @@ public class AbilityBeam extends AbilityEnergyProjectile impl defs.add(FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback)); defs.add(FieldDef.section("ability.section.beam")); defs.add(FieldDef.row( - FieldDef.floatField("ability.beamWidth", this::getBeamWidth, this::setBeamWidth), - FieldDef.floatField("ability.headSize", this::getHeadSize, this::setHeadSize) + FieldDef.floatField("ability.beamWidth", this::getBeamWidth, this::setBeamWidth).range(0.1f, 100.0f), + FieldDef.floatField("ability.headSize", this::getHeadSize, this::setHeadSize).range(0.1f, 100.0f) )); defs.add(FieldDef.row( - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).range(1.0f, 500.0f), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).range(1, 1200) )); defs.add(FieldDef.section("ability.section.homing")); defs.add(FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming).hover("ability.hover.homing")); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDisc.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDisc.java index 0fd8b494c..1a9194282 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDisc.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDisc.java @@ -208,14 +208,14 @@ public class AbilityDisc extends AbilityEnergyProjectile impl defs.add(FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback)); defs.add(FieldDef.section("ability.section.disc")); defs.add(FieldDef.row( - FieldDef.floatField("gui.radius", this::getDiscRadius, this::setDiscRadius), - FieldDef.floatField("gui.thickness", this::getDiscThickness, this::setDiscThickness) + FieldDef.floatField("gui.radius", this::getDiscRadius, this::setDiscRadius).range(0.1f, 100.0f), + FieldDef.floatField("gui.thickness", this::getDiscThickness, this::setDiscThickness).range(0.05f, 100.0f) )); defs.add(FieldDef.boolField("ability.vertical", this::isVertical, this::setVertical) .hover("ability.hover.vertical")); defs.add(FieldDef.row( - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).range(1.0f, 500.0f), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).range(1, 1200) )); defs.add(FieldDef.section("ability.section.homing")); defs.add(FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming).hover("ability.hover.homing")); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDome.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDome.java index 2fe0c4572..78a317cc2 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDome.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityDome.java @@ -132,7 +132,7 @@ public class AbilityDome extends AbilityEnergyBarrier { @Override protected void addBarrierTypeDefinitions(List defs) { defs.add(FieldDef.floatField("ability.domeRadius", this::getDomeRadius, this::setDomeRadius) - .range(1.0f, 30.0f)); + .range(1.0f, 50.0f)); defs.add(FieldDef.boolField("ability.followCaster", this::isFollowCaster, this::setFollowCaster) .hover("ability.hover.followCaster")); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyBarrier.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyBarrier.java index 3319b7dc6..f78cf5654 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyBarrier.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityEnergyBarrier.java @@ -247,7 +247,7 @@ public abstract class AbilityEnergyBarrier extends AbilityEnergy { .visibleWhen(this::isUseHealth)); defs.add(FieldDef.boolField("ability.useDuration", this::isUseDuration, this::setUseDuration)); defs.add(FieldDef.intField("ability.duration", this::getBarrierDuration, this::setBarrierDuration) - .range(1, 6000).visibleWhen(this::isUseDuration)); + .range(1, 12000).visibleWhen(this::isUseDuration)); defs.add(FieldDef.floatField("ability.defaultMultiplier", this::getDefaultMultiplier, this::setDefaultMultiplier)); // Knockback section diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityLaserShot.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityLaserShot.java index 4639901d4..0ffa52946 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityLaserShot.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityLaserShot.java @@ -218,14 +218,14 @@ public class AbilityLaserShot extends AbilityEnergyProjectile implem FieldDef.floatField("stats.speed", this::getOrbSpeed, this::setOrbSpeed) )); defs.add(FieldDef.row( - FieldDef.floatField("stats.size", this::getOrbSize, this::setOrbSize), + FieldDef.floatField("stats.size", this::getOrbSize, this::setOrbSize).range(0.1f, 100.0f), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) )); defs.add(FieldDef.row( - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).range(1.0f, 500.0f), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).range(1, 1200) )); defs.add(FieldDef.section("ability.section.homing")); defs.add(FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming).hover("ability.hover.homing")); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityShield.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityShield.java index 5d78e8c1d..f19f9844f 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityShield.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityShield.java @@ -145,8 +145,8 @@ public class AbilityShield extends AbilityEnergyBarrier { @Override protected void addBarrierTypeDefinitions(List defs) { defs.add(FieldDef.row( - FieldDef.floatField("gui.width", this::getShieldWidth, this::setShieldWidth).range(0.5f, 10.0f), - FieldDef.floatField("gui.height", this::getShieldHeight, this::setShieldHeight).range(0.5f, 10.0f) + FieldDef.floatField("gui.width", this::getShieldWidth, this::setShieldWidth).range(0.5f, 100.0f), + FieldDef.floatField("gui.height", this::getShieldHeight, this::setShieldHeight).range(0.5f, 100.0f) )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySlicer.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySlicer.java index b6e08e83b..202938655 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySlicer.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySlicer.java @@ -183,14 +183,14 @@ public class AbilitySlicer extends AbilityEnergyProjectile { defs.add(FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback)); defs.add(FieldDef.section("ability.section.slicer")); defs.add(FieldDef.row( - FieldDef.floatField("gui.width", this::getSliceWidth, this::setSliceWidth).range(0.5f, 20.0f), - FieldDef.floatField("gui.thickness", this::getSliceThickness, this::setSliceThickness).range(0.05f, 2.0f) + FieldDef.floatField("gui.width", this::getSliceWidth, this::setSliceWidth).range(0.5f, 100.0f), + FieldDef.floatField("gui.thickness", this::getSliceThickness, this::setSliceThickness).range(0.05f, 100.0f) )); defs.add(FieldDef.boolField("ability.piercing", this::isPiercing, this::setPiercing) .hover("ability.hover.piercing")); defs.add(FieldDef.row( - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).range(1.0f, 500.0f), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).range(1, 1200) )); defs.add(FieldDef.section("ability.section.explosive")); defs.add(FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive).hover("ability.hover.explosive")); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySweeper.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySweeper.java index 1e0302522..5c9a9fe37 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySweeper.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilitySweeper.java @@ -260,14 +260,14 @@ public class AbilitySweeper extends AbilityEnergy implements IAbilitySweeper { ), FieldDef.section("ability.section.beam"), FieldDef.row( - FieldDef.floatField("gui.length", this::getBeamLength, this::setBeamLength), - FieldDef.floatField("gui.width", this::getBeamWidth, this::setBeamWidth) + FieldDef.floatField("gui.length", this::getBeamLength, this::setBeamLength).range(0.5f, 100.0f), + FieldDef.floatField("gui.width", this::getBeamWidth, this::setBeamWidth).range(0.1f, 100.0f) ), FieldDef.row( - FieldDef.floatField("gui.height", this::getBeamHeight, this::setBeamHeight), - FieldDef.floatField("ability.sweepSpeed", this::getSweepSpeed, this::setSweepSpeed) + FieldDef.floatField("gui.height", this::getBeamHeight, this::setBeamHeight).range(0.1f, 100.0f), + FieldDef.floatField("ability.sweepSpeed", this::getSweepSpeed, this::setSweepSpeed).range(0.1f, 30.0f) ), - FieldDef.intField("ability.rotations", this::getNumberOfRotations, this::setNumberOfRotations), + FieldDef.intField("ability.rotations", this::getNumberOfRotations, this::setNumberOfRotations).range(1, 20), FieldDef.row( FieldDef.boolField("ability.piercing", this::isPiercing, this::setPiercing) .hover("ability.hover.piercing"), diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityWall.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityWall.java index 60680888f..4320177c1 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityWall.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/energy/AbilityWall.java @@ -205,8 +205,8 @@ public class AbilityWall extends AbilityEnergyBarrier { protected void addBarrierTypeDefinitions(List defs) { defs.add(FieldDef.section("ability.section.panel")); defs.add(FieldDef.row( - FieldDef.floatField("gui.width", this::getPanelWidth, this::setPanelWidth).range(0.5f, 20.0f), - FieldDef.floatField("gui.height", this::getPanelHeight, this::setPanelHeight).range(0.5f, 20.0f) + FieldDef.floatField("gui.width", this::getPanelWidth, this::setPanelWidth).range(0.5f, 100.0f), + FieldDef.floatField("gui.height", this::getPanelHeight, this::setPanelHeight).range(0.5f, 100.0f) )); defs.add(FieldDef.floatField("ability.heightOffset", this::getHeightOffset, this::setHeightOffset) .min(Float.NEGATIVE_INFINITY)); diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java index 87cddc415..b80926aab 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java @@ -694,8 +694,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { @Override protected void readProjectileNBT(NBTTagCompound nbt) { - this.beamWidth = nbt.hasKey("BeamWidth") ? nbt.getFloat("BeamWidth") : 0.3f; - this.headSize = nbt.hasKey("HeadSize") ? nbt.getFloat("HeadSize") : 0.5f; + this.beamWidth = sanitize(nbt.hasKey("BeamWidth") ? nbt.getFloat("BeamWidth") : 0.3f, 0.3f, MAX_ENTITY_SIZE); + this.headSize = sanitize(nbt.hasKey("HeadSize") ? nbt.getFloat("HeadSize") : 0.5f, 0.5f, MAX_ENTITY_SIZE); this.headOffsetX = nbt.hasKey("HeadOffsetX") ? nbt.getDouble("HeadOffsetX") : 0; this.headOffsetY = nbt.hasKey("HeadOffsetY") ? nbt.getDouble("HeadOffsetY") : 0; this.headOffsetZ = nbt.hasKey("HeadOffsetZ") ? nbt.getDouble("HeadOffsetZ") : 0; diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java index 2b8a99d07..1f6b8ba0c 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java @@ -38,6 +38,9 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { // Disc shape properties private float discRadius = 1.0f; // Width of disc private float discThickness = 0.2f; // Height of disc + + // Boomerang owner-gone tracking + private int returnOwnerNullTicks = 0; private boolean vertical = false; // false = horizontal (flat), true = vertical (thin edge forward) // Charging state (disc-specific target sizes) @@ -274,6 +277,7 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { if (returning) { Entity owner = getOwnerEntity(); if (owner != null) { + returnOwnerNullTicks = 0; double distToOwner = Math.sqrt( (posX - owner.posX) * (posX - owner.posX) + (posY - owner.posY) * (posY - owner.posY) + @@ -281,8 +285,9 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { ); return distToOwner < 1.5; } - // Owner gone but returning - keep going toward last known position - return false; + // Owner gone while returning - grace period then die + returnOwnerNullTicks++; + return returnOwnerNullTicks > 100; } // Not returning yet - don't die from distance (we'll trigger return above) @@ -487,8 +492,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { protected void readProjectileNBT(NBTTagCompound nbt) { this.boomerang = nbt.hasKey("Boomerang") && nbt.getBoolean("Boomerang"); this.boomerangDelay = nbt.hasKey("BoomerangDelay") ? nbt.getInteger("BoomerangDelay") : 40; - this.discRadius = nbt.hasKey("DiscRadius") ? nbt.getFloat("DiscRadius") : 1.0f; - this.discThickness = nbt.hasKey("DiscThickness") ? nbt.getFloat("DiscThickness") : 0.2f; + this.discRadius = sanitize(nbt.hasKey("DiscRadius") ? nbt.getFloat("DiscRadius") : 1.0f, 1.0f, MAX_ENTITY_SIZE); + this.discThickness = sanitize(nbt.hasKey("DiscThickness") ? nbt.getFloat("DiscThickness") : 0.2f, 0.2f, MAX_ENTITY_SIZE); this.vertical = nbt.hasKey("Vertical") ? nbt.getBoolean("Vertical") : false; this.returning = nbt.hasKey("Returning") && nbt.getBoolean("Returning"); // Charging state (common fields handled by base) diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java index 22880c1ec..08aeb24d7 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java @@ -473,7 +473,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { @Override protected void readProjectileNBT(NBTTagCompound nbt) { - this.laserWidth = nbt.hasKey("LaserWidth") ? nbt.getFloat("LaserWidth") : 0.2f; + this.laserWidth = sanitize(nbt.hasKey("LaserWidth") ? nbt.getFloat("LaserWidth") : 0.2f, 0.2f, MAX_ENTITY_SIZE); this.expansionSpeed = nbt.hasKey("ExpansionSpeed") ? nbt.getFloat("ExpansionSpeed") : 2.0f; this.lingerTicks = nbt.hasKey("LingerTicks") ? nbt.getInteger("LingerTicks") : 10; this.dieOnImpact = nbt.getBoolean("DieOnImpact"); diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilitySweeper.java b/src/main/java/kamkeel/npcs/entity/EntityAbilitySweeper.java index f215ca6d6..af4616654 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilitySweeper.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilitySweeper.java @@ -129,6 +129,12 @@ public class EntityAbilitySweeper extends EntityEnergyAbility { return; } + // Absolute hard lifetime cap (safety net) + if (ticksExisted > HARD_LIFETIME_CAP) { + this.setDead(); + return; + } + Entity owner = getOwnerEntity(); if (owner != null && owner.isDead) { this.setDead(); @@ -330,9 +336,9 @@ public class EntityAbilitySweeper extends EntityEnergyAbility { @Override protected void readEntityFromNBT(NBTTagCompound nbt) { readEnergyBaseNBT(nbt); - this.beamLength = nbt.getFloat("BeamLength"); - this.beamWidth = nbt.getFloat("BeamWidth"); - this.beamHeight = nbt.getFloat("BeamHeight"); + this.beamLength = sanitize(nbt.getFloat("BeamLength"), 10.0f, MAX_ENTITY_SIZE); + this.beamWidth = sanitize(nbt.getFloat("BeamWidth"), 0.3f, MAX_ENTITY_SIZE); + this.beamHeight = sanitize(nbt.getFloat("BeamHeight"), 0.8f, MAX_ENTITY_SIZE); this.sweepSpeed = nbt.getFloat("SweepSpeed"); this.numberOfRotations = nbt.getInteger("NumRotations"); this.completedRotations = nbt.getInteger("CompletedRotations"); diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java index 9721fb60e..2546fb8a2 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java @@ -18,6 +18,13 @@ import net.minecraft.world.World; */ public abstract class EntityEnergyAbility extends Entity implements IEntityAdditionalSpawnData { + // ==================== SAFETY CONSTANTS ==================== + protected static final int CHARGE_TIMEOUT_GRACE = 60; // Ticks of grace after charge should have ended + protected static final int HARD_LIFETIME_CAP = 1200; // 60 seconds absolute max for projectiles/sweepers + protected static final int BARRIER_HARD_LIFETIME_CAP = 12000; // 10 minutes absolute max for barriers + protected static final float MAX_ENTITY_SIZE = 100.0f; // Max size/width/length for any energy entity + protected static final float MAX_ENTITY_RADIUS = 50.0f; // Max radius for dome barriers + // ==================== VISUAL PROPERTIES ==================== protected EnergyDisplayData displayData = new EnergyDisplayData(); protected EnergyLightningData lightningData = new EnergyLightningData(); @@ -272,6 +279,17 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit return 0.0f; } + // ==================== SAFETY HELPERS ==================== + + /** + * Sanitize a float value loaded from NBT or external sources. + * Guards against NaN, Infinity, negative values, and values exceeding a max. + */ + protected static float sanitize(float value, float fallback, float max) { + if (Float.isNaN(value) || Float.isInfinite(value) || value < 0) return fallback; + return Math.min(value, max); + } + // ==================== NBT HELPERS ==================== /** diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java index 7ff4b04c2..afad7be9b 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyBarrier.java @@ -174,6 +174,13 @@ public abstract class EntityEnergyBarrier extends EntityEnergyAbility { return true; } + // Absolute hard lifetime cap (safety net for barriers with no duration) + if (ticksAlive > BARRIER_HARD_LIFETIME_CAP) { + onBarrierDestroyed(); + this.setDead(); + return true; + } + // Reset hit flash if (getHitFlash() > 0) { setHitFlash((byte) (getHitFlash() - 1)); diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java index 6ba436914..9b0c7cb27 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyDome.java @@ -216,8 +216,8 @@ public class EntityEnergyDome extends EntityEnergyBarrier { @Override protected void readEntityFromNBT(NBTTagCompound nbt) { readBarrierBaseNBT(nbt); - this.domeRadius = nbt.getFloat("DomeRadius"); - this.targetDomeRadius = nbt.hasKey("TargetDomeRadius") ? nbt.getFloat("TargetDomeRadius") : domeRadius; + this.domeRadius = sanitize(nbt.getFloat("DomeRadius"), 5.0f, MAX_ENTITY_RADIUS); + this.targetDomeRadius = sanitize(nbt.hasKey("TargetDomeRadius") ? nbt.getFloat("TargetDomeRadius") : domeRadius, 5.0f, MAX_ENTITY_RADIUS); this.followCaster = nbt.hasKey("FollowCaster") && nbt.getBoolean("FollowCaster"); } diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java index 98145836e..7fd617afb 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyPanel.java @@ -365,8 +365,10 @@ public class EntityEnergyPanel extends EntityEnergyBarrier { this.mode = (modeOrdinal >= 0 && modeOrdinal < PanelMode.values().length) ? PanelMode.values()[modeOrdinal] : PanelMode.PLACED; panelData.readNBT(nbt); - this.targetPanelWidth = nbt.hasKey("TargetPanelWidth") ? nbt.getFloat("TargetPanelWidth") : panelData.panelWidth; - this.targetPanelHeight = nbt.hasKey("TargetPanelHeight") ? nbt.getFloat("TargetPanelHeight") : panelData.panelHeight; + panelData.panelWidth = Math.min(panelData.panelWidth, MAX_ENTITY_SIZE); + panelData.panelHeight = Math.min(panelData.panelHeight, MAX_ENTITY_SIZE); + this.targetPanelWidth = sanitize(nbt.hasKey("TargetPanelWidth") ? nbt.getFloat("TargetPanelWidth") : panelData.panelWidth, 3.0f, MAX_ENTITY_SIZE); + this.targetPanelHeight = sanitize(nbt.hasKey("TargetPanelHeight") ? nbt.getFloat("TargetPanelHeight") : panelData.panelHeight, 3.0f, MAX_ENTITY_SIZE); } @Override diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java index b65439f83..7ec72f783 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java @@ -219,6 +219,18 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { } } + // Charging timeout - if charge phase exceeded with grace period, force kill + if (isCharging() && chargeTick > chargeDuration + CHARGE_TIMEOUT_GRACE) { + this.setDead(); + return; + } + + // Absolute hard lifetime cap (safety net for any stuck state) + if (ticksExisted > HARD_LIFETIME_CAP) { + this.setDead(); + return; + } + // Set death time on first tick if not already set (handles chunk load/unload) // Skip during charging phase - lifetime starts when the entity actually fires if (deathWorldTime < 0 && worldObj != null && !isCharging()) { @@ -911,7 +923,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { protected void readBaseNBT(NBTTagCompound nbt) { readEnergyBaseNBT(nbt); - this.size = nbt.getFloat("Size"); + this.size = sanitize(nbt.getFloat("Size"), 1.0f, MAX_ENTITY_SIZE); // Read effects list this.effects.clear(); diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergySlicer.java b/src/main/java/kamkeel/npcs/entity/EntityEnergySlicer.java index 34fc986e6..c24a5ca66 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergySlicer.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergySlicer.java @@ -328,8 +328,8 @@ public class EntityEnergySlicer extends EntityEnergyProjectile { @Override protected void readProjectileNBT(NBTTagCompound nbt) { readChargingNBT(nbt); - this.sliceWidth = nbt.hasKey("SliceWidth") ? nbt.getFloat("SliceWidth") : 3.0f; - this.sliceThickness = nbt.hasKey("SliceThickness") ? nbt.getFloat("SliceThickness") : 0.15f; + this.sliceWidth = sanitize(nbt.hasKey("SliceWidth") ? nbt.getFloat("SliceWidth") : 3.0f, 3.0f, MAX_ENTITY_SIZE); + this.sliceThickness = sanitize(nbt.hasKey("SliceThickness") ? nbt.getFloat("SliceThickness") : 0.15f, 0.15f, MAX_ENTITY_SIZE); this.piercing = !nbt.hasKey("Piercing") || nbt.getBoolean("Piercing"); this.targetSliceWidth = nbt.hasKey("TargetSliceWidth") ? nbt.getFloat("TargetSliceWidth") : sliceWidth; this.targetSliceThickness = nbt.hasKey("TargetSliceThickness") ? nbt.getFloat("TargetSliceThickness") : sliceThickness;