Fix Sizing Changes Mid Firing

This commit is contained in:
Kam committed 2026-03-10 23:01:54 -04:00
1 parent 3859bb70cb
commit a7d780565f
4 files changed
+80 -51

No files matched your search

@@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.entity.EntityAbilityBeam;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.Vec3;
import org.lwjgl.opengl.GL11;
@@ -51,19 +52,20 @@ public class RenderEnergyBeam extends RenderEnergy {
return;
}
// Get interpolated head offset
// Get interpolated head offset (for head/trail rendering relative to origin)
double headOffsetX = beam.getInterpolatedHeadOffsetX(partialTicks);
double headOffsetY = beam.getInterpolatedHeadOffsetY(partialTicks);
double headOffsetZ = beam.getInterpolatedHeadOffsetZ(partialTicks);
// The render system passes x,y,z as the position to render the entity at
// Entity position = origin + headOffset (in world coords)
// So origin render position = x,y,z - headOffset
double renderOriginX = x - headOffsetX;
double renderOriginY = y - headOffsetY;
double renderOriginZ = z - headOffsetZ;
// Compute render origin directly from the world origin and camera position.
// We can't derive it from MC's x,y,z because syncPositionStateToCurrent() snaps
// lastTickPos = posX on every sync packet, killing MC's position interpolation.
// The headOffset interpolation then mismatches, causing the origin to wobble.
double renderOriginX = beam.getOriginX() - RenderManager.renderPosX;
double renderOriginY = beam.getOriginY() - RenderManager.renderPosY;
double renderOriginZ = beam.getOriginZ() - RenderManager.renderPosZ;
// Get beam properties (interpolated for smooth size transitions)
// Get beam properties (lerp-smoothed for smooth size transitions)
float beamWidth = beam.getInterpolatedBeamWidth(partialTicks);
float headSize = beam.getInterpolatedHeadSize(partialTicks);
int innerColor = beam.getInnerColor();
@@ -77,21 +79,22 @@ public class RenderEnergyBeam extends RenderEnergy {
// Calculate head distance from origin (for overlap check)
double headDistFromOrigin = Math.sqrt(headOffsetX * headOffsetX + headOffsetY * headOffsetY + headOffsetZ * headOffsetZ);
// Render tail orb at origin (0,0,0) - only in anchored mode
// Don't render if head is too close to origin (would cause overlap/extra orb appearance)
if (beam.shouldRenderTailOrb() && headDistFromOrigin > headSize * 0.5) {
renderTailOrb(headSize * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, beam.getInnerAlpha() * proximityAlpha);
}
float innerAlpha = beam.getInnerAlpha() * proximityAlpha;
// Render trail segments with smooth connections (with fading for non-anchored)
// Render trail segments first (with fading for non-anchored)
if (beam.hasFadingTrail()) {
renderFadingTrail(beam, trail, beamWidth, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), innerAlpha);
} else {
renderSmoothTrail(trail, beamWidth, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), innerAlpha);
}
// Render tail orb at origin (0,0,0) AFTER trail so it draws on top
// Don't render if head is too close to origin (would cause overlap/extra orb appearance)
// Use target headSize (not lerped) so the threshold isn't inflated by lerp lag
if (beam.shouldRenderTailOrb() && headDistFromOrigin > beam.getHeadSize() * 0.5) {
renderTailOrb(beam.getHeadSize() * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, innerAlpha);
}
// Render head at interpolated offset position
renderHead(beam, headOffsetX, headOffsetY, headOffsetZ, headSize, innerColor, outerColor, outerAlpha, innerAlpha, partialTicks);
@@ -38,11 +38,15 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
FREE_TRAIL
}
// Beam shape properties
// Beam shape properties (target values - set by sync packets/scripts)
private float beamWidth = 0.3f;
private float headSize = 0.5f;
private float prevBeamWidth = 0.3f;
private float prevHeadSize = 0.5f;
// Lerp-smoothed render values (approach target each tick)
private float renderBeamWidth = 0.3f;
private float renderHeadSize = 0.5f;
private float prevRenderBeamWidth = 0.3f;
private float prevRenderHeadSize = 0.5f;
// Trail - list of points showing beam path (RELATIVE to origin!)
private List<Vec3> trailPoints = new ArrayList<>();
@@ -236,18 +240,26 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
@Override
protected void updateProjectile() {
// Save previous render values for sub-tick interpolation
prevRenderBeamWidth = renderBeamWidth;
prevRenderHeadSize = renderHeadSize;
// Handle charging state (windup phase) - use isCharging() for synced value
if (isCharging()) {
// During charging, snap render values to target (size grows smoothly already)
renderBeamWidth = beamWidth;
renderHeadSize = headSize;
updateCharging();
return;
}
// Store previous values for interpolation
// Lerp render values toward target (smooth out sync packet jumps)
renderBeamWidth += (beamWidth - renderBeamWidth) * 0.15f;
renderHeadSize += (headSize - renderHeadSize) * 0.15f;
prevHeadOffsetX = headOffsetX;
prevHeadOffsetY = headOffsetY;
prevHeadOffsetZ = headOffsetZ;
prevBeamWidth = beamWidth;
prevHeadSize = headSize;
// Age trail points for fading effect
if (isFadingMode()) {
@@ -585,11 +597,10 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
}
public float getInterpolatedBeamWidth(float partialTicks) {
return prevBeamWidth + (beamWidth - prevBeamWidth) * partialTicks;
return prevRenderBeamWidth + (renderBeamWidth - prevRenderBeamWidth) * partialTicks;
}
public void setBeamWidth(float beamWidth) {
this.prevBeamWidth = this.beamWidth;
this.beamWidth = beamWidth;
}
@@ -598,11 +609,10 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
}
public float getInterpolatedHeadSize(float partialTicks) {
return prevHeadSize + (headSize - prevHeadSize) * partialTicks;
return prevRenderHeadSize + (renderHeadSize - prevRenderHeadSize) * partialTicks;
}
public void setHeadSize(float headSize) {
this.prevHeadSize = this.headSize;
this.headSize = headSize;
}
@@ -761,8 +771,6 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
@Override
protected void applyProjectileClientSyncData(NBTTagCompound nbt) {
prevBeamWidth = beamWidth;
prevHeadSize = headSize;
beamWidth = nbt.getFloat("BeamWidth");
headSize = nbt.getFloat("HeadSize");
setAttachedToOwner(nbt.getBoolean("AttachedToOwner"));
@@ -774,8 +782,10 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
protected void readProjectileNBT(NBTTagCompound nbt) {
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.prevBeamWidth = this.beamWidth;
this.prevHeadSize = this.headSize;
this.renderBeamWidth = this.beamWidth;
this.renderHeadSize = this.headSize;
this.prevRenderBeamWidth = this.beamWidth;
this.prevRenderHeadSize = this.headSize;
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;
@@ -30,11 +30,15 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
private boolean returning = false;
private int ticksSinceMiss = 0;
// Disc shape properties
// Disc shape properties (target values)
private float discRadius = 1.0f; // Width of disc
private float discThickness = 0.2f; // Height of disc
private float prevDiscRadius = 1.0f;
private float prevDiscThickness = 0.2f;
// Lerp-smoothed render values
private float renderDiscRadius = 1.0f;
private float renderDiscThickness = 0.2f;
private float prevRenderDiscRadius = 1.0f;
private float prevRenderDiscThickness = 0.2f;
// Boomerang owner-gone tracking
private int returnOwnerNullTicks = 0;
@@ -136,16 +140,23 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
@Override
protected void updateProjectile() {
// Store previous values for interpolation
prevDiscRadius = discRadius;
prevDiscThickness = discThickness;
// Save previous render values for sub-tick interpolation
prevRenderDiscRadius = renderDiscRadius;
prevRenderDiscThickness = renderDiscThickness;
// Handle charging state (windup phase)
if (isCharging()) {
// During charging, snap render values to target (size grows smoothly already)
renderDiscRadius = discRadius;
renderDiscThickness = discThickness;
updateCharging();
return;
}
// Lerp render values toward target (smooth out sync packet jumps)
renderDiscRadius += (discRadius - renderDiscRadius) * 0.15f;
renderDiscThickness += (discThickness - renderDiscThickness) * 0.15f;
// In preview mode, run movement on client (no server)
if (previewMode) {
updatePreviewMovement();
@@ -354,11 +365,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
}
public float getInterpolatedDiscRadius(float partialTicks) {
return prevDiscRadius + (discRadius - prevDiscRadius) * partialTicks;
return prevRenderDiscRadius + (renderDiscRadius - prevRenderDiscRadius) * partialTicks;
}
public void setDiscRadius(float radius) {
this.prevDiscRadius = this.discRadius;
this.discRadius = radius;
}
@@ -367,11 +377,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
}
public float getInterpolatedDiscThickness(float partialTicks) {
return prevDiscThickness + (discThickness - prevDiscThickness) * partialTicks;
return prevRenderDiscThickness + (renderDiscThickness - prevRenderDiscThickness) * partialTicks;
}
public void setDiscThickness(float thickness) {
this.prevDiscThickness = this.discThickness;
this.discThickness = thickness;
}
@@ -459,8 +468,6 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
@Override
protected void applyProjectileClientSyncData(NBTTagCompound nbt) {
prevDiscRadius = discRadius;
prevDiscThickness = discThickness;
discRadius = nbt.getFloat("DiscRadius");
discThickness = nbt.getFloat("DiscThickness");
vertical = nbt.getBoolean("Vertical");
@@ -474,8 +481,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
this.boomerangDelay = nbt.hasKey("BoomerangDelay") ? nbt.getInteger("BoomerangDelay") : 40;
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.prevDiscRadius = this.discRadius;
this.prevDiscThickness = this.discThickness;
this.renderDiscRadius = this.discRadius;
this.renderDiscThickness = this.discThickness;
this.prevRenderDiscRadius = this.discRadius;
this.prevRenderDiscThickness = this.discThickness;
this.vertical = nbt.hasKey("Vertical") ? nbt.getBoolean("Vertical") : false;
this.returning = nbt.hasKey("Returning") && nbt.getBoolean("Returning");
// Charging state (common fields handled by base)
@@ -31,9 +31,12 @@ import java.util.List;
*/
public class EntityAbilityLaser extends EntityEnergyProjectile {
// Laser-specific properties
// Laser-specific properties (target value)
private float laserWidth = 0.2f;
private float prevLaserWidth = 0.2f;
// Lerp-smoothed render values
private float renderLaserWidth = 0.2f;
private float prevRenderLaserWidth = 0.2f;
private float expansionSpeed = 2.0f; // Blocks per tick
private float maxLength = 32.0f; // Maximum beam reach in blocks
@@ -145,14 +148,19 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
@Override
protected void updateProjectile() {
// Store previous values for interpolation
prevLaserWidth = laserWidth;
// Save previous render value for sub-tick interpolation
prevRenderLaserWidth = renderLaserWidth;
if (isCharging()) {
// During charging, snap render value to target
renderLaserWidth = laserWidth;
updateCharging();
return;
}
// Lerp render value toward target (smooth out sync packet jumps)
renderLaserWidth += (laserWidth - renderLaserWidth) * 0.15f;
// Save previous positions for partial tick interpolation
prevStartX = startX;
prevStartY = startY;
@@ -708,11 +716,10 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
}
public float getInterpolatedLaserWidth(float partialTicks) {
return prevLaserWidth + (laserWidth - prevLaserWidth) * partialTicks;
return prevRenderLaserWidth + (renderLaserWidth - prevRenderLaserWidth) * partialTicks;
}
public void setLaserWidth(float width) {
this.prevLaserWidth = this.laserWidth;
this.laserWidth = width;
}
@@ -888,7 +895,6 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
@Override
protected void applyProjectileClientSyncData(NBTTagCompound nbt) {
prevLaserWidth = laserWidth;
laserWidth = nbt.getFloat("LaserWidth");
expansionSpeed = nbt.getFloat("ExpansionSpeed");
maxLength = nbt.getFloat("MaxLength");
@@ -902,7 +908,8 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
@Override
protected void readProjectileNBT(NBTTagCompound nbt) {
this.laserWidth = sanitize(nbt.hasKey("LaserWidth") ? nbt.getFloat("LaserWidth") : 0.2f, 0.2f, MAX_ENTITY_SIZE);
this.prevLaserWidth = this.laserWidth;
this.renderLaserWidth = this.laserWidth;
this.prevRenderLaserWidth = this.laserWidth;
this.expansionSpeed = sanitize(nbt.hasKey("ExpansionSpeed") ? nbt.getFloat("ExpansionSpeed") : 2.0f, 0.1f, MAX_ENTITY_SIZE);
this.maxLength = sanitize(nbt.hasKey("MaxLength") ? nbt.getFloat("MaxLength") : 32.0f, 1.0f, MAX_ENTITY_SIZE);
this.dirX = nbt.getDouble("DirX");