574 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			574 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.entity.vehicle;
 | |
| 
 | |
| import com.mojang.datafixers.util.Pair;
 | |
| import io.netty.buffer.ByteBuf;
 | |
| import java.util.LinkedList;
 | |
| import java.util.List;
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.core.Vec3i;
 | |
| import net.minecraft.network.codec.ByteBufCodecs;
 | |
| import net.minecraft.network.codec.StreamCodec;
 | |
| import net.minecraft.server.level.ServerLevel;
 | |
| import net.minecraft.server.level.ServerPlayer;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.world.entity.Entity;
 | |
| import net.minecraft.world.entity.EntitySelector;
 | |
| import net.minecraft.world.entity.MoverType;
 | |
| import net.minecraft.world.entity.animal.IronGolem;
 | |
| import net.minecraft.world.entity.player.Player;
 | |
| import net.minecraft.world.level.GameRules;
 | |
| import net.minecraft.world.level.block.BaseRailBlock;
 | |
| import net.minecraft.world.level.block.Blocks;
 | |
| import net.minecraft.world.level.block.PoweredRailBlock;
 | |
| import net.minecraft.world.level.block.state.BlockState;
 | |
| import net.minecraft.world.level.block.state.properties.RailShape;
 | |
| import net.minecraft.world.phys.AABB;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| public class NewMinecartBehavior extends MinecartBehavior {
 | |
| 	public static final int POS_ROT_LERP_TICKS = 3;
 | |
| 	public static final double ON_RAIL_Y_OFFSET = 0.1;
 | |
| 	public static final double OPPOSING_SLOPES_REST_AT_SPEED_THRESHOLD = 0.005;
 | |
| 	@Nullable
 | |
| 	private NewMinecartBehavior.StepPartialTicks cacheIndexAlpha;
 | |
| 	private int cachedLerpDelay;
 | |
| 	private float cachedPartialTick;
 | |
| 	private int lerpDelay = 0;
 | |
| 	public final List<NewMinecartBehavior.MinecartStep> lerpSteps = new LinkedList();
 | |
| 	public final List<NewMinecartBehavior.MinecartStep> currentLerpSteps = new LinkedList();
 | |
| 	public double currentLerpStepsTotalWeight = 0.0;
 | |
| 	public NewMinecartBehavior.MinecartStep oldLerp = NewMinecartBehavior.MinecartStep.ZERO;
 | |
| 
 | |
| 	public NewMinecartBehavior(AbstractMinecart minecart) {
 | |
| 		super(minecart);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void tick() {
 | |
| 		if (this.level() instanceof ServerLevel serverLevel) {
 | |
| 			BlockPos var5 = this.minecart.getCurrentBlockPosOrRailBelow();
 | |
| 			BlockState blockState = this.level().getBlockState(var5);
 | |
| 			if (this.minecart.isFirstTick()) {
 | |
| 				this.minecart.setOnRails(BaseRailBlock.isRail(blockState));
 | |
| 				this.adjustToRails(var5, blockState, true);
 | |
| 			}
 | |
| 
 | |
| 			this.minecart.applyGravity();
 | |
| 			this.minecart.moveAlongTrack(serverLevel);
 | |
| 		} else {
 | |
| 			this.lerpClientPositionAndRotation();
 | |
| 			boolean bl = BaseRailBlock.isRail(this.level().getBlockState(this.minecart.getCurrentBlockPosOrRailBelow()));
 | |
| 			this.minecart.setOnRails(bl);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void lerpClientPositionAndRotation() {
 | |
| 		if (--this.lerpDelay <= 0) {
 | |
| 			this.setOldLerpValues();
 | |
| 			this.currentLerpSteps.clear();
 | |
| 			if (!this.lerpSteps.isEmpty()) {
 | |
| 				this.currentLerpSteps.addAll(this.lerpSteps);
 | |
| 				this.lerpSteps.clear();
 | |
| 				this.currentLerpStepsTotalWeight = 0.0;
 | |
| 
 | |
| 				for (NewMinecartBehavior.MinecartStep minecartStep : this.currentLerpSteps) {
 | |
| 					this.currentLerpStepsTotalWeight = this.currentLerpStepsTotalWeight + minecartStep.weight;
 | |
| 				}
 | |
| 
 | |
| 				this.lerpDelay = this.currentLerpStepsTotalWeight == 0.0 ? 0 : 3;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (this.cartHasPosRotLerp()) {
 | |
| 			this.setPos(this.getCartLerpPosition(1.0F));
 | |
| 			this.setDeltaMovement(this.getCartLerpMovements(1.0F));
 | |
| 			this.setXRot(this.getCartLerpXRot(1.0F));
 | |
| 			this.setYRot(this.getCartLerpYRot(1.0F));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void setOldLerpValues() {
 | |
| 		this.oldLerp = new NewMinecartBehavior.MinecartStep(this.position(), this.getDeltaMovement(), this.getYRot(), this.getXRot(), 0.0F);
 | |
| 	}
 | |
| 
 | |
| 	public boolean cartHasPosRotLerp() {
 | |
| 		return !this.currentLerpSteps.isEmpty();
 | |
| 	}
 | |
| 
 | |
| 	public float getCartLerpXRot(float partialTick) {
 | |
| 		NewMinecartBehavior.StepPartialTicks stepPartialTicks = this.getCurrentLerpStep(partialTick);
 | |
| 		return Mth.rotLerp(stepPartialTicks.partialTicksInStep, stepPartialTicks.previousStep.xRot, stepPartialTicks.currentStep.xRot);
 | |
| 	}
 | |
| 
 | |
| 	public float getCartLerpYRot(float partialTick) {
 | |
| 		NewMinecartBehavior.StepPartialTicks stepPartialTicks = this.getCurrentLerpStep(partialTick);
 | |
| 		return Mth.rotLerp(stepPartialTicks.partialTicksInStep, stepPartialTicks.previousStep.yRot, stepPartialTicks.currentStep.yRot);
 | |
| 	}
 | |
| 
 | |
| 	public Vec3 getCartLerpPosition(float partialTick) {
 | |
| 		NewMinecartBehavior.StepPartialTicks stepPartialTicks = this.getCurrentLerpStep(partialTick);
 | |
| 		return Mth.lerp(stepPartialTicks.partialTicksInStep, stepPartialTicks.previousStep.position, stepPartialTicks.currentStep.position);
 | |
| 	}
 | |
| 
 | |
| 	public Vec3 getCartLerpMovements(float partialTick) {
 | |
| 		NewMinecartBehavior.StepPartialTicks stepPartialTicks = this.getCurrentLerpStep(partialTick);
 | |
| 		return Mth.lerp(stepPartialTicks.partialTicksInStep, stepPartialTicks.previousStep.movement, stepPartialTicks.currentStep.movement);
 | |
| 	}
 | |
| 
 | |
| 	private NewMinecartBehavior.StepPartialTicks getCurrentLerpStep(float partialTick) {
 | |
| 		if (partialTick == this.cachedPartialTick && this.lerpDelay == this.cachedLerpDelay && this.cacheIndexAlpha != null) {
 | |
| 			return this.cacheIndexAlpha;
 | |
| 		} else {
 | |
| 			float f = (3 - this.lerpDelay + partialTick) / 3.0F;
 | |
| 			float g = 0.0F;
 | |
| 			float h = 1.0F;
 | |
| 			boolean bl = false;
 | |
| 
 | |
| 			int i;
 | |
| 			for (i = 0; i < this.currentLerpSteps.size(); i++) {
 | |
| 				float j = ((NewMinecartBehavior.MinecartStep)this.currentLerpSteps.get(i)).weight;
 | |
| 				if (!(j <= 0.0F)) {
 | |
| 					g += j;
 | |
| 					if (g >= this.currentLerpStepsTotalWeight * f) {
 | |
| 						float k = g - j;
 | |
| 						h = (float)((f * this.currentLerpStepsTotalWeight - k) / j);
 | |
| 						bl = true;
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (!bl) {
 | |
| 				i = this.currentLerpSteps.size() - 1;
 | |
| 			}
 | |
| 
 | |
| 			NewMinecartBehavior.MinecartStep minecartStep = (NewMinecartBehavior.MinecartStep)this.currentLerpSteps.get(i);
 | |
| 			NewMinecartBehavior.MinecartStep minecartStep2 = i > 0 ? (NewMinecartBehavior.MinecartStep)this.currentLerpSteps.get(i - 1) : this.oldLerp;
 | |
| 			this.cacheIndexAlpha = new NewMinecartBehavior.StepPartialTicks(h, minecartStep, minecartStep2);
 | |
| 			this.cachedLerpDelay = this.lerpDelay;
 | |
| 			this.cachedPartialTick = partialTick;
 | |
| 			return this.cacheIndexAlpha;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void adjustToRails(BlockPos pos, BlockState state, boolean snapToStart) {
 | |
| 		if (BaseRailBlock.isRail(state)) {
 | |
| 			RailShape railShape = state.getValue(((BaseRailBlock)state.getBlock()).getShapeProperty());
 | |
| 			Pair<Vec3i, Vec3i> pair = AbstractMinecart.exits(railShape);
 | |
| 			Vec3 vec3 = new Vec3(pair.getFirst()).scale(0.5);
 | |
| 			Vec3 vec32 = new Vec3(pair.getSecond()).scale(0.5);
 | |
| 			Vec3 vec33 = vec3.horizontal();
 | |
| 			Vec3 vec34 = vec32.horizontal();
 | |
| 			if (this.getDeltaMovement().length() > 1.0E-5F && this.getDeltaMovement().dot(vec33) < this.getDeltaMovement().dot(vec34)
 | |
| 				|| this.isDecending(vec34, railShape)) {
 | |
| 				Vec3 vec35 = vec33;
 | |
| 				vec33 = vec34;
 | |
| 				vec34 = vec35;
 | |
| 			}
 | |
| 
 | |
| 			float f = 180.0F - (float)(Math.atan2(vec33.z, vec33.x) * 180.0 / Math.PI);
 | |
| 			f += this.minecart.isFlipped() ? 180.0F : 0.0F;
 | |
| 			Vec3 vec36 = this.position();
 | |
| 			boolean bl = vec3.x() != vec32.x() && vec3.z() != vec32.z();
 | |
| 			Vec3 vec310;
 | |
| 			if (bl) {
 | |
| 				Vec3 vec37 = vec32.subtract(vec3);
 | |
| 				Vec3 vec38 = vec36.subtract(pos.getBottomCenter()).subtract(vec3);
 | |
| 				Vec3 vec39 = vec37.scale(vec37.dot(vec38) / vec37.dot(vec37));
 | |
| 				vec310 = pos.getBottomCenter().add(vec3).add(vec39);
 | |
| 				f = 180.0F - (float)(Math.atan2(vec39.z, vec39.x) * 180.0 / Math.PI);
 | |
| 				f += this.minecart.isFlipped() ? 180.0F : 0.0F;
 | |
| 			} else {
 | |
| 				boolean bl2 = vec3.subtract(vec32).x != 0.0;
 | |
| 				boolean bl3 = vec3.subtract(vec32).z != 0.0;
 | |
| 				vec310 = new Vec3(bl3 ? pos.getCenter().x : vec36.x, pos.getY(), bl2 ? pos.getCenter().z : vec36.z);
 | |
| 			}
 | |
| 
 | |
| 			Vec3 vec37 = vec310.subtract(vec36);
 | |
| 			this.setPos(vec36.add(vec37));
 | |
| 			float g = 0.0F;
 | |
| 			boolean bl4 = vec3.y() != vec32.y();
 | |
| 			if (bl4) {
 | |
| 				Vec3 vec311 = pos.getBottomCenter().add(vec34);
 | |
| 				double d = vec311.distanceTo(this.position());
 | |
| 				this.setPos(this.position().add(0.0, d + 0.1, 0.0));
 | |
| 				g = this.minecart.isFlipped() ? 45.0F : -45.0F;
 | |
| 			} else {
 | |
| 				this.setPos(this.position().add(0.0, 0.1, 0.0));
 | |
| 			}
 | |
| 
 | |
| 			this.setRotation(f, g);
 | |
| 			double e = vec36.distanceTo(this.position());
 | |
| 			if (e > 0.0) {
 | |
| 				this.lerpSteps
 | |
| 					.add(new NewMinecartBehavior.MinecartStep(this.position(), this.getDeltaMovement(), this.getYRot(), this.getXRot(), snapToStart ? 0.0F : (float)e));
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void setRotation(float yRot, float xRot) {
 | |
| 		double d = Math.abs(yRot - this.getYRot());
 | |
| 		if (d >= 175.0 && d <= 185.0) {
 | |
| 			this.minecart.setFlipped(!this.minecart.isFlipped());
 | |
| 			yRot -= 180.0F;
 | |
| 			xRot *= -1.0F;
 | |
| 		}
 | |
| 
 | |
| 		xRot = Math.clamp(xRot, -45.0F, 45.0F);
 | |
| 		this.setXRot(xRot % 360.0F);
 | |
| 		this.setYRot(yRot % 360.0F);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void moveAlongTrack(ServerLevel level) {
 | |
| 		for (NewMinecartBehavior.TrackIteration trackIteration = new NewMinecartBehavior.TrackIteration();
 | |
| 			trackIteration.shouldIterate() && this.minecart.isAlive();
 | |
| 			trackIteration.firstIteration = false
 | |
| 		) {
 | |
| 			Vec3 vec3 = this.getDeltaMovement();
 | |
| 			BlockPos blockPos = this.minecart.getCurrentBlockPosOrRailBelow();
 | |
| 			BlockState blockState = this.level().getBlockState(blockPos);
 | |
| 			boolean bl = BaseRailBlock.isRail(blockState);
 | |
| 			if (this.minecart.isOnRails() != bl) {
 | |
| 				this.minecart.setOnRails(bl);
 | |
| 				this.adjustToRails(blockPos, blockState, false);
 | |
| 			}
 | |
| 
 | |
| 			if (bl) {
 | |
| 				this.minecart.resetFallDistance();
 | |
| 				this.minecart.setOldPosAndRot();
 | |
| 				if (blockState.is(Blocks.ACTIVATOR_RAIL)) {
 | |
| 					this.minecart.activateMinecart(blockPos.getX(), blockPos.getY(), blockPos.getZ(), (Boolean)blockState.getValue(PoweredRailBlock.POWERED));
 | |
| 				}
 | |
| 
 | |
| 				RailShape railShape = blockState.getValue(((BaseRailBlock)blockState.getBlock()).getShapeProperty());
 | |
| 				Vec3 vec32 = this.calculateTrackSpeed(level, vec3.horizontal(), trackIteration, blockPos, blockState, railShape);
 | |
| 				if (trackIteration.firstIteration) {
 | |
| 					trackIteration.movementLeft = vec32.horizontalDistance();
 | |
| 				} else {
 | |
| 					trackIteration.movementLeft = trackIteration.movementLeft + (vec32.horizontalDistance() - vec3.horizontalDistance());
 | |
| 				}
 | |
| 
 | |
| 				this.setDeltaMovement(vec32);
 | |
| 				trackIteration.movementLeft = this.minecart.makeStepAlongTrack(blockPos, railShape, trackIteration.movementLeft);
 | |
| 			} else {
 | |
| 				this.minecart.comeOffTrack(level);
 | |
| 				trackIteration.movementLeft = 0.0;
 | |
| 			}
 | |
| 
 | |
| 			Vec3 vec33 = this.position();
 | |
| 			Vec3 vec32 = vec33.subtract(this.minecart.oldPosition());
 | |
| 			double d = vec32.length();
 | |
| 			if (d > 1.0E-5F) {
 | |
| 				if (!(vec32.horizontalDistanceSqr() > 1.0E-5F)) {
 | |
| 					if (!this.minecart.isOnRails()) {
 | |
| 						this.setXRot(this.minecart.onGround() ? 0.0F : Mth.rotLerp(0.2F, this.getXRot(), 0.0F));
 | |
| 					}
 | |
| 				} else {
 | |
| 					float f = 180.0F - (float)(Math.atan2(vec32.z, vec32.x) * 180.0 / Math.PI);
 | |
| 					float g = this.minecart.onGround() && !this.minecart.isOnRails()
 | |
| 						? 0.0F
 | |
| 						: 90.0F - (float)(Math.atan2(vec32.horizontalDistance(), vec32.y) * 180.0 / Math.PI);
 | |
| 					f += this.minecart.isFlipped() ? 180.0F : 0.0F;
 | |
| 					g *= this.minecart.isFlipped() ? -1.0F : 1.0F;
 | |
| 					this.setRotation(f, g);
 | |
| 				}
 | |
| 
 | |
| 				this.lerpSteps
 | |
| 					.add(new NewMinecartBehavior.MinecartStep(vec33, this.getDeltaMovement(), this.getYRot(), this.getXRot(), (float)Math.min(d, this.getMaxSpeed(level))));
 | |
| 			} else if (vec3.horizontalDistanceSqr() > 0.0) {
 | |
| 				this.lerpSteps.add(new NewMinecartBehavior.MinecartStep(vec33, this.getDeltaMovement(), this.getYRot(), this.getXRot(), 1.0F));
 | |
| 			}
 | |
| 
 | |
| 			if (d > 1.0E-5F || trackIteration.firstIteration) {
 | |
| 				this.minecart.applyEffectsFromBlocks();
 | |
| 				this.minecart.applyEffectsFromBlocks();
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private Vec3 calculateTrackSpeed(
 | |
| 		ServerLevel level, Vec3 speed, NewMinecartBehavior.TrackIteration trackIteration, BlockPos pos, BlockState state, RailShape railShape
 | |
| 	) {
 | |
| 		Vec3 vec3 = speed;
 | |
| 		if (!trackIteration.hasGainedSlopeSpeed) {
 | |
| 			Vec3 vec32 = this.calculateSlopeSpeed(speed, railShape);
 | |
| 			if (vec32.horizontalDistanceSqr() != speed.horizontalDistanceSqr()) {
 | |
| 				trackIteration.hasGainedSlopeSpeed = true;
 | |
| 				vec3 = vec32;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (trackIteration.firstIteration) {
 | |
| 			Vec3 vec32 = this.calculatePlayerInputSpeed(vec3);
 | |
| 			if (vec32.horizontalDistanceSqr() != vec3.horizontalDistanceSqr()) {
 | |
| 				trackIteration.hasHalted = true;
 | |
| 				vec3 = vec32;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (!trackIteration.hasHalted) {
 | |
| 			Vec3 vec32 = this.calculateHaltTrackSpeed(vec3, state);
 | |
| 			if (vec32.horizontalDistanceSqr() != vec3.horizontalDistanceSqr()) {
 | |
| 				trackIteration.hasHalted = true;
 | |
| 				vec3 = vec32;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (trackIteration.firstIteration) {
 | |
| 			vec3 = this.minecart.applyNaturalSlowdown(vec3);
 | |
| 			if (vec3.lengthSqr() > 0.0) {
 | |
| 				double d = Math.min(vec3.length(), this.minecart.getMaxSpeed(level));
 | |
| 				vec3 = vec3.normalize().scale(d);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (!trackIteration.hasBoosted) {
 | |
| 			Vec3 vec32 = this.calculateBoostTrackSpeed(vec3, pos, state);
 | |
| 			if (vec32.horizontalDistanceSqr() != vec3.horizontalDistanceSqr()) {
 | |
| 				trackIteration.hasBoosted = true;
 | |
| 				vec3 = vec32;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return vec3;
 | |
| 	}
 | |
| 
 | |
| 	private Vec3 calculateSlopeSpeed(Vec3 speed, RailShape railShape) {
 | |
| 		double d = Math.max(0.0078125, speed.horizontalDistance() * 0.02);
 | |
| 		if (this.minecart.isInWater()) {
 | |
| 			d *= 0.2;
 | |
| 		}
 | |
| 		return switch (railShape) {
 | |
| 			case ASCENDING_EAST -> speed.add(-d, 0.0, 0.0);
 | |
| 			case ASCENDING_WEST -> speed.add(d, 0.0, 0.0);
 | |
| 			case ASCENDING_NORTH -> speed.add(0.0, 0.0, d);
 | |
| 			case ASCENDING_SOUTH -> speed.add(0.0, 0.0, -d);
 | |
| 			default -> speed;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	private Vec3 calculatePlayerInputSpeed(Vec3 speed) {
 | |
| 		if (this.minecart.getFirstPassenger() instanceof ServerPlayer serverPlayer) {
 | |
| 			Vec3 vec3 = serverPlayer.getLastClientMoveIntent();
 | |
| 			if (vec3.lengthSqr() > 0.0) {
 | |
| 				Vec3 vec32 = vec3.normalize();
 | |
| 				double d = speed.horizontalDistanceSqr();
 | |
| 				if (vec32.lengthSqr() > 0.0 && d < 0.01) {
 | |
| 					return speed.add(new Vec3(vec32.x, 0.0, vec32.z).normalize().scale(0.001));
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return speed;
 | |
| 		} else {
 | |
| 			return speed;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private Vec3 calculateHaltTrackSpeed(Vec3 speed, BlockState state) {
 | |
| 		if (state.is(Blocks.POWERED_RAIL) && !(Boolean)state.getValue(PoweredRailBlock.POWERED)) {
 | |
| 			return speed.length() < 0.03 ? Vec3.ZERO : speed.scale(0.5);
 | |
| 		} else {
 | |
| 			return speed;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private Vec3 calculateBoostTrackSpeed(Vec3 speed, BlockPos pos, BlockState state) {
 | |
| 		if (state.is(Blocks.POWERED_RAIL) && (Boolean)state.getValue(PoweredRailBlock.POWERED)) {
 | |
| 			if (speed.length() > 0.01) {
 | |
| 				return speed.normalize().scale(speed.length() + 0.06);
 | |
| 			} else {
 | |
| 				Vec3 vec3 = this.minecart.getRedstoneDirection(pos);
 | |
| 				return vec3.lengthSqr() <= 0.0 ? speed : vec3.scale(speed.length() + 0.2);
 | |
| 			}
 | |
| 		} else {
 | |
| 			return speed;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public double stepAlongTrack(BlockPos pos, RailShape railShape, double speed) {
 | |
| 		if (speed < 1.0E-5F) {
 | |
| 			return 0.0;
 | |
| 		} else {
 | |
| 			Vec3 vec3 = this.position();
 | |
| 			Pair<Vec3i, Vec3i> pair = AbstractMinecart.exits(railShape);
 | |
| 			Vec3i vec3i = pair.getFirst();
 | |
| 			Vec3i vec3i2 = pair.getSecond();
 | |
| 			Vec3 vec32 = this.getDeltaMovement().horizontal();
 | |
| 			if (vec32.length() < 1.0E-5F) {
 | |
| 				this.setDeltaMovement(Vec3.ZERO);
 | |
| 				return 0.0;
 | |
| 			} else {
 | |
| 				boolean bl = vec3i.getY() != vec3i2.getY();
 | |
| 				Vec3 vec33 = new Vec3(vec3i2).scale(0.5).horizontal();
 | |
| 				Vec3 vec34 = new Vec3(vec3i).scale(0.5).horizontal();
 | |
| 				if (vec32.dot(vec34) < vec32.dot(vec33)) {
 | |
| 					vec34 = vec33;
 | |
| 				}
 | |
| 
 | |
| 				Vec3 vec35 = pos.getBottomCenter().add(vec34).add(0.0, 0.1, 0.0).add(vec34.normalize().scale(1.0E-5F));
 | |
| 				if (bl && !this.isDecending(vec32, railShape)) {
 | |
| 					vec35 = vec35.add(0.0, 1.0, 0.0);
 | |
| 				}
 | |
| 
 | |
| 				Vec3 vec36 = vec35.subtract(this.position()).normalize();
 | |
| 				vec32 = vec36.scale(vec32.length() / vec36.horizontalDistance());
 | |
| 				Vec3 vec37 = vec3.add(vec32.normalize().scale(speed * (bl ? Mth.SQRT_OF_TWO : 1.0F)));
 | |
| 				if (vec3.distanceToSqr(vec35) <= vec3.distanceToSqr(vec37)) {
 | |
| 					speed = vec35.subtract(vec37).horizontalDistance();
 | |
| 					vec37 = vec35;
 | |
| 				} else {
 | |
| 					speed = 0.0;
 | |
| 				}
 | |
| 
 | |
| 				this.minecart.move(MoverType.SELF, vec37.subtract(vec3));
 | |
| 				BlockState blockState = this.level().getBlockState(BlockPos.containing(vec37));
 | |
| 				if (bl) {
 | |
| 					if (BaseRailBlock.isRail(blockState)) {
 | |
| 						RailShape railShape2 = blockState.getValue(((BaseRailBlock)blockState.getBlock()).getShapeProperty());
 | |
| 						if (this.restAtVShape(railShape, railShape2)) {
 | |
| 							return 0.0;
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					double d = vec35.horizontal().distanceTo(this.position().horizontal());
 | |
| 					double e = vec35.y + (this.isDecending(vec32, railShape) ? d : -d);
 | |
| 					if (this.position().y < e) {
 | |
| 						this.setPos(this.position().x, e, this.position().z);
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if (this.position().distanceTo(vec3) < 1.0E-5F && vec37.distanceTo(vec3) > 1.0E-5F) {
 | |
| 					this.setDeltaMovement(Vec3.ZERO);
 | |
| 					return 0.0;
 | |
| 				} else {
 | |
| 					this.setDeltaMovement(vec32);
 | |
| 					return speed;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private boolean restAtVShape(RailShape shape1, RailShape shape2) {
 | |
| 		if (this.getDeltaMovement().lengthSqr() < 0.005
 | |
| 			&& shape2.isSlope()
 | |
| 			&& this.isDecending(this.getDeltaMovement(), shape1)
 | |
| 			&& !this.isDecending(this.getDeltaMovement(), shape2)) {
 | |
| 			this.setDeltaMovement(Vec3.ZERO);
 | |
| 			return true;
 | |
| 		} else {
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public double getMaxSpeed(ServerLevel level) {
 | |
| 		return level.getGameRules().getInt(GameRules.RULE_MINECART_MAX_SPEED) * (this.minecart.isInWater() ? 0.5 : 1.0) / 20.0;
 | |
| 	}
 | |
| 
 | |
| 	private boolean isDecending(Vec3 speed, RailShape railShape) {
 | |
| 		return switch (railShape) {
 | |
| 			case ASCENDING_EAST -> speed.x < 0.0;
 | |
| 			case ASCENDING_WEST -> speed.x > 0.0;
 | |
| 			case ASCENDING_NORTH -> speed.z > 0.0;
 | |
| 			case ASCENDING_SOUTH -> speed.z < 0.0;
 | |
| 			default -> false;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public double getSlowdownFactor() {
 | |
| 		return this.minecart.isVehicle() ? 0.997 : 0.975;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public boolean pushAndPickupEntities() {
 | |
| 		boolean bl = this.pickupEntities(this.minecart.getBoundingBox().inflate(0.2, 0.0, 0.2));
 | |
| 		if (!this.minecart.horizontalCollision && !this.minecart.verticalCollision) {
 | |
| 			return false;
 | |
| 		} else {
 | |
| 			boolean bl2 = this.pushEntities(this.minecart.getBoundingBox().inflate(1.0E-7));
 | |
| 			return bl && !bl2;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public boolean pickupEntities(AABB box) {
 | |
| 		if (this.minecart.isRideable() && !this.minecart.isVehicle()) {
 | |
| 			List<Entity> list = this.level().getEntities(this.minecart, box, EntitySelector.pushableBy(this.minecart));
 | |
| 			if (!list.isEmpty()) {
 | |
| 				for (Entity entity : list) {
 | |
| 					if (!(entity instanceof Player)
 | |
| 						&& !(entity instanceof IronGolem)
 | |
| 						&& !(entity instanceof AbstractMinecart)
 | |
| 						&& !this.minecart.isVehicle()
 | |
| 						&& !entity.isPassenger()) {
 | |
| 						boolean bl = entity.startRiding(this.minecart);
 | |
| 						if (bl) {
 | |
| 							return true;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	public boolean pushEntities(AABB box) {
 | |
| 		boolean bl = false;
 | |
| 		if (this.minecart.isRideable()) {
 | |
| 			List<Entity> list = this.level().getEntities(this.minecart, box, EntitySelector.pushableBy(this.minecart));
 | |
| 			if (!list.isEmpty()) {
 | |
| 				for (Entity entity : list) {
 | |
| 					if (entity instanceof Player || entity instanceof IronGolem || entity instanceof AbstractMinecart || this.minecart.isVehicle() || entity.isPassenger()) {
 | |
| 						entity.push(this.minecart);
 | |
| 						bl = true;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		} else {
 | |
| 			for (Entity entity2 : this.level().getEntities(this.minecart, box)) {
 | |
| 				if (!this.minecart.hasPassenger(entity2) && entity2.isPushable() && entity2 instanceof AbstractMinecart) {
 | |
| 					entity2.push(this.minecart);
 | |
| 					bl = true;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return bl;
 | |
| 	}
 | |
| 
 | |
| 	public record MinecartStep(Vec3 position, Vec3 movement, float yRot, float xRot, float weight) {
 | |
| 		public static final StreamCodec<ByteBuf, NewMinecartBehavior.MinecartStep> STREAM_CODEC = StreamCodec.composite(
 | |
| 			Vec3.STREAM_CODEC,
 | |
| 			NewMinecartBehavior.MinecartStep::position,
 | |
| 			Vec3.STREAM_CODEC,
 | |
| 			NewMinecartBehavior.MinecartStep::movement,
 | |
| 			ByteBufCodecs.ROTATION_BYTE,
 | |
| 			NewMinecartBehavior.MinecartStep::yRot,
 | |
| 			ByteBufCodecs.ROTATION_BYTE,
 | |
| 			NewMinecartBehavior.MinecartStep::xRot,
 | |
| 			ByteBufCodecs.FLOAT,
 | |
| 			NewMinecartBehavior.MinecartStep::weight,
 | |
| 			NewMinecartBehavior.MinecartStep::new
 | |
| 		);
 | |
| 		public static NewMinecartBehavior.MinecartStep ZERO = new NewMinecartBehavior.MinecartStep(Vec3.ZERO, Vec3.ZERO, 0.0F, 0.0F, 0.0F);
 | |
| 	}
 | |
| 
 | |
| 	record StepPartialTicks(float partialTicksInStep, NewMinecartBehavior.MinecartStep currentStep, NewMinecartBehavior.MinecartStep previousStep) {
 | |
| 	}
 | |
| 
 | |
| 	static class TrackIteration {
 | |
| 		double movementLeft = 0.0;
 | |
| 		boolean firstIteration = true;
 | |
| 		boolean hasGainedSlopeSpeed = false;
 | |
| 		boolean hasHalted = false;
 | |
| 		boolean hasBoosted = false;
 | |
| 
 | |
| 		public boolean shouldIterate() {
 | |
| 			return this.firstIteration || this.movementLeft > 1.0E-5F;
 | |
| 		}
 | |
| 	}
 | |
| }
 |