mirror of
https://github.com/jonesdevelopment/sonar.git
synced 2026-11-05 17:22:34 -05:00
Recode FallbackVehicleHandler
This commit is contained in:
1 file changed
+129
-78
+129
-78
@@ -19,6 +19,7 @@ package xyz.jonesdev.sonar.common.fallback.verification;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
@@ -40,8 +41,9 @@ public final class FallbackVehicleHandler extends FallbackVerificationHandler {
|
||||
private State state = State.WAITING;
|
||||
private State nextState;
|
||||
private int expectedKeepAliveId;
|
||||
private int rotations, inputs, paddles, vehicleMoves;
|
||||
private int checkedRound;
|
||||
private double boatMotion, boatY = IN_AIR_Y_POSITION;
|
||||
private @Nullable ExpectVehiclePacket expectVehiclePacket = null;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private enum State {
|
||||
@@ -54,6 +56,18 @@ public final class FallbackVehicleHandler extends FallbackVerificationHandler {
|
||||
private final boolean inVehicle;
|
||||
}
|
||||
|
||||
private enum ExpectVehiclePacket {
|
||||
PADDLE_BOAT,
|
||||
PLAYER_ROTATION,
|
||||
PLAYER_INPUT,
|
||||
VEHICLE_MOVE,
|
||||
CLIENT_TICK_END;
|
||||
|
||||
public @NotNull String formattedName() {
|
||||
return name().toLowerCase().replace('_', ' ');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(final @NotNull FallbackPacket packet) {
|
||||
if (packet instanceof KeepAlivePacket) {
|
||||
@@ -68,60 +82,25 @@ public final class FallbackVehicleHandler extends FallbackVerificationHandler {
|
||||
state = nextState;
|
||||
nextState = null;
|
||||
waitingForStateChange = false;
|
||||
} else if (!waitingForStateChange) {
|
||||
if (packet instanceof PaddleBoatPacket) {
|
||||
if (state == State.IN_BOAT) {
|
||||
paddles++;
|
||||
}
|
||||
} else if (packet instanceof VehicleMovePacket) {
|
||||
if (state == State.IN_BOAT) {
|
||||
final VehicleMovePacket vehicleMove = (VehicleMovePacket) packet;
|
||||
// Check the Y position of the vehicle
|
||||
checkState(vehicleMove.getY() <= IN_AIR_Y_POSITION, "bad vehicle y: " + vehicleMove.getY());
|
||||
|
||||
// Check the gravity of the vehicle
|
||||
final double lastBoatMotion = boatMotion;
|
||||
final double lastBoatY = boatY;
|
||||
boatY = vehicleMove.getY();
|
||||
boatMotion = boatY - lastBoatY;
|
||||
final double predicted = lastBoatMotion - 0.03999999910593033D;
|
||||
final double difference = Math.abs(boatMotion - predicted);
|
||||
// Check if the difference between the predicted and actual motion is too large
|
||||
checkState(difference < 1e-7, "bad vehicle gravity: " + predicted + "/" + boatMotion);
|
||||
|
||||
vehicleMoves++;
|
||||
}
|
||||
} else if (packet instanceof SetPlayerRotationPacket) {
|
||||
if (state.inVehicle) {
|
||||
rotations++;
|
||||
|
||||
// 1.21.2+ do not send PlayerInput packets when inside a vehicle.
|
||||
// Handle it after SetPlayerRotationPacket to simulate vanilla behavior.
|
||||
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
handlePlayerInput();
|
||||
}
|
||||
}
|
||||
} else if (packet instanceof PlayerInputPacket) {
|
||||
// 1.21.2+ send PlayerInput packets when the player starts sprinting, sneaking, etc.
|
||||
if (state.inVehicle && user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
final PlayerInputPacket playerInput = (PlayerInputPacket) packet;
|
||||
|
||||
// Check if the player is sending invalid vehicle speed values
|
||||
final float forward = Math.abs(playerInput.getForward());
|
||||
final float sideways = Math.abs(playerInput.getSideways());
|
||||
final float maxVehicleSpeed = /*user.isGeyser() ? 1 :*/ 0.98f;
|
||||
checkState(forward <= maxVehicleSpeed, "illegal speed (f): " + forward);
|
||||
checkState(sideways <= maxVehicleSpeed, "illegal speed (s): " + sideways);
|
||||
|
||||
handlePlayerInput();
|
||||
}
|
||||
} else if (packet instanceof SetPlayerPositionRotationPacket) {
|
||||
final SetPlayerPositionRotationPacket posRot = (SetPlayerPositionRotationPacket) packet;
|
||||
handleMovement(posRot.getY(), posRot.isOnGround());
|
||||
} else if (packet instanceof SetPlayerPositionPacket) {
|
||||
final SetPlayerPositionPacket position = (SetPlayerPositionPacket) packet;
|
||||
handleMovement(position.getY(), position.isOnGround());
|
||||
if (!state.inVehicle) {
|
||||
expectVehiclePacket = null;
|
||||
}
|
||||
} else if (packet instanceof PaddleBoatPacket) {
|
||||
onPaddleBoat((PaddleBoatPacket) packet);
|
||||
} else if (packet instanceof VehicleMovePacket) {
|
||||
onVehicleMove((VehicleMovePacket) packet);
|
||||
} else if (packet instanceof SetPlayerRotationPacket) {
|
||||
onPlayerRotation((SetPlayerRotationPacket) packet);
|
||||
} else if (packet instanceof PlayerInputPacket) {
|
||||
onPlayerInput((PlayerInputPacket) packet);
|
||||
} else if (packet instanceof ClientTickEndPacket) {
|
||||
onClientTickEnd((ClientTickEndPacket) packet);
|
||||
} else if (packet instanceof SetPlayerPositionRotationPacket) {
|
||||
final SetPlayerPositionRotationPacket posRot = (SetPlayerPositionRotationPacket) packet;
|
||||
handleMovement(posRot.getY(), posRot.isOnGround());
|
||||
} else if (packet instanceof SetPlayerPositionPacket) {
|
||||
final SetPlayerPositionPacket position = (SetPlayerPositionPacket) packet;
|
||||
handleMovement(position.getY(), position.isOnGround());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,13 +108,14 @@ public final class FallbackVehicleHandler extends FallbackVerificationHandler {
|
||||
user.delayedWrite(nextState == State.IN_BOAT ? SPAWN_BOAT_ENTITY : SPAWN_MINECART_ENTITY);
|
||||
user.delayedWrite(SET_VEHICLE_PASSENGERS);
|
||||
prepareForNextState(nextState);
|
||||
expectVehiclePacket = isClientMovingVehicle() ? ExpectVehiclePacket.PADDLE_BOAT : ExpectVehiclePacket.PLAYER_ROTATION;
|
||||
}
|
||||
|
||||
private void prepareForNextState(final @NotNull State nextState) {
|
||||
this.nextState = nextState;
|
||||
waitingForStateChange = true;
|
||||
expectedKeepAliveId = RANDOM.nextInt();
|
||||
rotations = inputs = paddles = vehicleMoves = 0;
|
||||
checkedRound = 0;
|
||||
user.delayedWrite(new KeepAlivePacket(expectedKeepAliveId));
|
||||
user.channel().flush();
|
||||
}
|
||||
@@ -151,9 +131,12 @@ public final class FallbackVehicleHandler extends FallbackVerificationHandler {
|
||||
|
||||
private void handleMovement(final double y, final boolean isOnGround) {
|
||||
// Make sure we're currently expecting movement
|
||||
if (state.inVehicle || state == State.WAITING) {
|
||||
if (state == State.WAITING) {
|
||||
return;
|
||||
}
|
||||
checkState(!state.inVehicle && !waitingForStateChange,
|
||||
"sending move packet while in vehicle");
|
||||
expectVehiclePacket = null;
|
||||
|
||||
// Make sure the ground state and y position are correct
|
||||
checkState(y <= boatY, "invalid y: " + y);
|
||||
@@ -166,31 +149,99 @@ public final class FallbackVehicleHandler extends FallbackVerificationHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePlayerInput() {
|
||||
// 1.8 and below do not have PaddleBoat packets, so we simply exempt them from the PaddleBoat check.
|
||||
// Clients also don't send PaddleBoat & VehicleMovePacket packets while riding minecarts.
|
||||
if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_9) || state == State.IN_MINECART) {
|
||||
paddles++;
|
||||
vehicleMoves++;
|
||||
}
|
||||
private void onPaddleBoat(final @NotNull PaddleBoatPacket packet) {
|
||||
checkState(isClientMovingVehicle(), "received unexpected paddle boat");
|
||||
checkPacketOrder(ExpectVehiclePacket.PADDLE_BOAT);
|
||||
expectVehiclePacket = ExpectVehiclePacket.PLAYER_ROTATION;
|
||||
}
|
||||
|
||||
// Check for packet order
|
||||
checkState(rotations >= inputs,
|
||||
"illegal packet order; i/r " + inputs + "/" + rotations);
|
||||
checkState(paddles >= inputs,
|
||||
"illegal packet order; i/p " + inputs + "/" + paddles);
|
||||
checkState(vehicleMoves >= inputs,
|
||||
"illegal packet order; i/v " + inputs + "/" + vehicleMoves);
|
||||
private void onPlayerRotation(final @NotNull SetPlayerRotationPacket packet) {
|
||||
checkPacketOrder(ExpectVehiclePacket.PLAYER_ROTATION);
|
||||
|
||||
inputs++;
|
||||
// Check yaw/pitch?
|
||||
|
||||
// Check if we've received more than the minimum number of packets
|
||||
final int minimumPackets = Sonar.get0().getConfig().getVerification().getVehicle().getMinimumPackets();
|
||||
if (inputs > minimumPackets && rotations > minimumPackets
|
||||
&& paddles > minimumPackets && vehicleMoves > minimumPackets) {
|
||||
// Move on to the next stage
|
||||
user.delayedWrite(REMOVE_VEHICLE);
|
||||
prepareForNextState(state == State.IN_BOAT ? State.IN_AIR_AFTER_BOAT : State.IN_AIR_AFTER_MINECART);
|
||||
if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
expectVehiclePacket = ExpectVehiclePacket.PLAYER_INPUT;
|
||||
} else if (isClientMovingVehicle()) {
|
||||
expectVehiclePacket = ExpectVehiclePacket.VEHICLE_MOVE;
|
||||
} else {
|
||||
expectVehiclePacket = ExpectVehiclePacket.CLIENT_TICK_END;
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlayerInput(final @NotNull PlayerInputPacket packet) {
|
||||
// 1.21.2+ send PlayerInput packets when the player starts sprinting, sneaking, etc.
|
||||
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
return;
|
||||
}
|
||||
checkPacketOrder(ExpectVehiclePacket.PLAYER_INPUT);
|
||||
|
||||
// Check if the player is sending invalid vehicle speed values
|
||||
final float forward = Math.abs(packet.getForward());
|
||||
final float sideways = Math.abs(packet.getSideways());
|
||||
final float maxVehicleSpeed = /*user.isGeyser() ? 1 :*/ 0.98f;
|
||||
checkState(forward <= maxVehicleSpeed, "illegal speed (f): " + forward);
|
||||
checkState(sideways <= maxVehicleSpeed, "illegal speed (s): " + sideways);
|
||||
|
||||
if (isClientMovingVehicle()) {
|
||||
expectVehiclePacket = ExpectVehiclePacket.VEHICLE_MOVE;
|
||||
} else {
|
||||
finishRound();
|
||||
}
|
||||
}
|
||||
|
||||
private void onVehicleMove(final @NotNull VehicleMovePacket packet) {
|
||||
checkState(isClientMovingVehicle(), "received unexpected vehicle move");
|
||||
checkPacketOrder(ExpectVehiclePacket.VEHICLE_MOVE);
|
||||
|
||||
// Check the Y position of the vehicle
|
||||
checkState(packet.getY() <= IN_AIR_Y_POSITION, "bad vehicle y: " + packet.getY());
|
||||
|
||||
// Check the gravity of the vehicle
|
||||
final double lastBoatMotion = boatMotion;
|
||||
final double lastBoatY = boatY;
|
||||
boatY = packet.getY();
|
||||
boatMotion = boatY - lastBoatY;
|
||||
final double predicted = lastBoatMotion - 0.03999999910593033D;
|
||||
final double difference = Math.abs(boatMotion - predicted);
|
||||
// Check if the difference between the predicted and actual motion is too large
|
||||
checkState(difference < 1e-7, "bad vehicle gravity: " + predicted + "/" + boatMotion);
|
||||
|
||||
if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
this.finishRound();
|
||||
} else {
|
||||
expectVehiclePacket = ExpectVehiclePacket.CLIENT_TICK_END;
|
||||
}
|
||||
}
|
||||
|
||||
private void onClientTickEnd(final @NotNull ClientTickEndPacket packet) {
|
||||
if (expectVehiclePacket == ExpectVehiclePacket.CLIENT_TICK_END) {
|
||||
finishRound();
|
||||
} else if (!waitingForStateChange && state.inVehicle) { // Client can send end tick while not in vehicle
|
||||
checkPacketOrder(ExpectVehiclePacket.CLIENT_TICK_END); // fail
|
||||
}
|
||||
}
|
||||
|
||||
private void finishRound() {
|
||||
final int minimumPackets = Sonar.get0().getConfig().getVerification().getVehicle().getMinimumPackets();
|
||||
if (++checkedRound > minimumPackets) {
|
||||
// Move on to the next stage
|
||||
expectVehiclePacket = null;
|
||||
user.delayedWrite(REMOVE_VEHICLE);
|
||||
prepareForNextState(state == State.IN_BOAT ? State.IN_AIR_AFTER_BOAT : State.IN_AIR_AFTER_MINECART);
|
||||
} else {
|
||||
expectVehiclePacket = isClientMovingVehicle() ? ExpectVehiclePacket.PADDLE_BOAT : ExpectVehiclePacket.PLAYER_ROTATION;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isClientMovingVehicle() {
|
||||
return (waitingForStateChange && nextState.inVehicle ? nextState : state) == State.IN_BOAT
|
||||
&& user.getProtocolVersion().greaterThan(ProtocolVersion.MINECRAFT_1_8);
|
||||
}
|
||||
|
||||
private void checkPacketOrder(final @NotNull ExpectVehiclePacket current) {
|
||||
checkState(expectVehiclePacket == current, expectVehiclePacket == null
|
||||
? "sending vehicle packet while not in vehicle (" + current.formattedName() + ")"
|
||||
: "expected " + expectVehiclePacket.formattedName() + " but got " + current.formattedName());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user