From b5e1ddc3c86bd560e3ebbb8814c7d074c1bd6a69 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 3 Jan 2023 19:28:43 -0500 Subject: [PATCH] Guess when the client is clicking air on mobile Should address #2113 --- .../geyser/session/GeyserSession.java | 16 +++++-- .../bedrock/BedrockAnimateTranslator.java | 44 ++++++++++--------- .../BedrockLevelSoundEventTranslator.java | 20 +++++++++ 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index a95706307..9ca124393 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -455,7 +455,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * Counts how many ticks have occurred since an arm animation started. - * -1 means there is no active arm swing. + * -1 means there is no active arm swing; -2 means an arm swing will start in a tick. */ private int armAnimationTicks = -1; @@ -1157,7 +1157,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { entity.tick(); } - if (armAnimationTicks != -1) { + if (armAnimationTicks >= 0) { // As of 1.18.2 Java Edition, it appears that the swing time is dynamically updated depending on the // player's effect status, but the animation can cut short if the duration suddenly decreases // (from suddenly no longer having mining fatigue, for example) @@ -1196,7 +1196,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void startSneaking() { // Toggle the shield, if there is no ongoing arm animation // This matches Bedrock Edition behavior as of 1.18.12 - if (armAnimationTicks == -1) { + if (armAnimationTicks < 0) { attemptToBlock(); } @@ -1328,6 +1328,16 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } } + /** + * For https://github.com/GeyserMC/Geyser/issues/2113 and combating arm ticking activating being delayed in + * BedrockAnimateTranslator. + */ + public void armSwingPending() { + if (armAnimationTicks == -1) { + armAnimationTicks = -2; + } + } + /** * Indicates to the client to stop blocking and tells the Java server the same. */ 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 4905b5647..6122f573b 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 @@ -46,30 +46,32 @@ public class BedrockAnimateTranslator extends PacketTranslator { } switch (packet.getAction()) { - case SWING_ARM -> + 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.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); - session.activateArmAnimationTicking(); - } - }, - 25, - TimeUnit.MILLISECONDS + 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.sendDownstreamPacket(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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java index df8cd07c1..87c03479d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java @@ -25,7 +25,10 @@ package org.geysermc.geyser.translator.protocol.bedrock.world; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.packet.AnimatePacket; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -46,5 +49,22 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator