Merge branch 'claude/fix-mount-movement-jitter-7JrfX' into dev

This commit is contained in:
Kam committed 2025-12-30 18:21:38 -05:00
commit 8dad290486
6 files changed
+42 -98

No files matched your search

@@ -123,8 +123,12 @@ public class NoppesUtilPlayer {
}
public static void teleportPlayer(EntityPlayerMP player, double posX, double posY, double posZ, int dimension) {
// Dismount from NPC mount before teleportation to prevent mount desync
if (player.ridingEntity instanceof EntityNPCInterface) {
player.mountEntity(null);
}
if (player.dimension != dimension) {
int dim = player.dimension;
MinecraftServer server = MinecraftServer.getServer();
WorldServer wor = server.worldServerForDimension(dimension);
if (wor == null) {
@@ -144,8 +148,12 @@ public class NoppesUtilPlayer {
}
public static void teleportPlayer(EntityPlayerMP player, double posX, double posY, double posZ, float yaw, float pitch, int dimension) {
// Dismount from NPC mount before teleportation to prevent mount desync
if (player.ridingEntity instanceof EntityNPCInterface) {
player.mountEntity(null);
}
if (player.dimension != dimension) {
int dim = player.dimension;
MinecraftServer server = MinecraftServer.getServer();
WorldServer wor = server.worldServerForDimension(dimension);
if (wor == null) {
@@ -11,6 +11,7 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.world.WorldServer;
import noppes.npcs.client.AnalyticsTracking;
import noppes.npcs.controllers.data.PlayerData;
import noppes.npcs.entity.EntityNPCInterface;
import noppes.npcs.controllers.data.action.ActionManager;
import java.net.InetAddress;
@@ -68,6 +69,11 @@ public class ServerTickHandler {
@SubscribeEvent
public void playerLogout(PlayerEvent.PlayerLoggedOutEvent event) {
// Dismount player from NPC mount before logout to prevent orphaned mount state
if (event.player.ridingEntity instanceof EntityNPCInterface) {
event.player.mountEntity(null);
}
PlayerData playerData = PlayerData.get(event.player);
if (playerData != null) {
playerData.onLogout();
@@ -84,7 +84,6 @@ public abstract class EntityNPCFlying extends EntityNPCInterface {
}
this.updateLimbSwing();
this.velocityChanged = true;
}
public void updateLimbSwing() {
@@ -136,7 +135,6 @@ public abstract class EntityNPCFlying extends EntityNPCInterface {
if (flightModeActive) {
super.performMountedMovement(strafe, forward, moveSpeed);
this.velocityChanged = true;
return;
}
@@ -149,6 +147,5 @@ public abstract class EntityNPCFlying extends EntityNPCInterface {
}
this.updateLimbSwing();
this.velocityChanged = true;
}
}
@@ -2130,35 +2130,21 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
this.moveForward = forward;
boolean flightMode = isMountFlightModeActive();
double prevMotionX = this.motionX;
double prevMotionY = this.motionY;
double prevMotionZ = this.motionZ;
float previousJumpFactor = this.jumpMovementFactor;
float appliedJumpFactor = getMountedAirStrafeFactor(moveSpeed, flightMode);
this.jumpMovementFactor = appliedJumpFactor;
this.setAIMoveSpeed(moveSpeed);
super.moveEntityWithHeading(strafe, forward);
if (flightMode) {
this.motionY = prevMotionY;
this.isAirBorne = true;
}
this.jumpMovementFactor = previousJumpFactor;
// Server-side only physics (like vanilla horse)
if (!worldObj.isRemote) {
double newMotionX = this.motionX;
double newMotionY = this.motionY;
double newMotionZ = this.motionZ;
if (Math.abs(newMotionX - prevMotionX) > 1.0E-5D || Math.abs(newMotionY - prevMotionY) > 1.0E-5D || Math.abs(newMotionZ - prevMotionZ) > 1.0E-5D) {
this.velocityChanged = true;
this.jumpMovementFactor = getMountedAirStrafeFactor(moveSpeed, flightMode);
this.setAIMoveSpeed(moveSpeed);
super.moveEntityWithHeading(strafe, forward);
if (flightMode) {
this.motionY = prevMotionY;
this.isAirBorne = true;
}
}
syncMountedRiderVelocity();
// Both sides do animation (like vanilla horse)
updateMountedLimbSwing();
}
@@ -2176,28 +2162,6 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
return moveSpeed * 0.5F;
}
private void syncMountedRiderVelocity() {
if (!(this.riddenByEntity instanceof EntityLivingBase)) {
return;
}
EntityLivingBase rider = (EntityLivingBase) this.riddenByEntity;
double riderPrevMotionX = rider.motionX;
double riderPrevMotionY = rider.motionY;
double riderPrevMotionZ = rider.motionZ;
rider.motionX = this.motionX;
rider.motionY = this.motionY;
rider.motionZ = this.motionZ;
rider.fallDistance = 0.0F;
rider.isAirBorne = !this.onGround;
if (!worldObj.isRemote) {
if (Math.abs(rider.motionX - riderPrevMotionX) > 1.0E-5D || Math.abs(rider.motionY - riderPrevMotionY) > 1.0E-5D || Math.abs(rider.motionZ - riderPrevMotionZ) > 1.0E-5D) {
rider.velocityChanged = true;
}
}
}
private void updateMountedLimbSwing() {
this.prevLimbSwingAmount = this.limbSwingAmount;
double deltaX = this.posX - this.prevPosX;
@@ -192,6 +192,10 @@ public class RoleMount extends RoleInterface {
}
public void onDisable() {
// Dismount any rider when mount role is disabled
if (npc.riddenByEntity != null) {
npc.riddenByEntity.mountEntity(null);
}
npc.ais.returnToStart = storedReturnToStart;
}
@@ -122,49 +122,22 @@ public final class NPCMountUtil {
npc.isAirBorne = true;
npc.fallDistance = 0.0F;
if (!npc.worldObj.isRemote && Math.abs(previousMotionY - newMotionY) > 1.0E-4D) {
npc.velocityChanged = true;
}
if (!npc.worldObj.isRemote && rider instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) rider;
if (!player.capabilities.isFlying) {
double playerPrevMotion = player.motionY;
player.motionY = npc.motionY;
if (Math.abs(playerPrevMotion - player.motionY) > 1.0E-4D) {
player.velocityChanged = true;
}
}
}
return;
}
if (jumpPressed && npc.onGround) {
double previousMotionY = npc.motionY;
npc.motionY = jumpFactor;
npc.setNpcJumpingState(true);
npc.isAirBorne = true;
npc.fallDistance = 0.0F;
if (!npc.worldObj.isRemote) {
if (Math.abs(previousMotionY - npc.motionY) > 1.0E-4D) {
npc.velocityChanged = true;
}
net.minecraftforge.common.ForgeHooks.onLivingJump(npc);
}
return;
}
if (!npc.onGround) {
double previousMotionY = npc.motionY;
double limitedMotionY = Math.max(npc.motionY, -descendSpeed);
if (Math.abs(previousMotionY - limitedMotionY) > 1.0E-4D) {
npc.motionY = limitedMotionY;
if (!npc.worldObj.isRemote) {
npc.velocityChanged = true;
}
} else {
npc.motionY = limitedMotionY;
}
npc.motionY = Math.max(npc.motionY, -descendSpeed);
npc.setNpcFlyingState(!npc.isInWater());
} else {
npc.setNpcFlyingState(false);
@@ -174,20 +147,14 @@ public final class NPCMountUtil {
}
if (npc.onGround) {
double previousMotionY = npc.motionY;
if (rider.isJumping) {
npc.motionY = jumpFactor;
npc.setNpcJumpingState(true);
npc.isAirBorne = true;
npc.fallDistance = 0.0F;
if (!npc.worldObj.isRemote) {
if (Math.abs(previousMotionY - npc.motionY) > 1.0E-4D) {
npc.velocityChanged = true;
}
net.minecraftforge.common.ForgeHooks.onLivingJump(npc);
}
} else {
npc.motionY = 0.0D;
}
return;
}
@@ -210,6 +177,17 @@ public final class NPCMountUtil {
RoleMount mount = (RoleMount) npc.roleInterface;
Entity currentRider = npc.riddenByEntity;
// Validate rider is alive and valid - dismount dead/invalid riders
if (currentRider != null && !currentRider.isEntityAlive()) {
currentRider.mountEntity(null);
stabilizeDismountedRider(currentRider);
haltMountedMotion(npc, state);
applyUnriddenFlightDescent(npc, state, mount);
currentRider = null;
}
// Only allow EntityPlayer as riders
if (currentRider != null && !(currentRider instanceof EntityPlayer)) {
Entity dismount = currentRider;
dismount.mountEntity(null);
@@ -239,9 +217,6 @@ public final class NPCMountUtil {
}
public static void haltMountedMotion(EntityNPCInterface npc, MountState state) {
double prevMotionX = npc.motionX;
double prevMotionY = npc.motionY;
double prevMotionZ = npc.motionZ;
npc.motionX = 0.0D;
npc.motionY = 0.0D;
npc.motionZ = 0.0D;
@@ -254,9 +229,6 @@ public final class NPCMountUtil {
npc.limbSwing = 0.0F;
npc.getNavigator().clearPathEntity();
npc.fallDistance = 0.0F;
if (!npc.worldObj.isRemote && (Math.abs(prevMotionX) > 1.0E-4D || Math.abs(prevMotionY) > 1.0E-4D || Math.abs(prevMotionZ) > 1.0E-4D)) {
npc.velocityChanged = true;
}
resetMountedFlightState(npc, state);
}
@@ -283,16 +255,11 @@ public final class NPCMountUtil {
return;
}
double desired = -descendSpeed;
double previousMotionY = npc.motionY;
npc.motionY = desired;
npc.motionY = -descendSpeed;
npc.isAirBorne = true;
npc.fallDistance = 0.0F;
npc.setNpcFlyingState(true);
npc.setNpcJumpingState(false);
if (!npc.worldObj.isRemote && Math.abs(previousMotionY - desired) > 1.0E-4D) {
npc.velocityChanged = true;
}
}
public static void stabilizeDismountedRider(Entity rider) {
@@ -314,8 +281,6 @@ public final class NPCMountUtil {
rider.motionZ = previousMotionZ;
rider.fallDistance = previousFall;
}
rider.velocityChanged = true;
}
private static void updateMountedFlightState(EntityNPCInterface npc, MountState state, RoleMount mount, EntityPlayer rider) {