2025-11-07 20:15:49 -05:00
|
|
|
package noppes.npcs.util;
|
|
|
|
|
|
|
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
|
import net.minecraft.entity.EntityLivingBase;
|
|
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
|
|
|
import net.minecraft.util.MathHelper;
|
|
|
|
|
import noppes.npcs.CustomNpcs;
|
|
|
|
|
import noppes.npcs.controllers.PlayerDataController;
|
|
|
|
|
import noppes.npcs.controllers.data.PlayerData;
|
|
|
|
|
import noppes.npcs.entity.EntityNPCInterface;
|
|
|
|
|
import noppes.npcs.constants.EnumRoleType;
|
|
|
|
|
import noppes.npcs.roles.RoleMount;
|
|
|
|
|
|
|
|
|
|
public final class NPCMountUtil {
|
|
|
|
|
private static final int MOUNT_FLIGHT_TOGGLE_WINDOW = 7;
|
|
|
|
|
|
|
|
|
|
private NPCMountUtil() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class MountState {
|
|
|
|
|
public Entity lastRider;
|
|
|
|
|
public boolean flightMode;
|
|
|
|
|
public boolean jumpPressed;
|
|
|
|
|
public int flightToggleTimer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean handleMountedMovement(EntityNPCInterface npc, MountState state, float strafe, float forward) {
|
|
|
|
|
if (npc.advanced.role != EnumRoleType.Mount || !(npc.roleInterface instanceof RoleMount)) {
|
|
|
|
|
resetMountedFlightState(npc, state);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (npc.riddenByEntity != null && !(npc.riddenByEntity instanceof EntityPlayer)) {
|
|
|
|
|
npc.riddenByEntity.mountEntity(null);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!(npc.riddenByEntity instanceof EntityPlayer)) {
|
|
|
|
|
resetMountedFlightState(npc, state);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RoleMount mount = (RoleMount) npc.roleInterface;
|
|
|
|
|
EntityPlayer rider = (EntityPlayer) npc.riddenByEntity;
|
|
|
|
|
updateMountedFlightState(npc, state, mount, rider);
|
|
|
|
|
|
|
|
|
|
npc.prevRotationYaw = npc.rotationYaw = rider.rotationYaw;
|
|
|
|
|
npc.rotationPitch = rider.rotationPitch * 0.5F;
|
|
|
|
|
npc.setPositionAndRotation(npc.posX, npc.posY, npc.posZ, npc.rotationYaw, npc.rotationPitch);
|
|
|
|
|
npc.renderYawOffset = npc.rotationYaw;
|
|
|
|
|
npc.rotationYawHead = npc.rotationYaw;
|
|
|
|
|
|
|
|
|
|
float controlledStrafe = rider.moveStrafing;
|
|
|
|
|
float controlledForward = rider.moveForward;
|
|
|
|
|
if (controlledForward <= 0.0F) {
|
|
|
|
|
controlledForward *= 0.25F;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-13 19:54:10 -05:00
|
|
|
float moveSpeed = getMountMoveSpeed(npc);
|
2025-11-07 20:15:49 -05:00
|
|
|
boolean riderSprinting = rider.isSprinting() && mount.isSprintAllowed();
|
|
|
|
|
if (riderSprinting) {
|
|
|
|
|
moveSpeed *= 1.2F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!mount.isSprintAllowed() && rider.isSprinting()) {
|
|
|
|
|
rider.setSprinting(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (moveSpeed <= 0.0F) {
|
|
|
|
|
controlledStrafe = 0.0F;
|
|
|
|
|
controlledForward = 0.0F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
npc.setSprinting(riderSprinting);
|
|
|
|
|
npc.stepHeight = 1.0F;
|
|
|
|
|
|
|
|
|
|
npc.getNavigator().clearPathEntity();
|
|
|
|
|
npc.setAttackTarget(null);
|
|
|
|
|
npc.setRevengeTarget(null);
|
|
|
|
|
|
|
|
|
|
npc.fallDistance = 0.0F;
|
|
|
|
|
rider.fallDistance = 0.0F;
|
|
|
|
|
|
|
|
|
|
applyMountedVerticalMotion(npc, state, mount, rider, moveSpeed, controlledForward);
|
|
|
|
|
npc.performMountedMovement(controlledStrafe, controlledForward, moveSpeed);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-13 19:54:10 -05:00
|
|
|
private static float getMountMoveSpeed(EntityNPCInterface npc) {
|
|
|
|
|
return Math.max(0.0F, npc.getSpeed());
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-07 20:15:49 -05:00
|
|
|
private static void applyMountedVerticalMotion(EntityNPCInterface npc, MountState state, RoleMount mount, EntityLivingBase rider, float moveSpeed, float forward) {
|
|
|
|
|
if (mount == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
double jumpFactor = MathHelper.clamp_double(mount.getJumpStrength(), 0.1D, 3.0D);
|
|
|
|
|
boolean flyingEnabled = mount.isFlyingMountEnabled();
|
|
|
|
|
|
|
|
|
|
npc.setNpcJumpingState(false);
|
|
|
|
|
|
|
|
|
|
if (flyingEnabled) {
|
|
|
|
|
double ascendSpeed = MathHelper.clamp_double(mount.getFlyingAscendSpeed(), 0.1D, 3.0D);
|
|
|
|
|
double descendSpeed = MathHelper.clamp_double(mount.getFlyingDescendSpeed(), 0.05D, 3.0D);
|
|
|
|
|
boolean flightMode = isMountInFlightMode(state);
|
|
|
|
|
boolean jumpPressed = rider.isJumping;
|
|
|
|
|
boolean descendPressed = rider instanceof EntityPlayer && isSpecialKeyDown((EntityPlayer) rider);
|
|
|
|
|
|
|
|
|
|
if (flightMode) {
|
2025-11-13 19:54:10 -05:00
|
|
|
double previousMotionY = npc.motionY;
|
|
|
|
|
double newMotionY = 0.0D;
|
2025-11-07 20:15:49 -05:00
|
|
|
|
|
|
|
|
if (jumpPressed) {
|
2025-11-13 19:54:10 -05:00
|
|
|
newMotionY += ascendSpeed;
|
2025-11-07 20:15:49 -05:00
|
|
|
} else if (descendPressed) {
|
2025-11-13 19:54:10 -05:00
|
|
|
newMotionY -= descendSpeed;
|
2025-11-07 20:15:49 -05:00
|
|
|
}
|
|
|
|
|
|
2025-11-13 19:54:10 -05:00
|
|
|
newMotionY = MathHelper.clamp_double(newMotionY, -descendSpeed, ascendSpeed);
|
|
|
|
|
npc.motionY = newMotionY;
|
2025-11-07 20:15:49 -05:00
|
|
|
npc.setNpcFlyingState(true);
|
|
|
|
|
npc.setNpcJumpingState(jumpPressed);
|
|
|
|
|
npc.isAirBorne = true;
|
|
|
|
|
npc.fallDistance = 0.0F;
|
|
|
|
|
|
2025-11-13 19:54:10 -05:00
|
|
|
if (!npc.worldObj.isRemote && Math.abs(previousMotionY - newMotionY) > 1.0E-4D) {
|
|
|
|
|
npc.velocityChanged = true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-07 20:15:49 -05:00
|
|
|
if (!npc.worldObj.isRemote && rider instanceof EntityPlayer) {
|
|
|
|
|
EntityPlayer player = (EntityPlayer) rider;
|
|
|
|
|
if (!player.capabilities.isFlying) {
|
2025-11-13 19:54:10 -05:00
|
|
|
double playerPrevMotion = player.motionY;
|
2025-11-07 20:15:49 -05:00
|
|
|
player.motionY = npc.motionY;
|
2025-11-13 19:54:10 -05:00
|
|
|
if (Math.abs(playerPrevMotion - player.motionY) > 1.0E-4D) {
|
|
|
|
|
player.velocityChanged = true;
|
|
|
|
|
}
|
2025-11-07 20:15:49 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (jumpPressed && npc.onGround) {
|
2025-11-13 19:54:10 -05:00
|
|
|
double previousMotionY = npc.motionY;
|
2025-11-07 20:15:49 -05:00
|
|
|
npc.motionY = jumpFactor;
|
|
|
|
|
npc.setNpcJumpingState(true);
|
|
|
|
|
npc.isAirBorne = true;
|
|
|
|
|
npc.fallDistance = 0.0F;
|
|
|
|
|
if (!npc.worldObj.isRemote) {
|
2025-11-13 19:54:10 -05:00
|
|
|
if (Math.abs(previousMotionY - npc.motionY) > 1.0E-4D) {
|
|
|
|
|
npc.velocityChanged = true;
|
|
|
|
|
}
|
2025-11-07 20:15:49 -05:00
|
|
|
net.minecraftforge.common.ForgeHooks.onLivingJump(npc);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!npc.onGround) {
|
2025-11-13 19:54:10 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2025-11-07 20:15:49 -05:00
|
|
|
npc.setNpcFlyingState(!npc.isInWater());
|
|
|
|
|
} else {
|
|
|
|
|
npc.setNpcFlyingState(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (npc.onGround) {
|
2025-11-13 19:54:10 -05:00
|
|
|
double previousMotionY = npc.motionY;
|
2025-11-07 20:15:49 -05:00
|
|
|
if (rider.isJumping) {
|
|
|
|
|
npc.motionY = jumpFactor;
|
|
|
|
|
npc.setNpcJumpingState(true);
|
|
|
|
|
npc.isAirBorne = true;
|
|
|
|
|
npc.fallDistance = 0.0F;
|
|
|
|
|
if (!npc.worldObj.isRemote) {
|
2025-11-13 19:54:10 -05:00
|
|
|
if (Math.abs(previousMotionY - npc.motionY) > 1.0E-4D) {
|
|
|
|
|
npc.velocityChanged = true;
|
|
|
|
|
}
|
2025-11-07 20:15:49 -05:00
|
|
|
net.minecraftforge.common.ForgeHooks.onLivingJump(npc);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
npc.motionY = 0.0D;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
npc.setNpcFlyingState(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void handleMountRiderState(EntityNPCInterface npc, MountState state) {
|
|
|
|
|
if (npc.worldObj.isRemote) {
|
|
|
|
|
if (npc.advanced.role != EnumRoleType.Mount || !(npc.roleInterface instanceof RoleMount)) {
|
|
|
|
|
state.lastRider = null;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (npc.advanced.role != EnumRoleType.Mount || !(npc.roleInterface instanceof RoleMount)) {
|
|
|
|
|
state.lastRider = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RoleMount mount = (RoleMount) npc.roleInterface;
|
|
|
|
|
Entity currentRider = npc.riddenByEntity;
|
|
|
|
|
if (currentRider != null && !(currentRider instanceof EntityPlayer)) {
|
|
|
|
|
Entity dismount = currentRider;
|
|
|
|
|
dismount.mountEntity(null);
|
|
|
|
|
stabilizeDismountedRider(dismount);
|
|
|
|
|
haltMountedMotion(npc, state);
|
|
|
|
|
applyUnriddenFlightDescent(npc, state, mount);
|
|
|
|
|
currentRider = null;
|
|
|
|
|
}
|
|
|
|
|
if (currentRider != state.lastRider) {
|
|
|
|
|
if (state.lastRider != null) {
|
|
|
|
|
stabilizeDismountedRider(state.lastRider);
|
|
|
|
|
}
|
|
|
|
|
if (currentRider == null) {
|
|
|
|
|
haltMountedMotion(npc, state);
|
|
|
|
|
applyUnriddenFlightDescent(npc, state, mount);
|
|
|
|
|
} else {
|
|
|
|
|
resetMountedFlightState(npc, state);
|
|
|
|
|
}
|
|
|
|
|
state.lastRider = currentRider;
|
|
|
|
|
} else if (currentRider == null) {
|
|
|
|
|
applyUnriddenFlightDescent(npc, state, mount);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isFlyingMountWithFlightEnabled(EntityNPCInterface npc) {
|
|
|
|
|
return npc.advanced.role == EnumRoleType.Mount && npc.roleInterface instanceof RoleMount && ((RoleMount) npc.roleInterface).isFlyingMountEnabled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void haltMountedMotion(EntityNPCInterface npc, MountState state) {
|
2025-11-13 19:54:10 -05:00
|
|
|
double prevMotionX = npc.motionX;
|
|
|
|
|
double prevMotionY = npc.motionY;
|
|
|
|
|
double prevMotionZ = npc.motionZ;
|
2025-11-07 20:15:49 -05:00
|
|
|
npc.motionX = 0.0D;
|
|
|
|
|
npc.motionY = 0.0D;
|
|
|
|
|
npc.motionZ = 0.0D;
|
|
|
|
|
npc.isAirBorne = false;
|
|
|
|
|
npc.setSprinting(false);
|
|
|
|
|
npc.moveForward = 0.0F;
|
|
|
|
|
npc.moveStrafing = 0.0F;
|
|
|
|
|
npc.setAIMoveSpeed(0.0F);
|
|
|
|
|
npc.limbSwingAmount = 0.0F;
|
|
|
|
|
npc.limbSwing = 0.0F;
|
|
|
|
|
npc.getNavigator().clearPathEntity();
|
|
|
|
|
npc.fallDistance = 0.0F;
|
2025-11-13 19:54:10 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2025-11-07 20:15:49 -05:00
|
|
|
resetMountedFlightState(npc, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void applyUnriddenFlightDescent(EntityNPCInterface npc, MountState state, RoleMount mount) {
|
|
|
|
|
if (mount == null || !mount.isFlyingMountEnabled()) {
|
|
|
|
|
npc.setNpcFlyingState(false);
|
|
|
|
|
npc.setNpcJumpingState(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-11-07 22:44:22 -05:00
|
|
|
if (npc.canFly()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-11-07 20:15:49 -05:00
|
|
|
if (npc.onGround) {
|
|
|
|
|
npc.motionY = 0.0D;
|
|
|
|
|
npc.setNpcFlyingState(false);
|
|
|
|
|
npc.setNpcJumpingState(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double descendSpeed = MathHelper.clamp_double(mount.getFlyingDescendSpeed(), 0.05D, 3.0D);
|
|
|
|
|
if (descendSpeed <= 0.0D) {
|
|
|
|
|
npc.setNpcFlyingState(false);
|
|
|
|
|
npc.setNpcJumpingState(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double desired = -descendSpeed;
|
2025-11-13 19:54:10 -05:00
|
|
|
double previousMotionY = npc.motionY;
|
2025-11-07 20:15:49 -05:00
|
|
|
npc.motionY = desired;
|
|
|
|
|
npc.isAirBorne = true;
|
|
|
|
|
npc.fallDistance = 0.0F;
|
|
|
|
|
npc.setNpcFlyingState(true);
|
|
|
|
|
npc.setNpcJumpingState(false);
|
2025-11-13 19:54:10 -05:00
|
|
|
if (!npc.worldObj.isRemote && Math.abs(previousMotionY - desired) > 1.0E-4D) {
|
|
|
|
|
npc.velocityChanged = true;
|
|
|
|
|
}
|
2025-11-07 20:15:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void stabilizeDismountedRider(Entity rider) {
|
|
|
|
|
boolean wasOnGround = rider.onGround;
|
|
|
|
|
double previousMotionX = rider.motionX;
|
|
|
|
|
double previousMotionY = rider.motionY;
|
|
|
|
|
double previousMotionZ = rider.motionZ;
|
|
|
|
|
float previousFall = rider.fallDistance;
|
|
|
|
|
|
|
|
|
|
if (wasOnGround) {
|
|
|
|
|
rider.motionX = 0.0D;
|
|
|
|
|
rider.motionY = 0.0D;
|
|
|
|
|
rider.motionZ = 0.0D;
|
|
|
|
|
rider.fallDistance = 0.0F;
|
|
|
|
|
rider.onGround = true;
|
|
|
|
|
} else {
|
|
|
|
|
rider.motionX = previousMotionX;
|
|
|
|
|
rider.motionY = previousMotionY;
|
|
|
|
|
rider.motionZ = previousMotionZ;
|
|
|
|
|
rider.fallDistance = previousFall;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rider.velocityChanged = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void updateMountedFlightState(EntityNPCInterface npc, MountState state, RoleMount mount, EntityPlayer rider) {
|
|
|
|
|
if (mount == null || rider == null || !mount.isFlyingMountEnabled()) {
|
|
|
|
|
resetMountedFlightState(npc, state);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (npc.onGround) {
|
|
|
|
|
state.flightMode = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean jumpPressed = rider.isJumping;
|
|
|
|
|
if (jumpPressed && !state.jumpPressed) {
|
|
|
|
|
if (state.flightToggleTimer > 0) {
|
|
|
|
|
state.flightMode = !state.flightMode;
|
|
|
|
|
state.flightToggleTimer = 0;
|
|
|
|
|
} else {
|
|
|
|
|
state.flightToggleTimer = MOUNT_FLIGHT_TOGGLE_WINDOW;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state.flightToggleTimer > 0) {
|
|
|
|
|
state.flightToggleTimer--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state.jumpPressed = jumpPressed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isMountInFlightMode(MountState state) {
|
|
|
|
|
return state.flightMode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void resetMountedFlightState(EntityNPCInterface npc, MountState state) {
|
|
|
|
|
state.flightMode = false;
|
|
|
|
|
state.jumpPressed = false;
|
|
|
|
|
state.flightToggleTimer = 0;
|
|
|
|
|
npc.setNpcFlyingState(false);
|
|
|
|
|
npc.setNpcJumpingState(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static boolean isSpecialKeyDown(EntityPlayer rider) {
|
|
|
|
|
if (rider == null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (rider.worldObj.isRemote) {
|
|
|
|
|
PlayerData data = CustomNpcs.proxy.getPlayerData(rider);
|
|
|
|
|
return data != null && data.isSpecialKeyDown();
|
|
|
|
|
}
|
|
|
|
|
PlayerData data = PlayerDataController.Instance.getPlayerData(rider);
|
|
|
|
|
return data != null && data.isSpecialKeyDown();
|
|
|
|
|
}
|
|
|
|
|
}
|