From ade4c1491114b274103d3974faf2239fcdd314d5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 7 Jan 2021 22:43:36 -0500 Subject: [PATCH] Block breaking refactors (#1336) Client-side block animations and reach checks are now added. This commit also includes cleanup in BlockChangeTranslator as well as proper Netherite tool support for calculating block breaking. Co-authored-by: rtm516 --- ...BedrockInventoryTransactionTranslator.java | 120 +++++++++++++++--- .../player/BedrockActionTranslator.java | 50 +++++++- .../entity/JavaEntityStatusTranslator.java | 15 ++- .../player/JavaPlayerActionAckTranslator.java | 99 ++++++++------- .../java/world/JavaBlockChangeTranslator.java | 11 +- .../world/block/BlockTranslator.java | 4 +- .../geysermc/connector/utils/BlockUtils.java | 3 + 7 files changed, 224 insertions(+), 78 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 228b2812..8263507b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -39,12 +39,11 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.LevelEventType; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlags; import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; -import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.connector.entity.CommandBlockMinecartEntity; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; @@ -64,9 +63,18 @@ import org.geysermc.connector.utils.InventoryUtils; import java.util.concurrent.TimeUnit; +/** + * BedrockInventoryTransactionTranslator handles most interactions between the client and the world, + * or the client and their inventory. + */ @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(InventoryTransactionPacket packet, GeyserSession session) { // Send book updates before opening inventories @@ -112,6 +120,46 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator + (session.getGameMode().equals(GameMode.CREATIVE) ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { + restoreCorrectBlock(session, blockPos, packet); + return; + } + + // Vanilla check + if (!(session.getPlayerEntity().getPosition().sub(0, EntityType.PLAYER.getOffset(), 0) + .distanceSquared(packet.getBlockPosition().toFloat().add(0.5f, 0.5f, 0.5f)) < 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; + } + /* + Block place checks end - client is good to go + */ + ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket( new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.values()[packet.getBlockFace()], @@ -159,7 +207,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator MAXIMUM_BLOCK_DESTROYING_DISTANCE) { + restoreCorrectBlock(session, packet.getBlockPosition(), packet); + return; } + LevelEventPacket blockBreakPacket = new LevelEventPacket(); + blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); + blockBreakPacket.setPosition(packet.getBlockPosition().toFloat()); + blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState)); + session.sendUpstreamPacket(blockBreakPacket); + session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID); + long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()); if (frameEntityId != -1 && session.getEntityCache().getEntityByJavaId(frameEntityId) != null) { ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) frameEntityId, InteractAction.ATTACK, session.isSneaking()); @@ -270,4 +330,34 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { @Override public void translate(ServerBlockChangePacket packet, GeyserSession session) { Position pos = packet.getRecord().getPosition(); - boolean updatePlacement = !(session.getConnector().getConfig().isCacheChunks() && session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()) == packet.getRecord().getBlock()); - ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), packet.getRecord().getPosition()); - if (updatePlacement && session.getConnector().getPlatformType() != PlatformType.SPIGOT) { + boolean updatePlacement = session.getConnector().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event + !(session.getConnector().getConfig().isCacheChunks() && + session.getConnector().getWorldManager().getBlockAt(session, pos) == packet.getRecord().getBlock()); + ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), pos); + if (updatePlacement) { this.checkPlace(session, packet); } this.checkInteract(session, packet); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java index db6f43fe..b047999e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java @@ -87,7 +87,9 @@ public class BlockTranslator { */ public static final int BEDROCK_RUNTIME_COMMAND_BLOCK_ID; - // For block breaking animation math + /** + * A list of all Java runtime wool IDs, for use with block breaking math and shears + */ public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet(); public static final int JAVA_RUNTIME_COBWEB_ID; diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java index 93909b20..c859b9f6 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java @@ -50,6 +50,7 @@ public class BlockUtils { if (toolType.equals("shears")) return isWoolBlock ? 5.0 : 15.0; if (toolType.equals("")) return 1.0; switch (toolTier) { + // https://minecraft.gamepedia.com/Breaking#Speed case "wooden": return 2.0; case "stone": @@ -58,6 +59,8 @@ public class BlockUtils { return 6.0; case "diamond": return 8.0; + case "netherite": + return 9.0; case "golden": return 12.0; default: