Files
CustomNPC-Plus/src/main/java/kamkeel/npcs/entity/EntityEnergyAbility.java
T
2026-02-22 03:28:56 -05:00

381 lines
11 KiB
Java

package kamkeel.npcs.entity;
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyDisplayData;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLightningData;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
/**
* Universal base class for all energy ability entities (Projectiles, Barriers, Sweeper).
* Provides shared visual data, owner tracking, charging state, and common entity properties.
*/
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();
// Client-side lightning state (not saved to NBT)
@SideOnly(Side.CLIENT)
public transient Object lightningState; // Actually AttachedLightningRenderer.LightningState
// ==================== TRACKING ====================
protected int ownerEntityId = -1;
// ==================== STATE ====================
/**
* The ability that spawned this entity. Transient, not saved to NBT.
*/
protected transient Ability sourceAbility = null;
protected boolean previewMode = false;
protected EntityLivingBase previewOwner = null;
// ==================== CHARGING STATE ====================
protected boolean charging = false;
protected int chargeDuration = 0;
protected int chargeTick = 0;
protected static final int DW_CHARGING = 20;
public EntityEnergyAbility(World world) {
super(world);
this.isImmuneToFire = true;
this.ignoreFrustumCheck = true;
}
@Override
protected void entityInit() {
this.dataWatcher.addObject(DW_CHARGING, (byte) 0);
}
// ==================== CHARGING ====================
/**
* Check if entity is in charging state (synced via data watcher).
* In preview mode, uses local field since data watcher isn't synced.
*/
public boolean isCharging() {
if (previewMode) return this.charging;
return this.dataWatcher.getWatchableObjectByte(DW_CHARGING) == 1;
}
/**
* Set charging state (server only, synced to clients via data watcher).
*/
public void setCharging(boolean value) {
this.charging = value;
if (!worldObj.isRemote) {
this.dataWatcher.updateObject(DW_CHARGING, (byte) (value ? 1 : 0));
}
}
public void setChargeDuration(int duration) {
this.chargeDuration = duration;
}
public float getChargeProgress() {
if (chargeDuration <= 0) return 1.0f;
return Math.min(1.0f, (float) chargeTick / chargeDuration);
}
public float getInterpolatedChargeProgress(float partialTicks) {
if (chargeDuration <= 0) return 1.0f;
float prevProgress = Math.max(0, (float) (chargeTick - 1) / chargeDuration);
float currProgress = Math.min(1.0f, (float) chargeTick / chargeDuration);
return prevProgress + (currProgress - prevProgress) * partialTicks;
}
// ==================== OWNER ====================
/**
* Get the owner entity. In preview mode, returns the preview owner directly.
*/
public Entity getOwnerEntity() {
if (previewMode && previewOwner != null) {
return previewOwner;
}
if (ownerEntityId == -1) return null;
return worldObj.getEntityByID(ownerEntityId);
}
public int getOwnerEntityId() {
return ownerEntityId;
}
public void setOwnerEntityId(int id) {
this.ownerEntityId = id;
}
// ==================== SOURCE ABILITY ====================
public Ability getSourceAbility() {
return sourceAbility;
}
public void setSourceAbility(Ability ability) {
this.sourceAbility = ability;
}
// ==================== PREVIEW MODE ====================
public boolean isPreviewMode() {
return previewMode;
}
public void setPreviewMode(boolean preview) {
this.previewMode = preview;
}
public void setPreviewOwner(EntityLivingBase owner) {
this.previewOwner = owner;
}
// ==================== DISPLAY GETTERS & SETTERS ====================
public EnergyDisplayData getDisplayData() {
return displayData;
}
public EnergyLightningData getLightningData() {
return lightningData;
}
public int getInnerColor() {
return displayData.getInnerColor();
}
public void setInnerColor(int color) {
displayData.setInnerColor(color);
}
public float getInnerAlpha() {
return displayData.getInnerAlpha();
}
public void setInnerAlpha(float alpha) {
displayData.setInnerAlpha(alpha);
}
public int getOuterColor() {
return displayData.getOuterColor();
}
public void setOuterColor(int color) {
displayData.setOuterColor(color);
}
public boolean isOuterColorEnabled() {
return displayData.isOuterColorEnabled();
}
public void setOuterColorEnabled(boolean enabled) {
displayData.setOuterColorEnabled(enabled);
}
public float getOuterColorWidth() {
return displayData.getOuterColorWidth();
}
public void setOuterColorWidth(float width) {
displayData.setOuterColorWidth(width);
}
public float getOuterColorAlpha() {
return displayData.getOuterColorAlpha();
}
public void setOuterColorAlpha(float alpha) {
displayData.setOuterColorAlpha(alpha);
}
public float getRotationSpeed() {
return displayData.getRotationSpeed();
}
public void setRotationSpeed(float speed) {
displayData.setRotationSpeed(speed);
}
// ==================== LIGHTNING GETTERS & SETTERS ====================
public boolean hasLightningEffect() {
return lightningData.isLightningEffect();
}
public void setLightningEffect(boolean enabled) {
lightningData.setLightningEffect(enabled);
}
public float getLightningDensity() {
return lightningData.getLightningDensity();
}
public void setLightningDensity(float density) {
lightningData.setLightningDensity(density);
}
public float getLightningRadius() {
return lightningData.getLightningRadius();
}
public void setLightningRadius(float radius) {
lightningData.setLightningRadius(radius);
}
public int getLightningFadeTime() {
return lightningData.getLightningFadeTime();
}
public void setLightningFadeTime(int ticks) {
lightningData.setLightningFadeTime(ticks);
}
// ==================== BRIGHTNESS ====================
@Override
public float getBrightness(float partialTicks) {
return 1.0f;
}
@Override
@SideOnly(Side.CLIENT)
public int getBrightnessForRender(float partialTicks) {
return 0xF000F0;
}
@Override
public boolean shouldRenderInPass(int pass) {
return pass == 1; // Translucent pass
}
// ==================== COLLISION SETTINGS ====================
@Override
public boolean canBePushed() {
return false;
}
@Override
protected boolean canTriggerWalking() {
return false;
}
@Override
public boolean isBurning() {
return false;
}
@SideOnly(Side.CLIENT)
public float getShadowSize() {
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 ====================
/**
* Write shared energy base fields to NBT (owner, display, lightning).
* Call from subclass NBT writers before writing type-specific fields.
*/
protected void writeEnergyBaseNBT(NBTTagCompound nbt) {
nbt.setInteger("OwnerId", ownerEntityId);
displayData.writeNBT(nbt);
lightningData.writeNBT(nbt);
}
/**
* Read shared energy base fields from NBT (owner, display, lightning).
* Call from subclass NBT readers before reading type-specific fields.
*/
protected void readEnergyBaseNBT(NBTTagCompound nbt) {
this.ownerEntityId = nbt.getInteger("OwnerId");
displayData.readNBT(nbt);
lightningData.readNBT(nbt);
}
// ==================== SPAWN DATA ====================
/**
* Write entity data for client sync. Subclasses override this
* to serialize their fields. Separate from writeEntityToNBT
* which is intentionally empty (entities are transient, not saved to world).
*/
protected void writeSpawnNBT(NBTTagCompound nbt) {
writeEnergyBaseNBT(nbt);
}
/**
* Read entity data from client sync. Subclasses override this
* to deserialize their fields. Separate from readEntityFromNBT
* which is intentionally empty (entities are transient, not saved to world).
*/
protected void readSpawnNBT(NBTTagCompound nbt) {
readEnergyBaseNBT(nbt);
}
/**
* Export spawn NBT for non-world preview rendering sync.
*/
public final NBTTagCompound exportSpawnNBT() {
NBTTagCompound nbt = new NBTTagCompound();
writeSpawnNBT(nbt);
return nbt;
}
/**
* Import spawn NBT for non-world preview rendering sync.
*/
public final void importSpawnNBT(NBTTagCompound nbt) {
if (nbt != null) {
readSpawnNBT(nbt);
}
}
@Override
public void writeSpawnData(ByteBuf buffer) {
try {
NBTTagCompound compound = new NBTTagCompound();
this.writeSpawnNBT(compound);
ByteBufUtils.writeNBT(buffer, compound);
} catch (Exception e) {
noppes.npcs.LogWriter.error("Error writing energy ability spawn data", e);
}
}
@Override
public void readSpawnData(ByteBuf buffer) {
try {
NBTTagCompound compound = ByteBufUtils.readNBT(buffer);
if (compound != null) {
this.readSpawnNBT(compound);
}
} catch (Exception e) {
noppes.npcs.LogWriter.error("Error reading energy ability spawn data", e);
}
}
}