mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 20:07:32 +00:00
Fix Rendering Glitches
This commit is contained in:
1 parent
08728efcdd
commit
abc34b3f6f
7 files changed
+71
-42
No files matched your search
@@ -59,12 +59,17 @@ public class RenderAbilityDisc extends RenderEnergyAbility {
|
||||
double motionX = entity.motionX;
|
||||
double motionY = entity.motionY;
|
||||
double motionZ = entity.motionZ;
|
||||
Vec3 motionVec = Vec3.createVectorHelper(motionX, motionY, motionZ);
|
||||
double speedSq = motionX * motionX + motionY * motionY + motionZ * motionZ;
|
||||
|
||||
float motionYaw = MathUtil.getYaw(motionVec);
|
||||
float motionPitch = MathUtil.getPitch(motionVec);
|
||||
GL11.glRotatef(motionYaw, 0, 1, 0);
|
||||
GL11.glRotatef(motionPitch, 1, 0, 0);
|
||||
// Only apply motion-based facing when speed is meaningful.
|
||||
// Near-zero motion makes atan2 unstable, producing jittery angles.
|
||||
if (speedSq > 0.0001) {
|
||||
Vec3 motionVec = Vec3.createVectorHelper(motionX, motionY, motionZ);
|
||||
float motionYaw = MathUtil.getYaw(motionVec);
|
||||
float motionPitch = MathUtil.getPitch(motionVec);
|
||||
GL11.glRotatef(motionYaw, 0, 1, 0);
|
||||
GL11.glRotatef(motionPitch, 1, 0, 0);
|
||||
}
|
||||
|
||||
// Apply Y-axis rotation for spin
|
||||
GL11.glRotatef(disc.getInterpolatedRotationY(partialTicks), 0.0f, 1.0f, 0.0f);
|
||||
|
||||
@@ -23,9 +23,6 @@ public class RenderAbilityLaser extends RenderEnergyAbility {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTicks) {
|
||||
if (shouldSkipInitialActiveRender(entity)) {
|
||||
return;
|
||||
}
|
||||
EntityAbilityLaser laser = (EntityAbilityLaser) entity;
|
||||
|
||||
setupRenderState();
|
||||
|
||||
@@ -46,12 +46,17 @@ public class RenderAbilityOrb extends RenderEnergyAbility {
|
||||
double motionX = entity.motionX;
|
||||
double motionY = entity.motionY;
|
||||
double motionZ = entity.motionZ;
|
||||
Vec3 motionVec = Vec3.createVectorHelper(motionX, motionY, motionZ);
|
||||
double speedSq = motionX * motionX + motionY * motionY + motionZ * motionZ;
|
||||
|
||||
float motionYaw = MathUtil.getYaw(motionVec);
|
||||
float motionPitch = MathUtil.getPitch(motionVec);
|
||||
GL11.glRotatef(motionYaw, 0, 1, 0);
|
||||
GL11.glRotatef(motionPitch, 1, 0, 0);
|
||||
// Only apply motion-based facing when speed is meaningful.
|
||||
// Near-zero motion makes atan2 unstable, producing jittery angles.
|
||||
if (speedSq > 0.0001) {
|
||||
Vec3 motionVec = Vec3.createVectorHelper(motionX, motionY, motionZ);
|
||||
float motionYaw = MathUtil.getYaw(motionVec);
|
||||
float motionPitch = MathUtil.getPitch(motionVec);
|
||||
GL11.glRotatef(motionYaw, 0, 1, 0);
|
||||
GL11.glRotatef(motionPitch, 1, 0, 0);
|
||||
}
|
||||
|
||||
// Use entity's interpolated rotation for smooth spinning
|
||||
GL11.glRotatef(orb.getInterpolatedRotationX(partialTicks), 1.0f, 0.0f, 0.0f);
|
||||
|
||||
@@ -39,6 +39,9 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
private int returnOwnerNullTicks = 0;
|
||||
private boolean vertical = false; // false = horizontal (flat), true = vertical (thin edge forward)
|
||||
|
||||
// Cached travel direction for smooth rendering when motion is near zero
|
||||
private float lastTravelYaw = 0.0f;
|
||||
|
||||
// Charging state (disc-specific target sizes)
|
||||
private float targetDiscRadius = 1.0f; // Full radius to grow to during charging
|
||||
private float targetDiscThickness = 0.2f; // Full thickness to grow to during charging
|
||||
@@ -60,7 +63,7 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
super(world);
|
||||
|
||||
// Initialize base properties
|
||||
initProjectile(owner, target, x, y, z, discRadius, display, combat, lightning, lifespan, trajectory);
|
||||
initProjectile(owner, target, x, y, z, 1.0f, display, combat, lightning, lifespan, trajectory);
|
||||
|
||||
this.homingData = homing;
|
||||
|
||||
@@ -316,7 +319,7 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
float progress = getChargeProgress();
|
||||
this.discRadius = targetDiscRadius * progress;
|
||||
this.discThickness = targetDiscThickness * progress;
|
||||
this.size = this.discRadius; // Base size for interpolation
|
||||
this.size = 1.0f; // Size acts as a scaling factor; discRadius handles actual dimensions
|
||||
|
||||
Entity owner = getOwnerEntity();
|
||||
if (owner instanceof EntityLivingBase) {
|
||||
@@ -382,14 +385,15 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
if (isCharging()) {
|
||||
Entity owner = previewMode ? previewOwner : getOwnerEntity();
|
||||
if (owner != null) {
|
||||
return owner.rotationYaw;
|
||||
lastTravelYaw = owner.rotationYaw;
|
||||
return lastTravelYaw;
|
||||
}
|
||||
}
|
||||
double speed = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
||||
if (speed > 0.001) {
|
||||
return (float) (Math.atan2(-motionX, motionZ) * 180.0 / Math.PI);
|
||||
lastTravelYaw = (float) (Math.atan2(-motionX, motionZ) * 180.0 / Math.PI);
|
||||
}
|
||||
return 0.0f;
|
||||
return lastTravelYaw;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
@@ -406,6 +410,12 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
readChargingNBT(nbt);
|
||||
this.targetDiscRadius = nbt.hasKey("TargetDiscRadius") ? nbt.getFloat("TargetDiscRadius") : this.discRadius;
|
||||
this.targetDiscThickness = nbt.hasKey("TargetDiscThickness") ? nbt.getFloat("TargetDiscThickness") : this.discThickness;
|
||||
|
||||
// Normalize size to 1.0 (scaling factor) — discRadius handles actual dimensions.
|
||||
// Old saves may have size = discRadius baked in from the quadratic scaling bug.
|
||||
this.size = 1.0f;
|
||||
this.renderCurrentSize = 1.0f;
|
||||
this.prevRenderSize = 1.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,8 @@ import kamkeel.npcs.controllers.data.ability.data.energy.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyTrajectoryData;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -103,6 +105,13 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.endZ = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isInRangeToRenderDist(double distance) {
|
||||
double range = Math.max(128.0D, currentLength * 2.0D + 64.0D);
|
||||
return distance < range * range;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRotation() {
|
||||
// Laser doesn't rotate
|
||||
@@ -179,7 +188,13 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
*/
|
||||
private void updateLaserOriginAndDirection() {
|
||||
Entity owner = getOwnerEntity();
|
||||
if (owner == null || !(owner instanceof EntityLivingBase)) return;
|
||||
if (owner == null || !(owner instanceof EntityLivingBase)) {
|
||||
// On client, fall back to entity tracker interpolation when owner not loaded
|
||||
if (worldObj != null && worldObj.isRemote) {
|
||||
handleClientInterpolation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
EntityLivingBase livingOwner = (EntityLivingBase) owner;
|
||||
|
||||
// Use owner look vector (head/eye aim) for direction updates so hit logic matches visuals.
|
||||
|
||||
@@ -801,19 +801,21 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
/**
|
||||
* Handle client-side position interpolation.
|
||||
* Only moves position during active interpolation (interpSteps > 0).
|
||||
* Does NOT predict/drift between server updates — the motion values are
|
||||
* derived from correction deltas, not actual entity velocity, so applying
|
||||
* them between updates causes entities to fly off in wrong directions.
|
||||
* This matches vanilla Minecraft behavior for non-player entities.
|
||||
*/
|
||||
protected void handleClientInterpolation() {
|
||||
if (this.interpSteps > 0) {
|
||||
// For very slow / stationary projectiles, snap directly to avoid jitter
|
||||
double dx = this.interpTargetX - this.posX;
|
||||
double dy = this.interpTargetY - this.posY;
|
||||
double dz = this.interpTargetZ - this.posZ;
|
||||
double distSq = dx * dx + dy * dy + dz * dz;
|
||||
if (distSq < 0.04) {
|
||||
|
||||
if (distSq < 0.0001) {
|
||||
this.setPosition(this.interpTargetX, this.interpTargetY, this.interpTargetZ);
|
||||
this.motionX = this.interpTargetMotionX;
|
||||
this.motionY = this.interpTargetMotionY;
|
||||
this.motionZ = this.interpTargetMotionZ;
|
||||
this.interpSteps = 0;
|
||||
return;
|
||||
}
|
||||
@@ -828,16 +830,6 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
this.setPosition(newX, newY, newZ);
|
||||
this.interpSteps--;
|
||||
} else {
|
||||
// Skip motion application for nearly-stationary projectiles to prevent drift
|
||||
double speedSq = this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ;
|
||||
if (speedSq < 0.0001) {
|
||||
return;
|
||||
}
|
||||
this.posX += this.motionX;
|
||||
this.posY += this.motionY;
|
||||
this.posZ += this.motionZ;
|
||||
this.setPosition(this.posX, this.posY, this.posZ);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1542,9 +1534,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
protected void setChargeOrigin(Vec3 pos) {
|
||||
if (pos == null) return;
|
||||
this.setPosition(pos.xCoord, pos.yCoord, pos.zCoord);
|
||||
this.prevPosX = pos.xCoord;
|
||||
this.prevPosY = pos.yCoord;
|
||||
this.prevPosZ = pos.zCoord;
|
||||
syncPositionState(pos.xCoord, pos.yCoord, pos.zCoord, true);
|
||||
this.startX = pos.xCoord;
|
||||
this.startY = pos.yCoord;
|
||||
this.startZ = pos.zCoord;
|
||||
|
||||
@@ -24,6 +24,10 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
private float sliceWidth = 3.0f;
|
||||
private float sliceThickness = 0.15f;
|
||||
|
||||
// Cached travel direction for smooth rendering when motion is near zero
|
||||
private float lastTravelYaw = 0.0f;
|
||||
private float lastTravelPitch = 0.0f;
|
||||
|
||||
public EntityEnergySlicer(World world) {
|
||||
super(world);
|
||||
}
|
||||
@@ -166,13 +170,16 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
public float getTravelYaw() {
|
||||
if (isCharging()) {
|
||||
Entity owner = previewMode ? previewOwner : getOwnerEntity();
|
||||
if (owner != null) return owner.rotationYaw;
|
||||
if (owner != null) {
|
||||
lastTravelYaw = owner.rotationYaw;
|
||||
return lastTravelYaw;
|
||||
}
|
||||
}
|
||||
double speed = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
||||
if (speed > 0.001) {
|
||||
return (float) (Math.atan2(-motionX, motionZ) * 180.0 / Math.PI);
|
||||
lastTravelYaw = (float) (Math.atan2(-motionX, motionZ) * 180.0 / Math.PI);
|
||||
}
|
||||
return 0.0f;
|
||||
return lastTravelYaw;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,9 +188,9 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
public float getTravelPitch() {
|
||||
double horizSpeed = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
||||
if (horizSpeed > 0.001 || Math.abs(motionY) > 0.001) {
|
||||
return (float) (-Math.atan2(motionY, horizSpeed) * 180.0 / Math.PI);
|
||||
lastTravelPitch = (float) (-Math.atan2(motionY, horizSpeed) * 180.0 / Math.PI);
|
||||
}
|
||||
return 0.0f;
|
||||
return lastTravelPitch;
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
Reference in new issue
Block a user