|
25 | 25 |
|
26 | 26 | package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
|
27 | 27 |
|
| 28 | +import org.cloudburstmc.math.vector.Vector2f; |
28 | 29 | import org.cloudburstmc.math.vector.Vector3f;
|
29 | 30 | import org.cloudburstmc.math.vector.Vector3i;
|
30 | 31 | import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
|
36 | 37 | import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket;
|
37 | 38 | import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
38 | 39 | import org.geysermc.geyser.entity.EntityDefinitions;
|
| 40 | +import org.geysermc.geyser.entity.type.BoatEntity; |
39 | 41 | import org.geysermc.geyser.entity.type.Entity;
|
40 | 42 | import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
| 43 | +import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; |
| 44 | +import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity; |
41 | 45 | import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
| 46 | +import org.geysermc.geyser.entity.vehicle.ClientVehicle; |
42 | 47 | import org.geysermc.geyser.level.block.type.Block;
|
43 | 48 | import org.geysermc.geyser.session.GeyserSession;
|
44 | 49 | import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
45 | 50 | import org.geysermc.geyser.translator.protocol.Translator;
|
46 | 51 | import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator;
|
| 52 | +import org.geysermc.geyser.util.MathUtils; |
47 | 53 | import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
48 | 54 | import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
49 | 55 | import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction;
|
50 | 56 | import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
|
51 | 57 | import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState;
|
| 58 | +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket; |
52 | 59 | import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
|
53 | 60 | import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
54 | 61 | import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
|
57 | 64 | import java.util.Set;
|
58 | 65 |
|
59 | 66 | @Translator(packet = PlayerAuthInputPacket.class)
|
60 |
| -public class BedrockPlayerAuthInputTranslator extends PacketTranslator<PlayerAuthInputPacket> { |
| 67 | +public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<PlayerAuthInputPacket> { |
61 | 68 |
|
62 | 69 | @Override
|
63 | 70 | public void translate(GeyserSession session, PlayerAuthInputPacket packet) {
|
64 | 71 | SessionPlayerEntity entity = session.getPlayerEntity();
|
| 72 | + |
| 73 | + boolean wasJumping = session.getInputCache().wasJumping(); |
65 | 74 | session.getInputCache().processInputs(packet);
|
66 | 75 |
|
| 76 | + processVehicleInput(session, packet, wasJumping); |
| 77 | + |
67 | 78 | BedrockMovePlayerTranslator.translate(session, packet);
|
68 | 79 |
|
69 | 80 | Set<PlayerAuthInputData> inputData = packet.getInputData();
|
@@ -202,4 +213,94 @@ private static void processItemUseTransaction(GeyserSession session, ItemUseTran
|
202 | 213 | session.getGeyser().getLogger().error("Unhandled item use transaction type!");
|
203 | 214 | }
|
204 | 215 | }
|
| 216 | + |
| 217 | + private static void processVehicleInput(GeyserSession session, PlayerAuthInputPacket packet, boolean wasJumping) { |
| 218 | + Entity vehicle = session.getPlayerEntity().getVehicle(); |
| 219 | + if (vehicle == null) { |
| 220 | + return; |
| 221 | + } |
| 222 | + if (vehicle instanceof ClientVehicle) { |
| 223 | + session.getPlayerEntity().setVehicleInput(packet.getAnalogMoveVector()); |
| 224 | + } |
| 225 | + |
| 226 | + boolean sendMovement = false; |
| 227 | + if (vehicle instanceof AbstractHorseEntity && !(vehicle instanceof LlamaEntity)) { |
| 228 | + sendMovement = vehicle.isOnGround(); |
| 229 | + } else if (vehicle instanceof BoatEntity) { |
| 230 | + if (vehicle.getPassengers().size() == 1) { |
| 231 | + // The player is the only rider |
| 232 | + sendMovement = true; |
| 233 | + } else { |
| 234 | + // Check if the player is the front rider |
| 235 | + if (session.getPlayerEntity().isRidingInFront()) { |
| 236 | + sendMovement = true; |
| 237 | + } |
| 238 | + } |
| 239 | + } |
| 240 | + |
| 241 | + if (vehicle instanceof AbstractHorseEntity) { |
| 242 | + // Behavior verified as of Java Edition 1.21.3 |
| 243 | + int currentJumpingTicks = session.getInputCache().getJumpingTicks(); |
| 244 | + if (currentJumpingTicks < 0) { |
| 245 | + session.getInputCache().setJumpingTicks(++currentJumpingTicks); |
| 246 | + if (currentJumpingTicks == 0) { |
| 247 | + session.getPlayerEntity().setVehicleJumpStrength(0); |
| 248 | + } |
| 249 | + } |
| 250 | + |
| 251 | + boolean holdingJump = packet.getInputData().contains(PlayerAuthInputData.JUMPING); |
| 252 | + if (wasJumping && !holdingJump) { |
| 253 | + // Jump released |
| 254 | + // Yes, I'm fairly certain that entity ID is correct. |
| 255 | + session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), |
| 256 | + PlayerState.START_HORSE_JUMP, MathUtils.floor(session.getInputCache().getJumpScale() * 100f))); |
| 257 | + session.getInputCache().setJumpingTicks(-10); |
| 258 | + } else if (!wasJumping && holdingJump) { |
| 259 | + session.getInputCache().setJumpingTicks(0); |
| 260 | + session.getInputCache().setJumpScale(0); |
| 261 | + } else if (holdingJump) { |
| 262 | + session.getInputCache().setJumpingTicks(++currentJumpingTicks); |
| 263 | + if (currentJumpingTicks < 10) { |
| 264 | + session.getInputCache().setJumpScale(session.getInputCache().getJumpScale() * 0.1F); |
| 265 | + } else { |
| 266 | + session.getInputCache().setJumpScale(0.8f + 2.0f / (currentJumpingTicks - 9) * 0.1f); |
| 267 | + } |
| 268 | + } |
| 269 | + } else { |
| 270 | + session.getInputCache().setJumpScale(0); |
| 271 | + } |
| 272 | + |
| 273 | + if (sendMovement) { |
| 274 | + Vector3f vehiclePosition = packet.getPosition(); |
| 275 | + Vector2f vehicleRotation = packet.getVehicleRotation(); |
| 276 | + if (vehicleRotation == null) { |
| 277 | + return; // If the client just got in or out of a vehicle for example. |
| 278 | + } |
| 279 | + |
| 280 | + if (session.getWorldBorder().isPassingIntoBorderBoundaries(vehiclePosition, false)) { |
| 281 | + Vector3f position = vehicle.getPosition(); |
| 282 | + if (vehicle instanceof BoatEntity boat) { |
| 283 | + // Undo the changes usually applied to the boat |
| 284 | + boat.moveAbsoluteWithoutAdjustments(position, vehicle.getYaw(), vehicle.isOnGround(), true); |
| 285 | + } else { |
| 286 | + // This doesn't work if teleported is false |
| 287 | + vehicle.moveAbsolute(position, |
| 288 | + vehicle.getYaw(), vehicle.getPitch(), vehicle.getHeadYaw(), |
| 289 | + vehicle.isOnGround(), true); |
| 290 | + } |
| 291 | + return; |
| 292 | + } |
| 293 | + |
| 294 | + if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) { |
| 295 | + // Remove some Y position to prevents boats flying up |
| 296 | + vehiclePosition = vehiclePosition.down(vehicle.getDefinition().offset()); |
| 297 | + } |
| 298 | + |
| 299 | + ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket( |
| 300 | + vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(), |
| 301 | + vehicleRotation.getY() - 90, vehiclePosition.getX() // TODO I wonder if this is related to the horse spinning bugs... |
| 302 | + ); |
| 303 | + session.sendDownstreamGamePacket(moveVehiclePacket); |
| 304 | + } |
| 305 | + } |
205 | 306 | }
|
0 commit comments