forked from GeyserMC/Geyser
		
	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 <rtm516@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									fe23c79053
								
							
						
					
					
						commit
						ade4c14911
					
				
					 7 changed files with 224 additions and 78 deletions
				
			
		| 
						 | 
				
			
			@ -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<InventoryTransactionPacket> {
 | 
			
		||||
 | 
			
		||||
    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<Inve
 | 
			
		|||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Vector3i blockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getBlockFace());
 | 
			
		||||
                        /*
 | 
			
		||||
                        Checks to ensure that the range will be accepted by the server.
 | 
			
		||||
                        "Not in range" doesn't refer to how far a vanilla client goes (that's a whole other mess),
 | 
			
		||||
                        but how much a server will accept from the client maximum
 | 
			
		||||
                         */
 | 
			
		||||
                        // CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch
 | 
			
		||||
                        Vector3f playerPosition = session.getPlayerEntity().getPosition();
 | 
			
		||||
                        EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
 | 
			
		||||
 | 
			
		||||
                        // Adjust position for current eye height
 | 
			
		||||
                        if (flags.getFlag(EntityFlag.SNEAKING)) {
 | 
			
		||||
                            playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0);
 | 
			
		||||
                        } else if (flags.getFlag(EntityFlag.SWIMMING) || flags.getFlag(EntityFlag.GLIDING) || flags.getFlag(EntityFlag.DAMAGE_NEARBY_MOBS)) {
 | 
			
		||||
                            // Swimming, gliding, or using the trident spin attack
 | 
			
		||||
                            playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.4f), 0);
 | 
			
		||||
                        } else if (flags.getFlag(EntityFlag.SLEEPING)) {
 | 
			
		||||
                            playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.2f), 0);
 | 
			
		||||
                        } // else, we don't have to modify the position
 | 
			
		||||
 | 
			
		||||
                        float diffX = playerPosition.getX() - packet.getBlockPosition().getX();
 | 
			
		||||
                        float diffY = playerPosition.getY() - packet.getBlockPosition().getY();
 | 
			
		||||
                        float diffZ = playerPosition.getZ() - packet.getBlockPosition().getZ();
 | 
			
		||||
                        if (((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) >
 | 
			
		||||
                                (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<Inve
 | 
			
		|||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Vector3i blockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getBlockFace());
 | 
			
		||||
                        ItemEntry handItem = ItemRegistry.getItem(packet.getItemInHand());
 | 
			
		||||
                        if (handItem.isBlock()) {
 | 
			
		||||
                            session.setLastBlockPlacePosition(blockPos);
 | 
			
		||||
| 
						 | 
				
			
			@ -184,19 +231,32 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
 | 
			
		|||
                        session.sendDownstreamPacket(useItemPacket);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 2:
 | 
			
		||||
                        int blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
 | 
			
		||||
                        double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(blockState);
 | 
			
		||||
                        if (session.getGameMode() == GameMode.CREATIVE || (session.getConnector().getConfig().isCacheChunks() && blockHardness == 0)) {
 | 
			
		||||
                            session.setLastBlockPlacedId(null);
 | 
			
		||||
                            session.setLastBlockPlacePosition(null);
 | 
			
		||||
                        int blockState = session.getGameMode() == GameMode.CREATIVE ?
 | 
			
		||||
                                session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition()) : session.getBreakingBlock();
 | 
			
		||||
 | 
			
		||||
                            LevelEventPacket blockBreakPacket = new LevelEventPacket();
 | 
			
		||||
                            blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
 | 
			
		||||
                            blockBreakPacket.setPosition(packet.getBlockPosition().toFloat());
 | 
			
		||||
                            blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState));
 | 
			
		||||
                            session.sendUpstreamPacket(blockBreakPacket);
 | 
			
		||||
                        session.setLastBlockPlacedId(null);
 | 
			
		||||
                        session.setLastBlockPlacePosition(null);
 | 
			
		||||
 | 
			
		||||
                        // Same deal with vanilla block placing as above.
 | 
			
		||||
                        // 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.
 | 
			
		||||
                        playerPosition = session.getPlayerEntity().getPosition();
 | 
			
		||||
                        Vector3f floatBlockPosition = packet.getBlockPosition().toFloat();
 | 
			
		||||
                        diffX = playerPosition.getX() - (floatBlockPosition.getX() + 0.5f);
 | 
			
		||||
                        diffY = (playerPosition.getY() - EntityType.PLAYER.getOffset()) - (floatBlockPosition.getY() + 0.5f) + 1.5f;
 | 
			
		||||
                        diffZ = playerPosition.getZ() - (floatBlockPosition.getZ() + 0.5f);
 | 
			
		||||
                        float distanceSquared = diffX * diffX + diffY * diffY + diffZ * diffZ;
 | 
			
		||||
                        if (distanceSquared > 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<Inve
 | 
			
		|||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Restore the correct block state from the server without updating the chunk cache.
 | 
			
		||||
     *
 | 
			
		||||
     * @param session the session of the Bedrock client
 | 
			
		||||
     * @param blockPos the block position to restore
 | 
			
		||||
     */
 | 
			
		||||
    private void restoreCorrectBlock(GeyserSession session, Vector3i blockPos, InventoryTransactionPacket packet) {
 | 
			
		||||
        int javaBlockState = session.getConnector().getWorldManager().getBlockAt(session, blockPos);
 | 
			
		||||
        UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
 | 
			
		||||
        updateBlockPacket.setDataLayer(0);
 | 
			
		||||
        updateBlockPacket.setBlockPosition(blockPos);
 | 
			
		||||
        updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(javaBlockState));
 | 
			
		||||
        updateBlockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
 | 
			
		||||
        session.sendUpstreamPacket(updateBlockPacket);
 | 
			
		||||
 | 
			
		||||
        UpdateBlockPacket updateWaterPacket = new UpdateBlockPacket();
 | 
			
		||||
        updateWaterPacket.setDataLayer(1);
 | 
			
		||||
        updateWaterPacket.setBlockPosition(blockPos);
 | 
			
		||||
        updateWaterPacket.setRuntimeId(BlockTranslator.isWaterlogged(javaBlockState) ? BlockTranslator.BEDROCK_WATER_ID : BlockTranslator.BEDROCK_AIR_ID);
 | 
			
		||||
        updateWaterPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
 | 
			
		||||
        session.sendUpstreamPacket(updateWaterPacket);
 | 
			
		||||
 | 
			
		||||
        // Reset the item in hand to prevent "missing" blocks
 | 
			
		||||
        InventorySlotPacket slotPacket = new InventorySlotPacket();
 | 
			
		||||
        slotPacket.setContainerId(ContainerId.INVENTORY);
 | 
			
		||||
        slotPacket.setSlot(packet.getHotbarSlot());
 | 
			
		||||
        slotPacket.setItem(packet.getItemInHand());
 | 
			
		||||
        session.sendUpstreamPacket(slotPacket);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,13 +25,16 @@
 | 
			
		|||
 | 
			
		||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
 | 
			
		||||
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
 | 
			
		||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
 | 
			
		||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
 | 
			
		||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
 | 
			
		||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
 | 
			
		||||
import com.nukkitx.math.vector.Vector3i;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,9 +43,12 @@ import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
 | 
			
		|||
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket;
 | 
			
		||||
import org.geysermc.connector.entity.Entity;
 | 
			
		||||
import org.geysermc.connector.inventory.PlayerInventory;
 | 
			
		||||
import org.geysermc.connector.network.session.GeyserSession;
 | 
			
		||||
import org.geysermc.connector.network.translators.PacketTranslator;
 | 
			
		||||
import org.geysermc.connector.network.translators.Translator;
 | 
			
		||||
import org.geysermc.connector.network.translators.item.ItemEntry;
 | 
			
		||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
 | 
			
		||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
 | 
			
		||||
import org.geysermc.connector.utils.BlockUtils;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +136,27 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
 | 
			
		|||
                break;
 | 
			
		||||
            case START_BREAK:
 | 
			
		||||
                if (session.getConnector().getConfig().isCacheChunks()) {
 | 
			
		||||
                    // Start the block breaking animation
 | 
			
		||||
                    if (session.getGameMode() != GameMode.CREATIVE) {
 | 
			
		||||
                        int blockState = session.getConnector().getWorldManager().getBlockAt(session, vector);
 | 
			
		||||
                        double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(blockState);
 | 
			
		||||
                        LevelEventPacket startBreak = new LevelEventPacket();
 | 
			
		||||
                        startBreak.setType(LevelEventType.BLOCK_START_BREAK);
 | 
			
		||||
                        startBreak.setPosition(vector.toFloat());
 | 
			
		||||
                        PlayerInventory inventory = session.getInventory();
 | 
			
		||||
                        ItemStack item = inventory.getItemInHand();
 | 
			
		||||
                        ItemEntry itemEntry = null;
 | 
			
		||||
                        CompoundTag nbtData = new CompoundTag("");
 | 
			
		||||
                        if (item != null) {
 | 
			
		||||
                            itemEntry = ItemRegistry.getItem(item);
 | 
			
		||||
                            nbtData = item.getNbt();
 | 
			
		||||
                        }
 | 
			
		||||
                        double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, blockState, itemEntry, nbtData, session) * 20);
 | 
			
		||||
                        startBreak.setData((int) (65535 / breakTime));
 | 
			
		||||
                        session.setBreakingBlock(blockState);
 | 
			
		||||
                        session.sendUpstreamPacket(startBreak);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Account for fire - the client likes to hit the block behind.
 | 
			
		||||
                    Vector3i fireBlockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getFace());
 | 
			
		||||
                    int blockUp = session.getConnector().getWorldManager().getBlockAt(session, fireBlockPos);
 | 
			
		||||
| 
						 | 
				
			
			@ -138,24 +165,33 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
 | 
			
		|||
                        ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
 | 
			
		||||
                                fireBlockPos.getY(), fireBlockPos.getZ()), BlockFace.values()[packet.getFace()]);
 | 
			
		||||
                        session.sendDownstreamPacket(startBreakingPacket);
 | 
			
		||||
                        break;
 | 
			
		||||
                        if (session.getGameMode() == GameMode.CREATIVE) {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(packet.getBlockPosition().getX(),
 | 
			
		||||
                        packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.values()[packet.getFace()]);
 | 
			
		||||
                ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, position, BlockFace.values()[packet.getFace()]);
 | 
			
		||||
                session.sendDownstreamPacket(startBreakingPacket);
 | 
			
		||||
                break;
 | 
			
		||||
            case CONTINUE_BREAK:
 | 
			
		||||
                if (session.getGameMode() == GameMode.CREATIVE) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                LevelEventPacket continueBreakPacket = new LevelEventPacket();
 | 
			
		||||
                continueBreakPacket.setType(LevelEventType.PARTICLE_CRACK_BLOCK);
 | 
			
		||||
                continueBreakPacket.setData(BlockTranslator.getBedrockBlockId(session.getBreakingBlock()));
 | 
			
		||||
                continueBreakPacket.setPosition(packet.getBlockPosition().toFloat());
 | 
			
		||||
                continueBreakPacket.setData((BlockTranslator.getBedrockBlockId(session.getBreakingBlock())) | (packet.getFace() << 24));
 | 
			
		||||
                continueBreakPacket.setPosition(vector.toFloat());
 | 
			
		||||
                session.sendUpstreamPacket(continueBreakPacket);
 | 
			
		||||
                break;
 | 
			
		||||
            case ABORT_BREAK:
 | 
			
		||||
                ClientPlayerActionPacket abortBreakingPacket = new ClientPlayerActionPacket(PlayerAction.CANCEL_DIGGING, new Position(packet.getBlockPosition().getX(),
 | 
			
		||||
                        packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.DOWN);
 | 
			
		||||
                ClientPlayerActionPacket abortBreakingPacket = new ClientPlayerActionPacket(PlayerAction.CANCEL_DIGGING, position, BlockFace.DOWN);
 | 
			
		||||
                session.sendDownstreamPacket(abortBreakingPacket);
 | 
			
		||||
                LevelEventPacket stopBreak = new LevelEventPacket();
 | 
			
		||||
                stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK);
 | 
			
		||||
                stopBreak.setPosition(vector.toFloat());
 | 
			
		||||
                stopBreak.setData(0);
 | 
			
		||||
                session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
 | 
			
		||||
                session.sendUpstreamPacket(stopBreak);
 | 
			
		||||
                break;
 | 
			
		||||
            case STOP_BREAK:
 | 
			
		||||
                // Handled in BedrockInventoryTransactionTranslator
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,8 +31,8 @@ import com.nukkitx.protocol.bedrock.data.LevelEventType;
 | 
			
		|||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
 | 
			
		||||
import org.geysermc.connector.entity.Entity;
 | 
			
		||||
| 
						 | 
				
			
			@ -183,6 +183,19 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
 | 
			
		|||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case LIVING_EQUIPMENT_BREAK_HEAD:
 | 
			
		||||
            case LIVING_EQUIPMENT_BREAK_CHEST:
 | 
			
		||||
            case LIVING_EQUIPMENT_BREAK_LEGS:
 | 
			
		||||
            case LIVING_EQUIPMENT_BREAK_FEET:
 | 
			
		||||
            case LIVING_EQUIPMENT_BREAK_MAIN_HAND:
 | 
			
		||||
            case LIVING_EQUIPMENT_BREAK_OFF_HAND:
 | 
			
		||||
                LevelSoundEvent2Packet equipmentBreakPacket = new LevelSoundEvent2Packet();
 | 
			
		||||
                equipmentBreakPacket.setSound(SoundEvent.BREAK);
 | 
			
		||||
                equipmentBreakPacket.setPosition(entity.getPosition());
 | 
			
		||||
                equipmentBreakPacket.setExtraData(-1);
 | 
			
		||||
                equipmentBreakPacket.setIdentifier("");
 | 
			
		||||
                session.sendUpstreamPacket(equipmentBreakPacket);
 | 
			
		||||
                return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        session.sendUpstreamPacket(entityEventPacket);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,19 +27,20 @@ package org.geysermc.connector.network.translators.java.entity.player;
 | 
			
		|||
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
 | 
			
		||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
 | 
			
		||||
import com.github.steveice10.opennbt.tag.builtin.*;
 | 
			
		||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
 | 
			
		||||
import com.nukkitx.math.vector.Vector3f;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
 | 
			
		||||
import org.geysermc.connector.inventory.PlayerInventory;
 | 
			
		||||
import org.geysermc.connector.network.session.GeyserSession;
 | 
			
		||||
import org.geysermc.connector.network.translators.PacketTranslator;
 | 
			
		||||
import org.geysermc.connector.network.translators.Translator;
 | 
			
		||||
import org.geysermc.connector.network.translators.item.ItemEntry;
 | 
			
		||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
 | 
			
		||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
 | 
			
		||||
import org.geysermc.connector.network.translators.item.ItemEntry;
 | 
			
		||||
import org.geysermc.connector.utils.BlockUtils;
 | 
			
		||||
import org.geysermc.connector.network.translators.Translator;
 | 
			
		||||
import org.geysermc.connector.utils.ChunkUtils;
 | 
			
		||||
 | 
			
		||||
@Translator(packet = ServerPlayerActionAckPacket.class)
 | 
			
		||||
| 
						 | 
				
			
			@ -47,54 +48,54 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayer
 | 
			
		|||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void translate(ServerPlayerActionAckPacket packet, GeyserSession session) {
 | 
			
		||||
        LevelEventPacket levelEvent = new LevelEventPacket();
 | 
			
		||||
        switch (packet.getAction()) {
 | 
			
		||||
            case FINISH_DIGGING:
 | 
			
		||||
                double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(session.getBreakingBlock());
 | 
			
		||||
                if (session.getGameMode() != GameMode.CREATIVE && blockHardness != 0) {
 | 
			
		||||
                    levelEvent.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
 | 
			
		||||
                    levelEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
 | 
			
		||||
                    levelEvent.setData(BlockTranslator.getBedrockBlockId(session.getBreakingBlock()));
 | 
			
		||||
        ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
 | 
			
		||||
        if (packet.getAction() == PlayerAction.START_DIGGING && !packet.isSuccessful()) {
 | 
			
		||||
            LevelEventPacket stopBreak = new LevelEventPacket();
 | 
			
		||||
            stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK);
 | 
			
		||||
            stopBreak.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
 | 
			
		||||
            stopBreak.setData(0);
 | 
			
		||||
            session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
 | 
			
		||||
            session.sendUpstreamPacket(stopBreak);
 | 
			
		||||
        }
 | 
			
		||||
        if (!session.getConnector().getConfig().isCacheChunks()) {
 | 
			
		||||
            LevelEventPacket levelEvent = new LevelEventPacket();
 | 
			
		||||
            switch (packet.getAction()) {
 | 
			
		||||
                case START_DIGGING:
 | 
			
		||||
                    if (session.getGameMode() == GameMode.CREATIVE) {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(packet.getNewState());
 | 
			
		||||
                    levelEvent.setType(LevelEventType.BLOCK_START_BREAK);
 | 
			
		||||
                    levelEvent.setPosition(Vector3f.from(
 | 
			
		||||
                            packet.getPosition().getX(),
 | 
			
		||||
                            packet.getPosition().getY(),
 | 
			
		||||
                            packet.getPosition().getZ()
 | 
			
		||||
                    ));
 | 
			
		||||
                    PlayerInventory inventory = session.getInventory();
 | 
			
		||||
                    ItemStack item = inventory.getItemInHand();
 | 
			
		||||
                    ItemEntry itemEntry = null;
 | 
			
		||||
                    CompoundTag nbtData = new CompoundTag("");
 | 
			
		||||
                    if (item != null) {
 | 
			
		||||
                        itemEntry = ItemRegistry.getItem(item);
 | 
			
		||||
                        nbtData = item.getNbt();
 | 
			
		||||
                    }
 | 
			
		||||
                    double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState(), itemEntry, nbtData, session) * 20);
 | 
			
		||||
                    levelEvent.setData((int) (65535 / breakTime));
 | 
			
		||||
                    session.setBreakingBlock(packet.getNewState());
 | 
			
		||||
                    session.sendUpstreamPacket(levelEvent);
 | 
			
		||||
                    session.setBreakingBlock(0);
 | 
			
		||||
                }
 | 
			
		||||
                ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
 | 
			
		||||
                break;
 | 
			
		||||
            case START_DIGGING:
 | 
			
		||||
                if (session.getGameMode() == GameMode.CREATIVE) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(packet.getNewState());
 | 
			
		||||
                levelEvent.setType(LevelEventType.BLOCK_START_BREAK);
 | 
			
		||||
                levelEvent.setPosition(Vector3f.from(
 | 
			
		||||
                        packet.getPosition().getX(),
 | 
			
		||||
                        packet.getPosition().getY(),
 | 
			
		||||
                        packet.getPosition().getZ()
 | 
			
		||||
                ));
 | 
			
		||||
                PlayerInventory inventory = session.getInventory();
 | 
			
		||||
                ItemStack item = inventory.getItemInHand();
 | 
			
		||||
                ItemEntry itemEntry = null;
 | 
			
		||||
                CompoundTag nbtData = new CompoundTag("");
 | 
			
		||||
                if (item != null) {
 | 
			
		||||
                    itemEntry = ItemRegistry.getItem(item);
 | 
			
		||||
                    nbtData = item.getNbt();
 | 
			
		||||
                }
 | 
			
		||||
                double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState(), itemEntry, nbtData, session) * 20);
 | 
			
		||||
                levelEvent.setData((int) (65535 / breakTime));
 | 
			
		||||
                session.setBreakingBlock(packet.getNewState());
 | 
			
		||||
                session.sendUpstreamPacket(levelEvent);
 | 
			
		||||
                break;
 | 
			
		||||
            case CANCEL_DIGGING:
 | 
			
		||||
                levelEvent.setType(LevelEventType.BLOCK_STOP_BREAK);
 | 
			
		||||
                levelEvent.setPosition(Vector3f.from(
 | 
			
		||||
                        packet.getPosition().getX(),
 | 
			
		||||
                        packet.getPosition().getY(),
 | 
			
		||||
                        packet.getPosition().getZ()
 | 
			
		||||
                ));
 | 
			
		||||
                levelEvent.setData(0);
 | 
			
		||||
                session.setBreakingBlock(0);
 | 
			
		||||
                session.sendUpstreamPacket(levelEvent);
 | 
			
		||||
                break;
 | 
			
		||||
                case CANCEL_DIGGING:
 | 
			
		||||
                    levelEvent.setType(LevelEventType.BLOCK_STOP_BREAK);
 | 
			
		||||
                    levelEvent.setPosition(Vector3f.from(
 | 
			
		||||
                            packet.getPosition().getX(),
 | 
			
		||||
                            packet.getPosition().getY(),
 | 
			
		||||
                            packet.getPosition().getZ()
 | 
			
		||||
                    ));
 | 
			
		||||
                    levelEvent.setData(0);
 | 
			
		||||
                    session.setBreakingBlock(0);
 | 
			
		||||
                    session.sendUpstreamPacket(levelEvent);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +26,7 @@
 | 
			
		|||
package org.geysermc.connector.network.translators.java.world;
 | 
			
		||||
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
 | 
			
		||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket;
 | 
			
		||||
import com.nukkitx.math.vector.Vector3i;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.data.SoundEvent;
 | 
			
		||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
 | 
			
		||||
| 
						 | 
				
			
			@ -37,17 +38,17 @@ import org.geysermc.connector.network.translators.sound.BlockSoundInteractionHan
 | 
			
		|||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
 | 
			
		||||
import org.geysermc.connector.utils.ChunkUtils;
 | 
			
		||||
 | 
			
		||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket;
 | 
			
		||||
 | 
			
		||||
@Translator(packet = ServerBlockChangePacket.class)
 | 
			
		||||
public class JavaBlockChangeTranslator extends PacketTranslator<ServerBlockChangePacket> {
 | 
			
		||||
 | 
			
		||||
    @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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue