diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java index 526906bf6..80e346caf 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java @@ -46,6 +46,8 @@ import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacke import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.BlockItemPacketRewriter1_21_2; import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.ComponentRewriter1_21_2; import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.EntityPacketRewriter1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage; import com.viaversion.viaversion.rewriter.AttributeRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; @@ -159,6 +161,14 @@ public final class Protocol1_21To1_21_2 extends AbstractProtocol wrapper.user().get(BundleStateTracker.class).toggleBundling()); + registerServerbound(ServerboundPackets1_21_2.PONG, wrapper -> { + final int id = wrapper.passthrough(Types.INT); // id + if (wrapper.user().get(PlayerPositionStorage.class).checkPong(id)) { + wrapper.cancel(); + } + }); } private void clientInformation(final PacketWrapper wrapper) { @@ -215,6 +225,8 @@ public final class Protocol1_21To1_21_2 extends AbstractProtocol { @@ -151,6 +154,27 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter { @@ -236,12 +260,20 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter { - wrapper.passthrough(Types.DOUBLE); // X - wrapper.passthrough(Types.DOUBLE); // Y - wrapper.passthrough(Types.DOUBLE); // Z - wrapper.passthrough(Types.FLOAT); // Yaw - wrapper.passthrough(Types.FLOAT); // Pitch + final double x = wrapper.passthrough(Types.DOUBLE); // X + final double y = wrapper.passthrough(Types.DOUBLE); // Y + final double z = wrapper.passthrough(Types.DOUBLE); // Z + final float yaw = wrapper.passthrough(Types.FLOAT); // Yaw + final float pitch = wrapper.passthrough(Types.FLOAT); // Pitch readOnGround(wrapper); + + final PlayerPositionStorage playerPositionStorage = wrapper.user().get(PlayerPositionStorage.class); + if (playerPositionStorage.checkCaptureNextPlayerPositionPacket()) { + // Capture this packet and send it after accept teleportation + final boolean onGround = wrapper.get(Types.BOOLEAN, 0); + playerPositionStorage.setPlayerPosition(new PlayerPositionStorage.PlayerPosition(x, y, z, yaw, pitch, onGround)); + wrapper.cancel(); + } }); protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_ROT, wrapper -> { wrapper.passthrough(Types.FLOAT); // Yaw @@ -249,6 +281,15 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter { + final PlayerPositionStorage playerPositionStorage = wrapper.user().get(PlayerPositionStorage.class); + if (playerPositionStorage.hasPlayerPosition()) { + // Send move player after accept teleportation + wrapper.sendToServer(Protocol1_21To1_21_2.class); + wrapper.cancel(); + playerPositionStorage.sendMovePlayerPosRot(wrapper.user()); + } + }); } private RegistryDataRewriter registryDataRewriter() { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/BundleStateTracker.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/BundleStateTracker.java new file mode 100644 index 000000000..fd93aef9e --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/BundleStateTracker.java @@ -0,0 +1,34 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; + +public class BundleStateTracker implements StorableObject { + + private boolean bundling; + + public boolean isBundling() { + return this.bundling; + } + + public void toggleBundling() { + this.bundling = !this.bundling; + } + +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/PlayerPositionStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/PlayerPositionStorage.java new file mode 100644 index 000000000..d84b6081e --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/PlayerPositionStorage.java @@ -0,0 +1,83 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; + +public class PlayerPositionStorage implements StorableObject { + + private final IntSet pendingPongs = new IntOpenHashSet(); + private boolean captureNextPlayerPositionPacket; + private PlayerPosition playerPosition; + + public void addPendingPong(final int id) { + if (!this.pendingPongs.add(id)) { + throw new IllegalStateException("Pong already pending for id " + id); + } + } + + public boolean checkPong(final int id) { + if (this.pendingPongs.remove(id)) { + this.captureNextPlayerPositionPacket = true; + return true; + } else { + return false; + } + } + + public boolean checkCaptureNextPlayerPositionPacket() { + if (this.captureNextPlayerPositionPacket) { + this.captureNextPlayerPositionPacket = false; + return true; + } else { + return false; + } + } + + public void setPlayerPosition(final PlayerPosition playerPosition) { + this.playerPosition = playerPosition; + } + + public boolean hasPlayerPosition() { + return this.playerPosition != null; + } + + public void sendMovePlayerPosRot(final UserConnection user) { + final PacketWrapper movePlayerPosRot = PacketWrapper.create(ServerboundPackets1_20_5.MOVE_PLAYER_POS_ROT, user); + movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.x); // X + movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.y); // Y + movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.z); // Z + movePlayerPosRot.write(Types.FLOAT, this.playerPosition.yaw); // Yaw + movePlayerPosRot.write(Types.FLOAT, this.playerPosition.pitch); // Pitch + movePlayerPosRot.write(Types.BOOLEAN, this.playerPosition.onGround); // On Ground + movePlayerPosRot.sendToServer(Protocol1_21To1_21_2.class); + this.captureNextPlayerPositionPacket = false; + this.playerPosition = null; + } + + public record PlayerPosition(double x, double y, double z, float yaw, float pitch, boolean onGround) { + } + +}