From 7d5c4a38f807c864c2784492b3aba0a7c79ef999 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Jul 2024 23:22:04 -0400 Subject: [PATCH] Respect block range attribute where we can #4864 --- .../entity/attribute/GeyserAttributeType.java | 1 + .../type/player/SessionPlayerEntity.java | 8 ++ ...BedrockInventoryTransactionTranslator.java | 81 +++++++++---------- 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index a4a0df8b898..3b543a943fc 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -50,6 +50,7 @@ public enum GeyserAttributeType { ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f), MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), + BLOCK_INTERACTION_RANGE("minecraft:player.block_interaction_range", null, 0.0f, 64f, 4.5f), // Bedrock Attributes ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f), diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index 45fea4d48f8..dc0545cee4c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -64,6 +64,11 @@ public class SessionPlayerEntity extends PlayerEntity { */ @Getter protected final Map attributes = new Object2ObjectOpenHashMap<>(); + /** + * Java-only attribute + */ + @Getter + private double blockInteractionRange = GeyserAttributeType.BLOCK_INTERACTION_RANGE.getDefaultValue(); /** * Used in PlayerInputTranslator for movement checks. */ @@ -232,6 +237,8 @@ protected boolean hasShield(boolean offhand) { protected void updateAttribute(Attribute javaAttribute, List newAttributes) { if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) { session.setAttackSpeed(AttributeUtils.calculateValue(javaAttribute)); + } else if (javaAttribute.getType() == AttributeType.Builtin.PLAYER_BLOCK_INTERACTION_RANGE) { + this.blockInteractionRange = AttributeUtils.calculateValue(javaAttribute); } else { super.updateAttribute(javaAttribute, newAttributes); } @@ -295,6 +302,7 @@ public void resetMetadata() { public void resetAttributes() { attributes.clear(); maxHealth = GeyserAttributeType.MAX_HEALTH.getDefaultValue(); + blockInteractionRange = GeyserAttributeType.BLOCK_INTERACTION_RANGE.getDefaultValue(); UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); attributesPacket.setRuntimeEntityId(geyserId); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 534a89e23f1..9d78d174bc2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -70,7 +70,11 @@ import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.util.*; +import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.geyser.util.CooldownUtils; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -78,7 +82,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; import java.util.List; import java.util.concurrent.TimeUnit; @@ -90,11 +98,6 @@ @Translator(packet = InventoryTransactionPacket.class) public class BedrockInventoryTransactionTranslator extends PacketTranslator { - private static final float MAXIMUM_BLOCK_PLACING_DISTANCE = 64f; - private static final int CREATIVE_EYE_HEIGHT_PLACE_DISTANCE = 49; - private static final int SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE = 36; - private static final float MAXIMUM_BLOCK_DESTROYING_DISTANCE = 36f; - @Override public void translate(GeyserSession session, InventoryTransactionPacket packet) { if (packet.getTransactionType() == InventoryTransactionType.NORMAL && packet.getActions().size() == 3) { @@ -243,17 +246,13 @@ public void translate(GeyserSession session, InventoryTransactionPacket packet) return; } - // CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch + // As of 1.21, Paper does not have any additional range checks that would inconvenience normal players. + // Note that, before these changes, I could replicate on Paper 1.20.4 and iPad 1.21.2 an instance of block ghosting + // that we had not previously implemented. Might be some sort of ray tracing that is currently unimplemented. Vector3f playerPosition = session.getPlayerEntity().getPosition(); playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight()); - boolean creative = session.getGameMode() == GameMode.CREATIVE; - - float diffX = playerPosition.getX() - packetBlockPosition.getX(); - float diffY = playerPosition.getY() - packetBlockPosition.getY(); - float diffZ = playerPosition.getZ() - packetBlockPosition.getZ(); - if (((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) > - (creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { + if (!canInteractWithBlock(session, playerPosition, packetBlockPosition)) { restoreCorrectBlock(session, blockPos, packet); return; } @@ -262,26 +261,8 @@ public void translate(GeyserSession session, InventoryTransactionPacket packet) double clickPositionFullY = (double) packetBlockPosition.getY() + (double) packet.getClickPosition().getY(); double clickPositionFullZ = (double) packetBlockPosition.getZ() + (double) packet.getClickPosition().getZ(); - // More recent Paper check - https://github.com/PaperMC/Paper/blob/87e11bf7fdf48ecdf3e1cae383c368b9b61d7df9/patches/server/0470-Move-range-check-for-block-placing-up.patch - double clickDiffX = playerPosition.getX() - clickPositionFullX; - double clickDiffY = playerPosition.getY() - clickPositionFullY; - double clickDiffZ = playerPosition.getZ() - clickPositionFullZ; - if (((clickDiffX * clickDiffX) + (clickDiffY * clickDiffY) + (clickDiffZ * clickDiffZ)) > - (creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { - restoreCorrectBlock(session, blockPos, packet); - return; - } - Vector3f blockCenter = Vector3f.from(packetBlockPosition.getX() + 0.5f, packetBlockPosition.getY() + 0.5f, packetBlockPosition.getZ() + 0.5f); - // Vanilla check - if (!(session.getPlayerEntity().getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0) - .distanceSquared(blockCenter) < MAXIMUM_BLOCK_PLACING_DISTANCE)) { - // The client thinks that its blocks have been successfully placed. Restore the server's blocks instead. - restoreCorrectBlock(session, blockPos, packet); - return; - } - // More recent vanilla check (as of 1.18.2) double clickDistanceX = clickPositionFullX - blockCenter.getX(); double clickDistanceY = clickPositionFullY - blockCenter.getY(); double clickDistanceZ = clickPositionFullZ - blockCenter.getZ(); @@ -433,14 +414,10 @@ public void translate(GeyserSession session, InventoryTransactionPacket packet) return; } - // This is working out the distance using 3d Pythagoras and the extra value added to the Y is the sneaking height of a java player. Vector3f playerPosition = session.getPlayerEntity().getPosition(); - Vector3f floatBlockPosition = packet.getBlockPosition().toFloat(); - float diffX = playerPosition.getX() - (floatBlockPosition.getX() + 0.5f); - float diffY = (playerPosition.getY() - EntityDefinitions.PLAYER.offset()) - (floatBlockPosition.getY() + 0.5f) + 1.5f; - float diffZ = playerPosition.getZ() - (floatBlockPosition.getZ() + 0.5f); - float distanceSquared = diffX * diffX + diffY * diffY + diffZ * diffZ; - if (distanceSquared > MAXIMUM_BLOCK_DESTROYING_DISTANCE) { + playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight()); + + if (!canInteractWithBlock(session, playerPosition, packet.getBlockPosition())) { restoreCorrectBlock(session, packet.getBlockPosition(), packet); return; } @@ -550,6 +527,28 @@ private void processEntityInteraction(GeyserSession session, InventoryTransactio } } + private boolean canInteractWithBlock(GeyserSession session, Vector3f playerPosition, Vector3i packetBlockPosition) { + // ViaVersion sends this 1.20.5+ attribute also, so older servers will have correct range checks. + double blockInteractionRange = session.getPlayerEntity().getBlockInteractionRange(); + + // Mojmap Player#canInteractWithBlock + double additionalRangeCheck = blockInteractionRange + 1.0d; + + // AABB.(BlockPos) + float minX = packetBlockPosition.getX(); + float minY = packetBlockPosition.getY(); + float minZ = packetBlockPosition.getZ(); + float maxX = packetBlockPosition.getX() + 1; + float maxY = packetBlockPosition.getY() + 1; + float maxZ = packetBlockPosition.getZ() + 1; + + // AABB#distanceToSqr + float diffX = Math.max(Math.max(minX - playerPosition.getX(), playerPosition.getX() - maxX), 0); + float diffY = Math.max(Math.max(minY - playerPosition.getY(), playerPosition.getY() - maxY), 0); + float diffZ = Math.max(Math.max(minZ - playerPosition.getZ(), playerPosition.getZ() - maxZ), 0); + return ((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) < (additionalRangeCheck * additionalRangeCheck); + } + /** * Restore the correct block state from the server without updating the chunk cache. * @@ -696,4 +695,4 @@ private void lookAt(GeyserSession session, Vector3f target) { }, 150, TimeUnit.MILLISECONDS)); } } -} \ No newline at end of file +}