From 9d2d12b87bb84528968f01546388b7f56113e803 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 26 Oct 2024 01:41:23 -0400 Subject: [PATCH] Re-implement steering indicators --- .../geyser/entity/type/BoatEntity.java | 7 + .../bedrock/BedrockAnimateTranslator.java | 70 ++++---- .../BedrockPlayerAuthInputTranslator.java | 149 +++++++++--------- 3 files changed, 111 insertions(+), 115 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java index 9312d83f5..86accea17 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java @@ -39,6 +39,7 @@ import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket; import java.util.UUID; @@ -182,6 +183,12 @@ public class BoatEntity extends Entity implements Leashable, Tickable { @Override public void tick() { // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing + if (session.getPlayerEntity().getVehicle() == this) { + // For packet timing accuracy, we'll send the packets here, as that's what Java Edition 1.21.3 does. + ServerboundPaddleBoatPacket steerPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); + session.sendDownstreamGamePacket(steerPacket); + return; + } doTick = !doTick; // Run every 100 ms if (!doTick || passengers.isEmpty()) { return; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java index 79e013246..487c3ef75 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java @@ -25,13 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import java.util.concurrent.TimeUnit; @@ -45,45 +44,32 @@ public class BedrockAnimateTranslator extends PacketTranslator { return; } - switch (packet.getAction()) { - case SWING_ARM -> { - session.armSwingPending(); - // Delay so entity damage can be processed first - session.scheduleInEventLoop(() -> { - if (session.getArmAnimationTicks() != 0) { - // So, generally, a Java player can only do one *thing* at a time. - // If a player right-clicks, for example, then there's probably only one action associated with - // that right-click that will send a swing. - // The only exception I can think of to this, *maybe*, is a player dropping items - // Bedrock is a little funkier than this - it can send several arm animation packets in the - // same tick, notably with high levels of haste applied. - // Packet limiters do not like this and can crash the player. - // If arm animation ticks is 0, then we just sent an arm swing packet this tick. - // See https://github.com/GeyserMC/Geyser/issues/2875 - // This behavior was last touched on with ViaVersion 4.5.1 (with its packet limiter), Java 1.16.5, - // and Bedrock 1.19.51. - // Note for the future: we should probably largely ignore this packet and instead replicate - // all actions on our end, and send swings where needed. - session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); - session.activateArmAnimationTicking(); - } - }, - 25, - TimeUnit.MILLISECONDS - ); - } - // These two might need to be flipped, but my recommendation is getting moving working first - case ROW_LEFT -> { - // Packet value is a float of how long one has been rowing, so we convert that into a boolean - session.setSteeringLeft(packet.getRowingTime() > 0.0); - ServerboundPaddleBoatPacket steerLeftPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); - session.sendDownstreamGamePacket(steerLeftPacket); - } - case ROW_RIGHT -> { - session.setSteeringRight(packet.getRowingTime() > 0.0); - ServerboundPaddleBoatPacket steerRightPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); - session.sendDownstreamGamePacket(steerRightPacket); - } + System.out.println("wewewewewewewewewewewe"); + if (packet.getAction() == AnimatePacket.Action.SWING_ARM) { + session.armSwingPending(); + // Delay so entity damage can be processed first + session.scheduleInEventLoop(() -> { + if (session.getArmAnimationTicks() != 0) { + // So, generally, a Java player can only do one *thing* at a time. + // If a player right-clicks, for example, then there's probably only one action associated with + // that right-click that will send a swing. + // The only exception I can think of to this, *maybe*, is a player dropping items + // Bedrock is a little funkier than this - it can send several arm animation packets in the + // same tick, notably with high levels of haste applied. + // Packet limiters do not like this and can crash the player. + // If arm animation ticks is 0, then we just sent an arm swing packet this tick. + // See https://github.com/GeyserMC/Geyser/issues/2875 + // This behavior was last touched on with ViaVersion 4.5.1 (with its packet limiter), Java 1.16.5, + // and Bedrock 1.19.51. + // Note for the future: we should probably largely ignore this packet and instead replicate + // all actions on our end, and send swings where needed. + session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.activateArmAnimationTicking(); + } + }, + 25, + TimeUnit.MILLISECONDS + ); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index 0889579c2..a0c874743 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -78,83 +78,86 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator inputData = packet.getInputData(); - if (!inputData.isEmpty()) { - for (PlayerAuthInputData input : inputData) { - switch (input) { - case PERFORM_ITEM_INTERACTION -> processItemUseTransaction(session, packet.getItemUseTransaction()); - case PERFORM_BLOCK_ACTIONS -> BedrockBlockActions.translate(session, packet.getPlayerActions()); - case START_SNEAKING -> { - ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); - session.sendDownstreamGamePacket(startSneakPacket); + for (PlayerAuthInputData input : inputData) { + switch (input) { + case PERFORM_ITEM_INTERACTION -> processItemUseTransaction(session, packet.getItemUseTransaction()); + case PERFORM_BLOCK_ACTIONS -> BedrockBlockActions.translate(session, packet.getPlayerActions()); + case START_SNEAKING -> { + ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); + session.sendDownstreamGamePacket(startSneakPacket); - session.startSneaking(); - } - case STOP_SNEAKING -> { - ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING); - session.sendDownstreamGamePacket(stopSneakPacket); - - session.stopSneaking(); - } - case START_SPRINTING -> { - if (!entity.getFlag(EntityFlag.SWIMMING)) { - ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); - session.sendDownstreamGamePacket(startSprintPacket); - session.setSprinting(true); - } - } - case STOP_SPRINTING -> { - if (!entity.getFlag(EntityFlag.SWIMMING)) { - ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); - session.sendDownstreamGamePacket(stopSprintPacket); - } - session.setSprinting(false); - } - case START_SWIMMING -> session.setSwimming(true); - case STOP_SWIMMING -> session.setSwimming(false); - case START_FLYING -> { // Since 1.20.30 - if (session.isCanFly()) { - if (session.getGameMode() == GameMode.SPECTATOR) { - // should already be flying - session.sendAdventureSettings(); - break; - } - - if (session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) { - // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling - // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE - session.sendAdventureSettings(); - break; - } - - session.setFlying(true); - session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(true)); - } else { - // update whether we can fly - session.sendAdventureSettings(); - // stop flying - PlayerActionPacket stopFlyingPacket = new PlayerActionPacket(); - stopFlyingPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); - stopFlyingPacket.setAction(PlayerActionType.STOP_FLYING); - stopFlyingPacket.setBlockPosition(Vector3i.ZERO); - stopFlyingPacket.setResultPosition(Vector3i.ZERO); - stopFlyingPacket.setFace(0); - session.sendUpstreamPacket(stopFlyingPacket); - } - } - case STOP_FLYING -> { - session.setFlying(false); - session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false)); - } - case START_GLIDING -> { - // Otherwise gliding will not work in creative - ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false); - session.sendDownstreamGamePacket(playerAbilitiesPacket); - sendPlayerGlideToggle(session, entity); - } - case STOP_GLIDING -> sendPlayerGlideToggle(session, entity); + session.startSneaking(); } + case STOP_SNEAKING -> { + ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING); + session.sendDownstreamGamePacket(stopSneakPacket); + + session.stopSneaking(); + } + case START_SPRINTING -> { + if (!entity.getFlag(EntityFlag.SWIMMING)) { + ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); + session.sendDownstreamGamePacket(startSprintPacket); + session.setSprinting(true); + } + } + case STOP_SPRINTING -> { + if (!entity.getFlag(EntityFlag.SWIMMING)) { + ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); + session.sendDownstreamGamePacket(stopSprintPacket); + } + session.setSprinting(false); + } + case START_SWIMMING -> session.setSwimming(true); + case STOP_SWIMMING -> session.setSwimming(false); + case START_FLYING -> { // Since 1.20.30 + if (session.isCanFly()) { + if (session.getGameMode() == GameMode.SPECTATOR) { + // should already be flying + session.sendAdventureSettings(); + break; + } + + if (session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) { + // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling + // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE + session.sendAdventureSettings(); + break; + } + + session.setFlying(true); + session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(true)); + } else { + // update whether we can fly + session.sendAdventureSettings(); + // stop flying + PlayerActionPacket stopFlyingPacket = new PlayerActionPacket(); + stopFlyingPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); + stopFlyingPacket.setAction(PlayerActionType.STOP_FLYING); + stopFlyingPacket.setBlockPosition(Vector3i.ZERO); + stopFlyingPacket.setResultPosition(Vector3i.ZERO); + stopFlyingPacket.setFace(0); + session.sendUpstreamPacket(stopFlyingPacket); + } + } + case STOP_FLYING -> { + session.setFlying(false); + session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false)); + } + case START_GLIDING -> { + // Otherwise gliding will not work in creative + ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false); + session.sendDownstreamGamePacket(playerAbilitiesPacket); + sendPlayerGlideToggle(session, entity); + } + case STOP_GLIDING -> sendPlayerGlideToggle(session, entity); } } + boolean up = inputData.contains(PlayerAuthInputData.UP); + // Yes. These are flipped. It's always been an issue with Geyser. That's what it's like working with this codebase. + // Hi random stranger. I am six days into updating for 1.21.3. How's it going? + session.setSteeringLeft(up || inputData.contains(PlayerAuthInputData.PADDLE_RIGHT)); + session.setSteeringRight(up || inputData.contains(PlayerAuthInputData.PADDLE_LEFT)); } private static void sendPlayerGlideToggle(GeyserSession session, Entity entity) {