From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: SoSeDiK Date: Fri, 2 Dec 2022 21:44:23 +0200 Subject: [PATCH] Dynamic minecart speed diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java index 9a80cf593bbdd7681bc9395daf4545a98e07636f..012d4ad1651d7a9118b24e0589d8bdf28ed0b708 100644 --- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java @@ -573,7 +573,108 @@ public abstract class AbstractMinecart extends Entity { d5 = -d5; } - double d8 = Math.min(2.0D, vec3d1.horizontalDistance()); + // Kiterino start - dynamic minecart speed + double vanillaMaxHorizontalMovementPerTick = 0.4D; + double horizontalMomentumPerTick = vec3d1.horizontalDistance(); + + java.util.function.DoubleSupplier calculateMaxHorizontalMovementPerTick = () -> { + final double fallbackSpeedFactor = 1.15D; + double fallback = this.getMaxSpeed(); + + if (this.getPassengers().isEmpty()) + return fallback; + + if (horizontalMomentumPerTick < vanillaMaxHorizontalMovementPerTick) + return fallback; + + fallback *= fallbackSpeedFactor; + + boolean hasEligibleShape = blockpropertytrackposition == RailShape.NORTH_SOUTH || blockpropertytrackposition == RailShape.EAST_WEST; + if (!hasEligibleShape) + return fallback; + + boolean hasEligibleType = state.is(Blocks.RAIL) || (state.is(Blocks.POWERED_RAIL) && state.getValue(PoweredRailBlock.POWERED)); + if (!hasEligibleType) + return fallback; + + var eligibleNeighbors = new java.util.concurrent.atomic.AtomicInteger(); + + java.util.HashSet checkedPositions = new java.util.HashSet<>(); + checkedPositions.add(pos); + + java.util.function.BiFunction>> checkNeighbors = (cPos, cRailShape) -> { + Pair cAdjPosDiff = AbstractMinecart.exits(cRailShape); + java.util.ArrayList> newNeighbors = new java.util.ArrayList<>(); + + BlockPos n1Pos = cPos.offset(cAdjPosDiff.getFirst()); + + if (!checkedPositions.contains(n1Pos)) { + BlockState n1State = this.level.getBlockState(n1Pos); + boolean n1HasEligibleType = n1State.is(Blocks.RAIL) || (n1State.is(Blocks.POWERED_RAIL) && n1State.getValue(PoweredRailBlock.POWERED)); + if (!n1HasEligibleType) + return new java.util.ArrayList<>(); + + RailShape n1RailShape = n1State.getValue(((BaseRailBlock) n1State.getBlock()).getShapeProperty()); + if (n1RailShape != blockpropertytrackposition) + return new java.util.ArrayList<>(); + + checkedPositions.add(n1Pos); + eligibleNeighbors.incrementAndGet(); + newNeighbors.add(Pair.of(n1Pos, n1RailShape)); + } + + BlockPos n2Pos = cPos.offset(cAdjPosDiff.getSecond()); + if (!checkedPositions.contains(n2Pos)) { + BlockState n2State = this.level.getBlockState(n2Pos); + boolean n2HasEligibleType = n2State.is(Blocks.RAIL) || (n2State.is(Blocks.POWERED_RAIL) && n2State.getValue(PoweredRailBlock.POWERED)); + if (!n2HasEligibleType) + return new java.util.ArrayList<>(); + + RailShape n2RailShape = n2State.getValue(((BaseRailBlock) n2State.getBlock()).getShapeProperty()); + + if (n2RailShape != blockpropertytrackposition) + return new java.util.ArrayList<>(); + + checkedPositions.add(n2Pos); + eligibleNeighbors.incrementAndGet(); + newNeighbors.add(Pair.of(n2Pos, n2RailShape)); + } + + return newNeighbors; + }; + + + java.util.ArrayList> newNeighbors = checkNeighbors.apply(pos, blockpropertytrackposition); + + while (!newNeighbors.isEmpty() && eligibleNeighbors.get() < 16) { + java.util.ArrayList> tempNewNeighbors = new java.util.ArrayList<>(newNeighbors); + newNeighbors.clear(); + + for (Pair newNeighbor : tempNewNeighbors) { + java.util.ArrayList> result = checkNeighbors.apply(newNeighbor.getFirst(), newNeighbor.getSecond()); + + if (result.isEmpty()) { + newNeighbors.clear(); + break; + } + + newNeighbors.addAll(result); + } + } + + int eligibleForwardRailTrackCount = eligibleNeighbors.get() / 2; + + if (eligibleForwardRailTrackCount <= 1) + return fallback; + + return (2.01D + eligibleForwardRailTrackCount * 4D) / 20D; + }; + + double maxHorizontalMovementPerTick = calculateMaxHorizontalMovementPerTick.getAsDouble(); + double maxHorizontalMomentumPerTick = Math.max(maxHorizontalMovementPerTick * 5D, 4.2D); + // Kiterino end + + double d8 = Math.min(maxHorizontalMomentumPerTick, vec3d1.horizontalDistance()); // Kiterino - dynamic minecart speed, unhardcode 2.0D vec3d1 = new Vec3(d8 * d4 / d6, vec3d1.y, d8 * d5 / d6); this.setDeltaMovement(vec3d1); @@ -596,8 +697,15 @@ public abstract class AbstractMinecart extends Entity { d11 = this.getDeltaMovement().horizontalDistance(); if (d11 < 0.03D) { this.setDeltaMovement(Vec3.ZERO); - } else { - this.setDeltaMovement(this.getDeltaMovement().multiply(0.5D, 0.0D, 0.5D)); + } + else { + // Kiterino start - dynamic minecart speed + double brakeFactor = 0.5D; + if (horizontalMomentumPerTick > 4D * vanillaMaxHorizontalMovementPerTick) { + brakeFactor = Math.pow(brakeFactor, 1D + ((horizontalMomentumPerTick - 3.99D * vanillaMaxHorizontalMovementPerTick) / 1.2D)); + } + // Kiterino end + this.setDeltaMovement(this.getDeltaMovement().multiply(brakeFactor, 0.0D, brakeFactor)); // Kiterino - dynamic minecart speed, unhardcode 0.5D } } @@ -626,9 +734,10 @@ public abstract class AbstractMinecart extends Entity { d2 = d12 + d5 * d15; this.setPos(d0, d1, d2); d16 = this.isVehicle() ? 0.75D : 1.0D; - d17 = this.getMaxSpeed(); + d17 = maxHorizontalMomentumPerTick; vec3d1 = this.getDeltaMovement(); - this.move(MoverType.SELF, new Vec3(Mth.clamp(d16 * vec3d1.x, -d17, d17), 0.0D, Mth.clamp(d16 * vec3d1.z, -d17, d17))); + var movement = new Vec3(Mth.clamp(d16 * vec3d1.x, -d17, d17), 0D, Mth.clamp(d16 * vec3d1.z, -d17, d17)); + this.move(MoverType.SELF, movement); // Kiterino - dynamic minecart speed, expose into the variable if (baseblockposition.getY() != 0 && Mth.floor(this.getX()) - pos.getX() == baseblockposition.getX() && Mth.floor(this.getZ()) - pos.getZ() == baseblockposition.getZ()) { this.setPos(this.getX(), this.getY() + (double) baseblockposition.getY(), this.getZ()); } else if (baseblockposition1.getY() != 0 && Mth.floor(this.getX()) - pos.getX() == baseblockposition1.getX() && Mth.floor(this.getZ()) - pos.getZ() == baseblockposition1.getZ()) { @@ -658,26 +767,52 @@ public abstract class AbstractMinecart extends Entity { if (i != pos.getX() || j != pos.getZ()) { vec3d4 = this.getDeltaMovement(); d18 = vec3d4.horizontalDistance(); - this.setDeltaMovement(d18 * (double) (i - pos.getX()), vec3d4.y, d18 * (double) (j - pos.getZ())); + this.setDeltaMovement(d18 * Mth.clamp((double) i - pos.getX(), -1D, 1D), vec3d4.y, d18 * Mth.clamp((double) j - pos.getZ(), -1D, 1D)); // Kiterino - dynamic minecart speed, clamp values } if (flag) { vec3d4 = this.getDeltaMovement(); d18 = vec3d4.horizontalDistance(); + final double basisAccelerationPerTick = 0.021D; // Kiterino - dynamic minecart speed if (d18 > 0.01D) { + // Kiterino start - dynamic minecart speed + if (!getPassengers().isEmpty()) { + // Based on 10 ticks per second basis spent per powered block we calculate a fair acceleration per tick + // due to spending less ticks per powered block on higher speeds (and even skipping blocks) + final double basisTicksPerSecond = 10D; + // Tps = Ticks per second + final double tickMovementForBasisTps = 1D / basisTicksPerSecond; + final double maxSkippedBlocksToConsider = 3D; + + double acceleration = basisAccelerationPerTick; + final double distanceMovedHorizontally = movement.horizontalDistance(); + + if (distanceMovedHorizontally > tickMovementForBasisTps) { + acceleration *= Math.min((1D + maxSkippedBlocksToConsider) * basisTicksPerSecond, distanceMovedHorizontally / tickMovementForBasisTps); + + // Add progressively slower (or faster) acceleration for higher speeds; + double highspeedFactor = 1D + Mth.clamp(-0.45D * (distanceMovedHorizontally / tickMovementForBasisTps / basisTicksPerSecond), -0.7D, 2D); + acceleration *= highspeedFactor; + } + this.setDeltaMovement(vec3d4.add(acceleration * (vec3d4.x / d18), 0D, acceleration * (vec3d4.z / d18))); + } else { + this.setDeltaMovement(vec3d4.add(vec3d4.x / d18 * 0.06D, 0D, vec3d4.z / d18 * 0.06D)); + } + // Kiterino end double d20 = 0.06D; - this.setDeltaMovement(vec3d4.add(vec3d4.x / d18 * 0.06D, 0.0D, vec3d4.z / d18 * 0.06D)); + // this.setDeltaMovement(vec3d4.add(vec3d4.x / d18 * 0.06D, 0.0D, vec3d4.z / d18 * 0.06D)); // Kiterino - dynamic minecart speed } else { Vec3 vec3d5 = this.getDeltaMovement(); double d21 = vec3d5.x; double d22 = vec3d5.z; + final double railStopperAcceleration = basisAccelerationPerTick * 16D; // Kiterino if (blockpropertytrackposition == RailShape.EAST_WEST) { if (this.isRedstoneConductor(pos.west())) { - d21 = 0.02D; + d21 = railStopperAcceleration; // Kiterino - dynamic minecart speed, unhardcode 0.02D } else if (this.isRedstoneConductor(pos.east())) { - d21 = -0.02D; + d21 = -railStopperAcceleration; // Kiterino - dynamic minecart speed, unhardcode -0.02D } } else { if (blockpropertytrackposition != RailShape.NORTH_SOUTH) {