Java 17 update

This commit is contained in:
SamB440 committed 2024-11-14 15:59:51 +00:00
1 parent fe95424e28
commit 5a6f87fe22
43 files changed
+249 -433

No files matched your search

+4 -2
View File
@@ -28,8 +28,10 @@ spotless {
group = "ac.grim.grimac"
version = "2.3.68"
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
// Set to false for debug builds
// You cannot live reload classes if the jar relocates dependencies
@@ -59,15 +59,15 @@ public class AimProcessor extends Check implements RotationCheck {
if (this.xRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
Pair<Double, Integer> modeX = this.xRotMode.getMode();
if (modeX.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeX = modeX.getFirst();
if (modeX.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeX = modeX.first();
this.sensitivityX = convertToSensitivity(this.modeX);
}
}
if (this.yRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
Pair<Double, Integer> modeY = this.yRotMode.getMode();
if (modeY.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeY = modeY.getFirst();
if (modeY.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeY = modeY.first();
this.sensitivityY = convertToSensitivity(this.modeY);
}
}
@@ -39,7 +39,7 @@ public class BadPacketsO extends Check implements PacketCheck {
boolean hasID = false;
for (Pair<Long, Long> iterator : keepaliveMap) {
if (iterator.getFirst() == id) {
if (iterator.first() == id) {
hasID = true;
break;
}
@@ -55,7 +55,7 @@ public class BadPacketsO extends Check implements PacketCheck {
do {
data = keepaliveMap.poll();
if (data == null) break;
} while (data.getFirst() != id);
} while (data.first() != id);
}
}
}
@@ -208,7 +208,7 @@ public class Reach extends Check implements PacketCheck {
Vector eyePos = new Vector(from.getX(), from.getY() + eye, from.getZ());
Vector endReachPos = eyePos.clone().add(new Vector(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).getFirst();
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
if (ReachUtils.isVecInside(targetBox, eyePos)) {
minDistance = 0;
@@ -48,27 +48,21 @@ public class PositionPlace extends BlockPlaceCheck {
// So now we have the player's possible eye positions
// So then look at the face that the player has clicked
boolean flag = false;
switch (place.getDirection()) {
case NORTH: // Z- face
flag = eyePositions.minZ > combined.minZ;
break;
case SOUTH: // Z+ face
flag = eyePositions.maxZ < combined.maxZ;
break;
case EAST: // X+ face
flag = eyePositions.maxX < combined.maxX;
break;
case WEST: // X- face
flag = eyePositions.minX > combined.minX;
break;
case UP: // Y+ face
flag = eyePositions.maxY < combined.maxY;
break;
case DOWN: // Y- face
flag = eyePositions.minY > combined.minY;
break;
}
boolean flag = switch (place.getDirection()) {
case NORTH -> // Z- face
eyePositions.minZ > combined.minZ;
case SOUTH -> // Z+ face
eyePositions.maxZ < combined.maxZ;
case EAST -> // X+ face
eyePositions.maxX < combined.maxX;
case WEST -> // X- face
eyePositions.minX > combined.minX;
case UP -> // Y+ face
eyePositions.maxY < combined.maxY;
case DOWN -> // Y- face
eyePositions.minY > combined.minY;
default -> false;
};
if (flag) {
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
@@ -113,7 +113,7 @@ public class RotationPlace extends BlockPlaceCheck {
Ray trace = new Ray(player, starting.getX(), starting.getY(), starting.getZ(), lookDir.getX(), lookDir.getY());
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.getFirst() != null) return true;
if (intercept.first() != null) return true;
}
}
@@ -23,8 +23,7 @@ public class GrimSpectate extends BaseCommand {
@CommandPermission("grim.spectate")
@CommandCompletion("@players")
public void onSpectate(CommandSender sender, @Optional OnlinePlayer target) {
if (!(sender instanceof Player)) return;
Player player = (Player) sender;
if (!(sender instanceof Player player)) return;
if (target != null && target.getPlayer().getUniqueId().equals(player.getUniqueId())) {
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("cannot-run-on-self", "%prefix% &cYou cannot use this command on yourself!");
@@ -17,8 +17,7 @@ public class GrimStopSpectating extends BaseCommand {
@CommandCompletion("here")
public void onStopSpectate(CommandSender sender, String[] args) {
String string = args.length > 0 ? args[0] : null;
if (!(sender instanceof Player)) return;
Player player = (Player) sender;
if (!(sender instanceof Player player)) return;
if (GrimAPI.INSTANCE.getSpectateManager().isSpectating(player.getUniqueId())) {
boolean teleportBack = string == null || !string.equalsIgnoreCase("here");
GrimAPI.INSTANCE.getSpectateManager().disable(player, teleportBack);
@@ -225,11 +225,10 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
private static void handleBlockPlaceOrUseItem(PacketWrapper packet, GrimPlayer player) {
private static void handleBlockPlaceOrUseItem(PacketWrapper<?> packet, GrimPlayer player) {
// Legacy "use item" packet
if (packet instanceof WrapperPlayClientPlayerBlockPlacement &&
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place &&
PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
@@ -244,9 +243,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
if (packet instanceof WrapperPlayClientUseItem) {
WrapperPlayClientUseItem place = (WrapperPlayClientUseItem) packet;
if (packet instanceof WrapperPlayClientUseItem place) {
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
ItemStack placedWith = player.getInventory().getHeldItem();
@@ -258,9 +255,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
// Check for interactable first (door, etc)
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
ItemStack placedWith = player.getInventory().getHeldItem();
ItemStack offhand = player.getInventory().getOffHand();
@@ -296,8 +291,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
Vector3i blockPosition = place.getBlockPosition();
BlockFace face = place.getFace();
@@ -805,14 +799,14 @@ public class CheckManagerListener extends PacketListenerAbstract {
for (SimpleCollisionBox box : boxes) {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.getFirst() == null) continue; // No intercept
if (intercept.first() == null) continue; // No intercept
Vector hitLoc = intercept.getFirst();
Vector hitLoc = intercept.first();
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
bestHitResult = hitLoc.distanceSquared(startingVec);
bestHitLoc = hitLoc;
bestFace = intercept.getSecond();
bestFace = intercept.second();
}
}
if (bestHitLoc != null) {
@@ -827,8 +821,8 @@ public class CheckManagerListener extends PacketListenerAbstract {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.getFirst() != null) {
return new HitData(vector3i, intercept.getFirst(), intercept.getSecond(), block);
if (intercept.first() != null) {
return new HitData(vector3i, intercept.first(), intercept.second(), block);
}
}
@@ -227,9 +227,8 @@ public class PacketEntityReplication extends Check implements PacketCheck {
if (status.getStatus() == 31) {
PacketEntity hook = player.compensatedEntities.getEntity(status.getEntityId());
if (!(hook instanceof PacketEntityHook)) return;
if (!(hook instanceof PacketEntityHook hookEntity)) return;
PacketEntityHook hookEntity = (PacketEntityHook) hook;
if (hookEntity.attached == player.entityID) {
player.sendTransaction();
// We don't transaction sandwich this, it's too rare to be a real problem.
@@ -454,8 +453,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
player.latencyUtils.addRealTimeTask(lastTrans, () -> {
PacketEntity entity = player.compensatedEntities.getEntity(entityId);
if (entity == null) return;
if (entity instanceof PacketEntityTrackXRot && yaw != null) {
PacketEntityTrackXRot xRotEntity = (PacketEntityTrackXRot) entity;
if (entity instanceof PacketEntityTrackXRot xRotEntity && yaw != null) {
xRotEntity.packetYaw = yaw;
xRotEntity.steps = entity.isBoat() ? 10 : 3;
}
@@ -15,7 +15,7 @@ import java.util.BitSet;
public class PacketWorldReaderEight extends BasePacketWorldReader {
@Override
public void handleMapChunkBulk(final GrimPlayer player, final PacketSendEvent event) {
PacketWrapper wrapper = new PacketWrapper(event);
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
ByteBuf buffer = (ByteBuf) wrapper.getBuffer();
boolean skylight = wrapper.readBoolean();
@@ -47,7 +47,7 @@ public class PacketWorldReaderEight extends BasePacketWorldReader {
@Override
public void handleMapChunk(final GrimPlayer player, final PacketSendEvent event) {
PacketWrapper wrapper = new PacketWrapper(event);
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
final int chunkX = wrapper.readInt();
final int chunkZ = wrapper.readInt();
@@ -153,12 +153,12 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
VelocityData futureExplosion = player.checkManager.getExplosionHandler().getFutureExplosion();
// Velocity sets
if (futureKb.getFirst() != null) {
clientVel = futureKb.getSecond();
if (futureKb.first() != null) {
clientVel = futureKb.second();
}
// Explosion adds
if (futureExplosion != null && (futureKb.getFirst() == null || futureKb.getFirst().transaction < futureExplosion.transaction)) {
if (futureExplosion != null && (futureKb.first() == null || futureKb.first().transaction < futureExplosion.transaction)) {
clientVel.add(futureExplosion.vector);
}
@@ -328,16 +328,16 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
while (true) {
Pair<Integer, Vector3d> teleportPos = player.vehicleData.vehicleTeleports.peek();
if (teleportPos == null) break;
if (lastTransaction < teleportPos.getFirst()) {
if (lastTransaction < teleportPos.first()) {
break;
}
Vector3d position = teleportPos.getSecond();
Vector3d position = teleportPos.second();
if (position.getX() == x && position.getY() == y && position.getZ() == z) {
player.vehicleData.vehicleTeleports.poll();
return true;
} else if (lastTransaction > teleportPos.getFirst() + 1) {
} else if (lastTransaction > teleportPos.first() + 1) {
player.vehicleData.vehicleTeleports.poll();
// Vehicles have terrible netcode so just ignore it if the teleport wasn't from us setting the player back
@@ -71,14 +71,8 @@ public class SpectateManager implements Initable {
spectatingPlayers.remove(uuid);
}
private static class PreviousState {
public PreviousState(org.bukkit.GameMode gameMode, Location location) {
this.gameMode = gameMode;
this.location = location;
}
private record PreviousState(org.bukkit.GameMode gameMode, Location location) {
private final org.bukkit.GameMode gameMode;
private final Location location;
}
}
@@ -42,7 +42,7 @@ public class TickEndEvent implements Initable {
// but whatever. At least plugins can't break it, I guess.
//
// Pledge injects into another list, so we should be safe injecting into this one
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<Object>(endOfTickObject) {
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<>(endOfTickObject) {
@Override
public void onIterator() {
hasTicked = true;
@@ -326,7 +326,7 @@ public class GrimPlayer implements GrimUser {
boolean hasID = false;
int skipped = 0;
for (Pair<Short, Long> iterator : transactionsSent) {
if (iterator.getFirst() == id) {
if (iterator.first() == id) {
hasID = true;
break;
}
@@ -347,9 +347,9 @@ public class GrimPlayer implements GrimUser {
lastTransactionReceived.incrementAndGet();
lastTransReceived = System.currentTimeMillis();
transactionPing = (System.nanoTime() - data.getSecond());
playerClockAtLeast = data.getSecond();
} while (data.getFirst() != id);
transactionPing = (System.nanoTime() - data.second());
playerClockAtLeast = data.second();
} while (data.first() != id);
// A transaction means a new tick, so apply any block places
CheckManagerListener.handleQueuedPlaces(this, false, 0, 0, System.currentTimeMillis());
@@ -357,7 +357,7 @@ public class GrimPlayer implements GrimUser {
}
// Were we the ones who sent the packet?
return data != null && data.getFirst() == id;
return data != null && data.first() == id;
}
public void baseTickAddWaterPushing(Vector vector) {
@@ -443,8 +443,7 @@ public class GrimPlayer implements GrimUser {
public void disconnect(Component reason) {
String textReason;
if (reason instanceof TranslatableComponent) {
TranslatableComponent translatableComponent = (TranslatableComponent) reason;
if (reason instanceof TranslatableComponent translatableComponent) {
textReason = translatableComponent.key();
} else {
textReason = LegacyComponentSerializer.legacySection().serialize(reason);
@@ -258,8 +258,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// When in control of the entity, the player sets the entity position to their current position
riding.setPositionRaw(GetBoundingBox.getPacketEntityBoundingBox(player, player.x, player.y, player.z, riding));
if (riding instanceof PacketEntityTrackXRot) {
PacketEntityTrackXRot boat = (PacketEntityTrackXRot) riding;
if (riding instanceof PacketEntityTrackXRot boat) {
boat.packetYaw = player.xRot;
boat.interpYaw = player.xRot;
boat.steps = 0;
@@ -339,7 +338,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
boolean clientClaimsRiptide = player.packetStateData.tryingToRiptide;
if (player.packetStateData.tryingToRiptide) {
long currentTime = System.currentTimeMillis();
boolean isInWater = player.compensatedWorld.isRaining || Collisions.hasMaterial(player, player.boundingBox.copy().expand(0.1f), (block) -> Materials.isWater(CompensatedWorld.blockVersion, block.getFirst()));
boolean isInWater = player.compensatedWorld.isRaining || Collisions.hasMaterial(player, player.boundingBox.copy().expand(0.1f), (block) -> Materials.isWater(CompensatedWorld.blockVersion, block.first()));
if (currentTime - player.packetStateData.lastRiptide < 450 || !isInWater) {
player.packetStateData.tryingToRiptide = false;
@@ -350,7 +349,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
SimpleCollisionBox steppingOnBB = GetBoundingBox.getCollisionBoxForPlayer(player, player.x, player.y, player.z).expand(0.03).offset(0, -1, 0);
Collisions.hasMaterial(player, steppingOnBB, (pair) -> {
WrappedBlockState data = pair.getFirst();
WrappedBlockState data = pair.first();
if (data.getType() == StateTypes.SLIME_BLOCK && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8)) {
player.uncertaintyHandler.isSteppingOnSlime = true;
player.uncertaintyHandler.isSteppingOnBouncyBlock = true;
@@ -396,8 +395,8 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.uncertaintyHandler.isNearGlitchyBlock = player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
&& Collisions.hasMaterial(player, expandedBB.copy().expand(0.2),
checkData -> BlockTags.ANVIL.contains(checkData.getFirst().getType())
|| checkData.getFirst().getType() == StateTypes.CHEST || checkData.getFirst().getType() == StateTypes.TRAPPED_CHEST);
checkData -> BlockTags.ANVIL.contains(checkData.first().getType())
|| checkData.first().getType() == StateTypes.CHEST || checkData.first().getType() == StateTypes.TRAPPED_CHEST);
player.uncertaintyHandler.isOrWasNearGlitchyBlock = isGlitchy || player.uncertaintyHandler.isNearGlitchyBlock;
player.uncertaintyHandler.checkForHardCollision();
@@ -151,7 +151,7 @@ public class PlayerBaseTick {
// Might be null after respawn?
final Optional<WrapperPlayServerUpdateAttributes.Property> property = playerSpeed.property();
if (!property.isPresent()) return;
if (property.isEmpty()) return;
// The client first desync's this attribute
property.get().getModifiers().removeIf(modifier -> modifier.getUUID().equals(CompensatedEntities.SNOW_MODIFIER_UUID) || modifier.getName().getKey().equals("powder_snow"));
@@ -360,22 +360,12 @@ public class PlayerBaseTick {
double d7 = direction2 == BlockFace.WEST || direction2 == BlockFace.EAST ? relativeXMovement : relativeZMovement;
d6 = direction2 == BlockFace.EAST || direction2 == BlockFace.SOUTH ? 1.0 - d7 : d7;
// d7 and d6 flip the movement direction based on desired movement direction
boolean doesSuffocate;
switch (direction2) {
case EAST:
doesSuffocate = this.suffocatesAt(blockX + 1, blockZ);
break;
case WEST:
doesSuffocate = this.suffocatesAt(blockX - 1, blockZ);
break;
case NORTH:
doesSuffocate = this.suffocatesAt(blockX, blockZ - 1);
break;
default:
case SOUTH:
doesSuffocate = this.suffocatesAt(blockX, blockZ + 1);
break;
}
boolean doesSuffocate = switch (direction2) {
case EAST -> this.suffocatesAt(blockX + 1, blockZ);
case WEST -> this.suffocatesAt(blockX - 1, blockZ);
case NORTH -> this.suffocatesAt(blockX, blockZ - 1);
default -> this.suffocatesAt(blockX, blockZ + 1);
};
if (d6 >= lowestValue || doesSuffocate) continue;
lowestValue = d6;
@@ -248,21 +248,21 @@ public class PointThreeEstimator {
// Check for flowing water
Collisions.hasMaterial(player, pointThreeBox, (pair) -> {
final WrappedBlockState state = pair.getFirst();
final WrappedBlockState state = pair.first();
final StateType stateType = state.getType();
if (player.tagManager.block(SyncedTags.CLIMBABLE).contains(stateType) || (stateType == StateTypes.POWDER_SNOW && !player.compensatedEntities.getSelf().inVehicle() && player.getInventory().getBoots().getType() == ItemTypes.LEATHER_BOOTS)) {
isNearClimbable = true;
}
if (BlockTags.TRAPDOORS.contains(stateType)) {
isNearClimbable = isNearClimbable || Collisions.trapdoorUsableAsLadder(player, pair.getSecond().getX(), pair.getSecond().getY(), pair.getSecond().getZ(), state);
isNearClimbable = isNearClimbable || Collisions.trapdoorUsableAsLadder(player, pair.second().getX(), pair.second().getY(), pair.second().getZ(), state);
}
if (stateType == StateTypes.BUBBLE_COLUMN) {
isNearBubbleColumn = true;
}
if (Materials.isWater(player.getClientVersion(), pair.getFirst()) || pair.getFirst().getType() == StateTypes.LAVA) {
if (Materials.isWater(player.getClientVersion(), pair.first()) || pair.first().getType() == StateTypes.LAVA) {
isNearFluid = true;
}
@@ -303,8 +303,7 @@ public class UncertaintyHandler {
// This is the end of that section.
// I can't figure out how the client exactly tracks boost time
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityRideable) {
PacketEntityRideable vehicle = (PacketEntityRideable) player.compensatedEntities.getSelf().getRiding();
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityRideable vehicle) {
if (vehicle.currentBoostTime < vehicle.boostTimeMax + 20)
offset -= 0.01;
}
@@ -133,8 +133,8 @@ public class PredictionEngine {
// Returns pair of primary push movement, and then outputvel
Pair<Vector, Vector> output = doSeekingWallCollisions(player, primaryPushMovement, originalClientVel, clientVelAfterInput);
primaryPushMovement = output.getFirst();
Vector outputVel = clampMovementToHardBorder(player, output.getSecond());
primaryPushMovement = output.first();
Vector outputVel = clampMovementToHardBorder(player, output.second());
double resultAccuracy = outputVel.distanceSquared(player.actualMovement);
@@ -47,7 +47,7 @@ public class PredictionEngineNormal extends PredictionEngine {
// And 0.03 didn't affect onGround status
// The player cannot jump
final OptionalInt jumpBoost = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.JUMP_BOOST);
if (((!jumpBoost.isPresent() || jumpBoost.getAsInt() >= 0) && player.onGround) || !player.lastOnGround)
if (((jumpBoost.isEmpty() || jumpBoost.getAsInt() >= 0) && player.onGround) || !player.lastOnGround)
return;
JumpPower.jumpFromGround(player, jump);
@@ -17,9 +17,7 @@ import java.util.Set;
public class PredictionEngineRideableUtils {
public static Set<VectorData> handleJumps(GrimPlayer player, Set<VectorData> possibleVectors) {
if (!(player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityHorse)) return possibleVectors;
PacketEntityHorse horse = (PacketEntityHorse) player.compensatedEntities.getSelf().getRiding();
if (!(player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityHorse horse)) return possibleVectors;
// Setup player inputs
float f = player.vehicleData.vehicleHorizontal * 0.5F;
@@ -537,21 +537,14 @@ public class BlockPlace {
}
public Vector3i getNormalBlockFace() {
switch (face) {
default:
case UP:
return new Vector3i(0, 1, 0);
case DOWN:
return new Vector3i(0, -1, 0);
case SOUTH:
return new Vector3i(0, 0, 1);
case NORTH:
return new Vector3i(0, 0, -1);
case WEST:
return new Vector3i(-1, 0, 0);
case EAST:
return new Vector3i(1, 0, 0);
}
return switch (face) {
case DOWN -> new Vector3i(0, -1, 0);
case SOUTH -> new Vector3i(0, 0, 1);
case NORTH -> new Vector3i(0, 0, -1);
case WEST -> new Vector3i(-1, 0, 0);
case EAST -> new Vector3i(1, 0, 0);
default -> new Vector3i(0, 1, 0);
};
}
public void set(StateType material) {
@@ -672,7 +665,7 @@ public class BlockPlace {
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE) + 3;
Vector eyePos = new Vector(player.x, player.y + player.getEyeHeight(), player.z);
Vector endReachPos = eyePos.clone().add(new Vector(look.getX() * distance, look.getY() * distance, look.getZ() * distance));
Vector intercept = ReachUtils.calculateIntercept(box, eyePos, endReachPos).getFirst();
Vector intercept = ReachUtils.calculateIntercept(box, eyePos, endReachPos).first();
// Bring this back to relative to the block
// The player didn't even click the block... (we should force resync BEFORE we get here!)
@@ -107,17 +107,11 @@ public class ConsumesBlockPlace {
Attachment attachment = bell.getAttachment();
BlockFace dir2 = BlockFace.valueOf(direction.name());
switch (attachment) {
case FLOOR:
return AxisUtil.isSameAxis(dir, dir2);
case SINGLE_WALL:
case DOUBLE_WALL:
return !AxisUtil.isSameAxis(dir, dir2);
case CEILING:
return true;
default:
return false;
}
return switch (attachment) {
case FLOOR -> AxisUtil.isSameAxis(dir, dir2);
case SINGLE_WALL, DOUBLE_WALL -> !AxisUtil.isSameAxis(dir, dir2);
case CEILING -> true;
};
} else {
return false;
}
@@ -18,64 +18,42 @@ public class BlockFaceHelper {
*/
@Deprecated
public static BlockFace fromBukkitFace(org.bukkit.block.BlockFace face) {
switch (face) {
case NORTH:
return BlockFace.NORTH;
case SOUTH:
return BlockFace.SOUTH;
case WEST:
return BlockFace.WEST;
case EAST:
return BlockFace.EAST;
case UP:
return BlockFace.UP;
case DOWN:
return BlockFace.DOWN;
default:
return BlockFace.OTHER;
}
return switch (face) {
case NORTH -> BlockFace.NORTH;
case SOUTH -> BlockFace.SOUTH;
case WEST -> BlockFace.WEST;
case EAST -> BlockFace.EAST;
case UP -> BlockFace.UP;
case DOWN -> BlockFace.DOWN;
default -> BlockFace.OTHER;
};
}
public static BlockFace getClockWise(BlockFace face) {
switch (face) {
case NORTH:
return BlockFace.EAST;
case SOUTH:
return BlockFace.WEST;
case WEST:
return BlockFace.NORTH;
case EAST:
default:
return BlockFace.SOUTH;
}
return switch (face) {
case NORTH -> BlockFace.EAST;
case SOUTH -> BlockFace.WEST;
case WEST -> BlockFace.NORTH;
default -> BlockFace.SOUTH;
};
}
public static BlockFace getPEClockWise(BlockFace face) {
switch (face) {
case NORTH:
return BlockFace.EAST;
case SOUTH:
return BlockFace.WEST;
case WEST:
return BlockFace.NORTH;
case EAST:
default:
return BlockFace.SOUTH;
}
return switch (face) {
case NORTH -> BlockFace.EAST;
case SOUTH -> BlockFace.WEST;
case WEST -> BlockFace.NORTH;
default -> BlockFace.SOUTH;
};
}
public static BlockFace getCounterClockwise(BlockFace face) {
switch (face) {
case NORTH:
return BlockFace.WEST;
case SOUTH:
return BlockFace.EAST;
case WEST:
return BlockFace.SOUTH;
case EAST:
default:
return BlockFace.NORTH;
}
return switch (face) {
case NORTH -> BlockFace.WEST;
case SOUTH -> BlockFace.EAST;
case WEST -> BlockFace.SOUTH;
default -> BlockFace.NORTH;
};
}
public Vector offset(Vector toOffset, BlockFace face) {
@@ -54,36 +54,22 @@ public enum AxisUtil {
}
public static AxisSelect getAxis(BlockFace face) {
switch (face) {
case EAST:
return EAST.select;
case WEST:
return WEST.select;
case NORTH:
return NORTH.select;
case SOUTH:
return SOUTH.select;
case UP:
return UP.select;
case DOWN:
default:
return DOWN.select;
}
return switch (face) {
case EAST -> EAST.select;
case WEST -> WEST.select;
case NORTH -> NORTH.select;
case SOUTH -> SOUTH.select;
case UP -> UP.select;
default -> DOWN.select;
};
}
public static boolean isSameAxis(BlockFace one, BlockFace two) {
switch (one) {
case WEST:
case EAST:
return two == BlockFace.WEST || two == BlockFace.EAST;
case NORTH:
case SOUTH:
return two == BlockFace.NORTH || two == BlockFace.SOUTH;
case UP:
case DOWN:
return two == BlockFace.UP || two == BlockFace.DOWN;
default:
return false;
}
return switch (one) {
case WEST, EAST -> two == BlockFace.WEST || two == BlockFace.EAST;
case NORTH, SOUTH -> two == BlockFace.NORTH || two == BlockFace.SOUTH;
case UP, DOWN -> two == BlockFace.UP || two == BlockFace.DOWN;
default -> false;
};
}
}
@@ -21,18 +21,14 @@ public class DoorHandler implements CollisionFactory {
@Override
public CollisionBox fetch(GrimPlayer player, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
switch (fetchDirection(player, version, block, x, y, z)) {
case NORTH:
return NORTH_AABB.copy();
case SOUTH:
return SOUTH_AABB.copy();
case EAST:
return EAST_AABB.copy();
case WEST:
return WEST_AABB.copy();
}
return switch (fetchDirection(player, version, block, x, y, z)) {
case NORTH -> NORTH_AABB.copy();
case SOUTH -> SOUTH_AABB.copy();
case EAST -> EAST_AABB.copy();
case WEST -> WEST_AABB.copy();
default -> NoCollisionBox.INSTANCE;
};
return NoCollisionBox.INSTANCE;
}
public BlockFace fetchDirection(GrimPlayer player, ClientVersion version, WrappedBlockState door, int x, int y, int z) {
@@ -80,16 +76,11 @@ public class DoorHandler implements CollisionFactory {
isRightHinge = door.getHinge() == Hinge.RIGHT;
}
switch (facingDirection) {
case EAST:
default:
return isClosed ? BlockFace.EAST : (isRightHinge ? BlockFace.NORTH : BlockFace.SOUTH);
case SOUTH:
return isClosed ? BlockFace.SOUTH : (isRightHinge ? BlockFace.EAST : BlockFace.WEST);
case WEST:
return isClosed ? BlockFace.WEST : (isRightHinge ? BlockFace.SOUTH : BlockFace.NORTH);
case NORTH:
return isClosed ? BlockFace.NORTH : (isRightHinge ? BlockFace.WEST : BlockFace.EAST);
}
return switch (facingDirection) {
case SOUTH -> isClosed ? BlockFace.SOUTH : (isRightHinge ? BlockFace.EAST : BlockFace.WEST);
case WEST -> isClosed ? BlockFace.WEST : (isRightHinge ? BlockFace.SOUTH : BlockFace.NORTH);
case NORTH -> isClosed ? BlockFace.NORTH : (isRightHinge ? BlockFace.WEST : BlockFace.EAST);
default -> isClosed ? BlockFace.EAST : (isRightHinge ? BlockFace.NORTH : BlockFace.SOUTH);
};
}
}
@@ -77,17 +77,12 @@ public class DynamicStair implements CollisionFactory {
}
private static BlockFace rotateYCCW(BlockFace face) {
switch (face) {
default:
case NORTH:
return BlockFace.WEST;
case EAST:
return BlockFace.NORTH;
case SOUTH:
return BlockFace.EAST;
case WEST:
return BlockFace.SOUTH;
}
return switch (face) {
case EAST -> BlockFace.NORTH;
case SOUTH -> BlockFace.EAST;
case WEST -> BlockFace.SOUTH;
default -> BlockFace.WEST;
};
}
private static CollisionBox[] makeShapes(CollisionBox p_199779_0_, CollisionBox p_199779_1_, CollisionBox p_199779_2_, CollisionBox p_199779_3_, CollisionBox p_199779_4_) {
@@ -134,36 +129,23 @@ public class DynamicStair implements CollisionFactory {
}
private int directionToValue(BlockFace face) {
switch (face) {
default:
case UP:
case DOWN:
return -1;
case NORTH:
return 2;
case SOUTH:
return 0;
case WEST:
return 1;
case EAST:
return 3;
}
return switch (face) {
case NORTH -> 2;
case SOUTH -> 0;
case WEST -> 1;
case EAST -> 3;
default -> -1;
};
}
private EnumShape toEnumShape(Shape shape) {
switch (shape) {
default:
case STRAIGHT:
return EnumShape.STRAIGHT;
case INNER_LEFT:
return EnumShape.INNER_LEFT;
case INNER_RIGHT:
return EnumShape.INNER_RIGHT;
case OUTER_LEFT:
return EnumShape.OUTER_LEFT;
case OUTER_RIGHT:
return EnumShape.OUTER_RIGHT;
}
return switch (shape) {
case INNER_LEFT -> EnumShape.INNER_LEFT;
case INNER_RIGHT -> EnumShape.INNER_RIGHT;
case OUTER_LEFT -> EnumShape.OUTER_LEFT;
case OUTER_RIGHT -> EnumShape.OUTER_RIGHT;
default -> EnumShape.STRAIGHT;
};
}
enum EnumShape {
@@ -14,20 +14,13 @@ public class PistonBaseCollision implements CollisionFactory {
public CollisionBox fetch(GrimPlayer player, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
if (!block.isExtended()) return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
switch (block.getFacing()) {
default:
case DOWN:
return new HexCollisionBox(0, 4, 0, 16, 16, 16);
case UP:
return new HexCollisionBox(0, 0, 0, 16, 12, 16);
case NORTH:
return new HexCollisionBox(0, 0, 4, 16, 16, 16);
case SOUTH:
return new HexCollisionBox(0, 0, 0, 16, 16, 12);
case WEST:
return new HexCollisionBox(4, 0, 0, 16, 16, 16);
case EAST:
return new HexCollisionBox(0, 0, 0, 12, 16, 16);
}
return switch (block.getFacing()) {
case UP -> new HexCollisionBox(0, 0, 0, 16, 12, 16);
case NORTH -> new HexCollisionBox(0, 0, 4, 16, 16, 16);
case SOUTH -> new HexCollisionBox(0, 0, 0, 16, 16, 12);
case WEST -> new HexCollisionBox(4, 0, 0, 16, 16, 16);
case EAST -> new HexCollisionBox(0, 0, 0, 12, 16, 16);
default -> new HexCollisionBox(0, 4, 0, 16, 16, 16);
};
}
}
@@ -38,38 +38,35 @@ public class PistonHeadCollision implements CollisionFactory {
longAmount = 0;
switch (block.getFacing()) {
case DOWN:
default:
return new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 16, 4, 16),
new HexCollisionBox(6, 4, 6, 10, 16 + longAmount, 10));
case UP:
return new ComplexCollisionBox(new HexCollisionBox(0, 12, 0, 16, 16, 16),
new HexCollisionBox(6, 0 - longAmount, 6, 10, 12, 10));
case NORTH:
return new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 16, 16, 4),
new HexCollisionBox(6, 6, 4, 10, 10, 16 + longAmount));
case SOUTH:
return switch (block.getFacing()) {
case UP -> new ComplexCollisionBox(new HexCollisionBox(0, 12, 0, 16, 16, 16),
new HexCollisionBox(6, 0 - longAmount, 6, 10, 12, 10));
case NORTH -> new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 16, 16, 4),
new HexCollisionBox(6, 6, 4, 10, 10, 16 + longAmount));
case SOUTH -> {
// SOUTH piston is glitched in 1.7 and 1.8, fixed in 1.9
// Don't bother with short piston boxes as 1.7/1.8 clients don't have them
if (version.isOlderThanOrEquals(ClientVersion.V_1_8))
return new ComplexCollisionBox(new HexCollisionBox(0, 0, 12, 16, 16, 16),
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 12, 16, 16, 16),
new HexCollisionBox(4, 6, 0, 12, 10, 12));
return new ComplexCollisionBox(new HexCollisionBox(0, 0, 12, 16, 16, 16),
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 12, 16, 16, 16),
new HexCollisionBox(6, 6, 0 - longAmount, 10, 10, 12));
case WEST:
}
case WEST -> {
// WEST piston is glitched in 1.7 and 1.8, fixed in 1.9
// Don't bother with short piston boxes as 1.7/1.8 clients don't have them
if (version.isOlderThanOrEquals(ClientVersion.V_1_8))
return new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 4, 16, 16),
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 4, 16, 16),
new HexCollisionBox(6, 4, 4, 10, 12, 16));
return new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 4, 16, 16),
yield new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 4, 16, 16),
new HexCollisionBox(4, 6, 6, 16 + longAmount, 10, 10));
case EAST:
return new ComplexCollisionBox(new HexCollisionBox(12, 0, 0, 16, 16, 16),
new HexCollisionBox(0 - longAmount, 6, 4, 12, 10, 12));
}
}
case EAST -> new ComplexCollisionBox(new HexCollisionBox(12, 0, 0, 16, 16, 16),
new HexCollisionBox(0 - longAmount, 6, 4, 12, 10, 12));
default -> new ComplexCollisionBox(new HexCollisionBox(0, 0, 0, 16, 4, 16),
new HexCollisionBox(6, 4, 6, 10, 16 + longAmount, 10));
};
}
}
@@ -286,19 +286,13 @@ public class SimpleCollisionBox implements CollisionBox {
// Get the direction of block we are trying to connect to -> towards the block that is trying to connect
final BlockFace faceToSourceConnector = axis.getOppositeFace();
switch (faceToSourceConnector) {
case EAST:
case WEST:
return this.minX == 0 && this.maxX == 1;
case UP:
case DOWN:
return this.minY == 0 && this.maxY == 1;
case NORTH:
case SOUTH:
return this.minZ == 0 && this.maxZ == 1;
}
return switch (faceToSourceConnector) {
case EAST, WEST -> this.minX == 0 && this.maxX == 1;
case UP, DOWN -> this.minY == 0 && this.maxY == 1;
case NORTH, SOUTH -> this.minZ == 0 && this.maxZ == 1;
default -> false;
};
return false;
}
public boolean isFullBlockNoCache() {
@@ -20,25 +20,10 @@ package ac.grim.grimac.utils.data;
import java.util.Objects;
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public record Pair<A, B>(A first, B second) {
public static <T, K> Pair<T, K> of(T a, K b) {
return new Pair<T, K>(a, b);
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
return new Pair<>(a, b);
}
@Override
@@ -13,18 +13,13 @@ public enum EquipmentType {
HEAD;
public static EquipmentType byArmorID(int id) {
switch (id) {
case 0:
return HEAD;
case 1:
return CHEST;
case 2:
return LEGS;
case 3:
return FEET;
default:
return MAINHAND;
}
return switch (id) {
case 0 -> HEAD;
case 1 -> CHEST;
case 2 -> LEGS;
case 3 -> FEET;
default -> MAINHAND;
};
}
public static EquipmentType getEquipmentSlotForItem(ItemStack p_147234_) {
@@ -64,21 +59,11 @@ public enum EquipmentType {
}
public int getIndex() {
switch (this) {
case MAINHAND:
return 0;
case OFFHAND:
return 1;
case FEET:
return 0;
case LEGS:
return 1;
case CHEST:
return 2;
case HEAD:
return 3;
default:
return -1;
}
return switch (this) {
case MAINHAND, FEET -> 0;
case OFFHAND, LEGS -> 1;
case CHEST -> 2;
case HEAD -> 3;
};
}
}
@@ -58,38 +58,24 @@ public enum MenuType {
public static AbstractContainerMenu getMenuFromID(GrimPlayer player, Inventory playerInventory, MenuType type) {
switch (type) {
case GENERIC_9x1:
case GENERIC_9x2:
case GENERIC_9x3:
case GENERIC_9x4:
case GENERIC_9x5:
case GENERIC_9x6:
return new BasicInventoryMenu(player, playerInventory, type.getId() + 1);
case GENERIC_3x3:
return new DispenserMenu(player, playerInventory);
case HOPPER:
return new HopperMenu(player, playerInventory);
default:
return new NotImplementedMenu(player, playerInventory);
}
return switch (type) {
case GENERIC_9x1, GENERIC_9x2, GENERIC_9x3, GENERIC_9x4, GENERIC_9x5, GENERIC_9x6 ->
new BasicInventoryMenu(player, playerInventory, type.getId() + 1);
case GENERIC_3x3 -> new DispenserMenu(player, playerInventory);
case HOPPER -> new HopperMenu(player, playerInventory);
default -> new NotImplementedMenu(player, playerInventory);
};
}
public static AbstractContainerMenu getMenuFromString(GrimPlayer player, Inventory inventory, String legacyType, int slots, int horse) {
switch (legacyType) {
case "minecraft:chest":
case "minecraft:container":
return new BasicInventoryMenu(player, inventory, slots / 9);
case "minecraft:dispenser":
case "minecraft:dropper":
return new DispenserMenu(player, inventory);
case "minecraft:hopper":
return new HopperMenu(player, inventory);
case "minecraft:shulker_box":
return new BasicInventoryMenu(player, inventory, 3);
default: // Villager menu
return new NotImplementedMenu(player, inventory);
}
return switch (legacyType) {
case "minecraft:chest", "minecraft:container" -> new BasicInventoryMenu(player, inventory, slots / 9);
case "minecraft:dispenser", "minecraft:dropper" -> new DispenserMenu(player, inventory);
case "minecraft:hopper" -> new HopperMenu(player, inventory);
case "minecraft:shulker_box" -> new BasicInventoryMenu(player, inventory, 3);
default -> // Villager menu
new NotImplementedMenu(player, inventory);
};
}
}
@@ -72,8 +72,7 @@ public class CompensatedEntities {
PacketEntity entity = entityMap.remove(entityID);
if (entity == null) return;
if (entity instanceof PacketEntityEnderDragon) {
PacketEntityEnderDragon dragon = (PacketEntityEnderDragon) entity;
if (entity instanceof PacketEntityEnderDragon dragon) {
for (int i = 1; i < dragon.getParts().size() + 1; i++) {
entityMap.remove(entityID + i);
}
@@ -136,7 +135,7 @@ public class CompensatedEntities {
}
final Optional<ValuedAttribute> valuedAttribute = entity.getAttribute(attribute);
if (!valuedAttribute.isPresent()) {
if (valuedAttribute.isEmpty()) {
// Not an attribute we want to track
continue;
}
@@ -373,8 +372,7 @@ public class CompensatedEntities {
// track camel dashing
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20)) {
if (entity instanceof PacketEntityCamel) {
PacketEntityCamel camel = (PacketEntityCamel) entity;
if (entity instanceof PacketEntityCamel camel) {
EntityData entityData = WatchableIndexUtil.getIndex(watchableObjects, 18);
if (entityData != null) {
camel.dashing = (boolean) entityData.getValue();
@@ -166,25 +166,17 @@ public class CompensatedInventory extends Check implements PacketCheck {
}
private ItemStack getByEquipmentType(EquipmentType type) {
switch (type) {
case HEAD:
return getHelmet();
case CHEST:
return getChestplate();
case LEGS:
return getLeggings();
case FEET:
return getBoots();
case OFFHAND:
return getOffHand();
case MAINHAND:
return getHeldItem();
default:
return ItemStack.EMPTY;
}
return switch (type) {
case HEAD -> getHelmet();
case CHEST -> getChestplate();
case LEGS -> getLeggings();
case FEET -> getBoots();
case OFFHAND -> getOffHand();
case MAINHAND -> getHeldItem();
default -> ItemStack.EMPTY;
};
}
public boolean hasItemType(ItemType type) {
if (isPacketInventoryActive || player.bukkitPlayer == null) return inventory.hasItemType(type);
@@ -607,7 +607,7 @@ public class CompensatedWorld {
}
public boolean containsLiquid(SimpleCollisionBox var0) {
return Collisions.hasMaterial(player, var0, data -> Materials.isWater(player.getClientVersion(), data.getFirst()) || data.getFirst().getType() == StateTypes.LAVA);
return Collisions.hasMaterial(player, var0, data -> Materials.isWater(player.getClientVersion(), data.first()) || data.first().getType() == StateTypes.LAVA);
}
public double getLavaFluidLevelAt(int x, int y, int z) {
@@ -629,7 +629,7 @@ public class CompensatedWorld {
}
public boolean containsLava(SimpleCollisionBox var0) {
return Collisions.hasMaterial(player, var0, data -> data.getFirst().getType() == StateTypes.LAVA);
return Collisions.hasMaterial(player, var0, data -> data.first().getType() == StateTypes.LAVA);
}
public double getWaterFluidLevelAt(double x, double y, double z) {
@@ -43,17 +43,17 @@ public class LatencyUtils {
Pair<Integer, Runnable> pair = iterator.next();
// We are at most a tick ahead when running tasks based on transactions, meaning this is too far
if (transaction + 1 < pair.getFirst())
if (transaction + 1 < pair.first())
return;
// This is at most tick ahead of what we want
if (transaction == pair.getFirst() - 1)
if (transaction == pair.first() - 1)
continue;
try {
// Run the task
pair.getSecond().run();
pair.second().run();
} catch (Exception e) {
System.out.println("An error has occurred when running transactions for player: " + player.user.getName());
e.printStackTrace();
@@ -18,7 +18,7 @@ import java.util.concurrent.ConcurrentHashMap;
* Or copy (and debug) over around 5k lines of code to accomplish inventories
* Grim uses a hybrid system for inventories - we lag compensate but rely on the server
* for the ultimate source of truth, and resync if what we found is different from what the server sees
*
* <p>
* This also patches most desync's that happen with inventories on some versions like 1.8 or
* other desync's introduced by mojang or viabackwards
*
@@ -136,7 +136,7 @@ public class BlockBreakSpeed {
OptionalInt conduit = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.CONDUIT_POWER);
if (digSpeed.isPresent() || conduit.isPresent()) {
int hasteLevel = Math.max(!digSpeed.isPresent() ? 0 : digSpeed.getAsInt(), !conduit.isPresent() ? 0 : conduit.getAsInt());
int hasteLevel = Math.max(digSpeed.isEmpty() ? 0 : digSpeed.getAsInt(), !conduit.isPresent() ? 0 : conduit.getAsInt());
speedMultiplier *= (float) (1 + (0.2 * (hasteLevel + 1)));
}
@@ -29,13 +29,12 @@ public class BlockProperties {
return (float) (player.speed * 0.1f);
}
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityStrider) {
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityStrider strider) {
// Unsure which version the speed changed in
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20)) {
return (float) player.speed * 0.1f;
}
PacketEntityStrider strider = (PacketEntityStrider) player.compensatedEntities.getSelf().getRiding();
// Vanilla multiplies by 0.1 to calculate speed
return (float) strider.getAttributeValue(Attributes.GENERIC_MOVEMENT_SPEED) * (strider.isShaking ? 0.66F : 1.0F) * 0.1f;
}
@@ -129,9 +129,7 @@ public final class BoundingBoxSize {
double y = box.minY;
double z = (box.maxZ + box.minZ) / 2.0;
if (entity instanceof PacketEntityTrackXRot) {
PacketEntityTrackXRot xRotEntity = (PacketEntityTrackXRot) entity;
if (entity instanceof PacketEntityTrackXRot xRotEntity) {
// Horses desync here, and we can't do anything about it without interpolating animations.
// Mojang just has to fix it. I'm not attempting to fix it.
// Striders also do the same with animations, causing a desync.
@@ -21,7 +21,7 @@ public class MainSupportingBlockPosFinder {
SimpleCollisionBox slightlyBelowPlayer = new SimpleCollisionBox(maxPose.minX, maxPose.minY - 1.0E-6D, maxPose.minZ, maxPose.maxX, maxPose.minY, maxPose.maxZ);
Optional<Vector3i> supportingBlock = findSupportingBlock(player, slightlyBelowPlayer);
if (!supportingBlock.isPresent() && (!lastSupportingBlock.lastOnGroundAndNoBlock())) {
if (supportingBlock.isEmpty() && (!lastSupportingBlock.lastOnGroundAndNoBlock())) {
if (lastMovement != null) {
SimpleCollisionBox aabb2 = slightlyBelowPlayer.offset(-lastMovement.x, 0.0D, -lastMovement.z);
supportingBlock = findSupportingBlock(player, aabb2);