From 6638c53029eca3dc742ec6db08f92d011771cb8a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:54:19 -0400 Subject: [PATCH] Implement command block and jigsaw support (#1291) * Implement command block and jigsaw support - Command block UI is now fully implemented to match Java Edition. - Command block minecarts are now supported. - Command blocks now show the correct type of command block. - Jigsaw blocks are translated. Structure blocks can be implemented, but these will be trickier as there are significant GUI differences between Java and Bedrock. * Add more detail about command block minecart color * Set PlayerPermission.OPERATOR to allow command blocks to be destroyed --- README.md | 1 - .../entity/CommandBlockMinecartEntity.java | 67 +++++++++++++++++ .../connector/entity/type/EntityType.java | 2 +- .../network/session/GeyserSession.java | 3 +- .../BedrockBlockEntityDataTranslator.java | 13 ++++ .../BedrockCommandBlockUpdateTranslator.java | 71 +++++++++++++++++++ ...BedrockInventoryTransactionTranslator.java | 33 +++++++++ .../world/JavaUpdateTileEntityTranslator.java | 16 ++++- .../world/block/BlockStateValues.java | 16 +++++ .../world/block/BlockTranslator.java | 33 ++++++--- .../entity/BannerBlockEntityTranslator.java | 16 ----- .../entity/BedBlockEntityTranslator.java | 12 ---- .../block/entity/BlockEntityTranslator.java | 9 +-- .../entity/CampfireBlockEntityTranslator.java | 12 ---- .../CommandBlockBlockEntityTranslator.java | 67 +++++++++++++++++ .../DoubleChestBlockEntityTranslator.java | 10 --- .../entity/EmptyBlockEntityTranslator.java | 10 --- .../EndGatewayBlockEntityTranslator.java | 20 +----- .../JigsawBlockBlockEntityTranslator.java | 47 ++++++++++++ .../ShulkerBoxBlockEntityTranslator.java | 12 ---- .../entity/SignBlockEntityTranslator.java | 18 ----- .../entity/SkullBlockEntityTranslator.java | 13 ---- .../entity/SpawnerBlockEntityTranslator.java | 13 ---- 23 files changed, 359 insertions(+), 155 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandBlockUpdateTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java diff --git a/README.md b/README.md index 156745df3..ba3e6fc2d 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,6 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - [ ] Beacon - [ ] Cartography Table - [ ] Stonecutter - - [ ] Command Block - [ ] Structure Block - [ ] Horse Inventory - [ ] Loom diff --git a/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java new file mode 100644 index 000000000..8cabba645 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.entity; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.github.steveice10.mc.protocol.data.message.Message; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.utils.MessageUtils; + +public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity { + + public CommandBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position, motion, rotation); + // Required, or else the GUI will not open + metadata.put(EntityData.CONTAINER_TYPE, (byte) 16); + metadata.put(EntityData.CONTAINER_BASE_SIZE, 1); + // Required, or else the client does not bother to send a packet back with the new information + metadata.put(EntityData.COMMAND_BLOCK_ENABLED, (byte) 1); + } + + @Override + public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + if (entityMetadata.getId() == 13) { + metadata.put(EntityData.COMMAND_BLOCK_COMMAND, entityMetadata.getValue()); + } + if (entityMetadata.getId() == 14) { + metadata.put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageUtils.getBedrockMessage((Message) entityMetadata.getValue())); + } + super.updateBedrockMetadata(entityMetadata, session); + } + + /** + * By default, the command block shown is purple on Bedrock, which does not match Java Edition's orange. + */ + @Override + public void updateDefaultBlockMetadata() { + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.BEDROCK_RUNTIME_COMMAND_BLOCK_ID); + metadata.put(EntityData.DISPLAY_OFFSET, 6); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java index 87f4c8b50..500e135ed 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java +++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java @@ -135,7 +135,7 @@ public enum EntityType { MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"), MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"), MINECART_SPAWNER(SpawnerMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"), - MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"), + MINECART_COMMAND_BLOCK(CommandBlockMinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"), LINGERING_POTION(ThrowableEntity.class, 101, 0f), LLAMA_SPIT(Entity.class, 102, 0.25f), EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"), diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 7a61eb220..efdb1aa61 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -714,7 +714,8 @@ public class GeyserSession implements CommandSender { // This allows mobile players access to a GUI for doing commands. The commands there do not change above OPERATOR // and all commands there are accessible with OP permission level 2 adventureSettingsPacket.setCommandPermission(opPermissionLevel >= 2 ? CommandPermission.OPERATOR : CommandPermission.NORMAL); - adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); + // Required to make command blocks destroyable + adventureSettingsPacket.setPlayerPermission(opPermissionLevel >= 2 ? PlayerPermission.OPERATOR : PlayerPermission.MEMBER); Set flags = new HashSet<>(); if (canFly) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java index 147b8a3b1..3522b4d56 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientUpdateJigsawBlockPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientUpdateSignPacket; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; @@ -109,6 +110,18 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator { + + @Override + public void translate(CommandBlockUpdatePacket packet, GeyserSession session) { + String command = packet.getCommand(); + boolean outputTracked = packet.isOutputTracked(); + if (packet.isBlock()) { + CommandBlockMode mode; + switch (packet.getMode()) { + case CHAIN: // The green one + mode = CommandBlockMode.SEQUENCE; + break; + case REPEATING: // The purple one + mode = CommandBlockMode.AUTO; + break; + default: // NORMAL, the orange one + mode = CommandBlockMode.REDSTONE; + break; + } + boolean isConditional = packet.isConditional(); + boolean automatic = !packet.isRedstoneMode(); // Automatic = Always Active option in Java + ClientUpdateCommandBlockPacket commandBlockPacket = new ClientUpdateCommandBlockPacket( + new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), + command, mode, outputTracked, isConditional, automatic); + session.sendDownstreamPacket(commandBlockPacket); + } else { + ClientUpdateCommandBlockMinecartPacket commandMinecartPacket = new ClientUpdateCommandBlockMinecartPacket( + (int) session.getEntityCache().getEntityByGeyserId(packet.getMinecartRuntimeEntityId()).getEntityId(), + command, outputTracked + ); + session.sendDownstreamPacket(commandMinecartPacket); + } + } +} 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 cc1da85e8..95e669572 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,8 +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.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import org.geysermc.connector.entity.CommandBlockMinecartEntity; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity; @@ -105,6 +108,24 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator= 2 && session.getGameMode() == GameMode.CREATIVE) { + // Otherwise insufficient permissions + int blockState = BlockTranslator.getJavaBlockState(packet.getBlockRuntimeId()); + String blockName = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(blockState, ""); + // In the future this can be used for structure blocks too, however not all elements + // are available in each GUI + if (blockName.contains("jigsaw")) { + ContainerOpenPacket openPacket = new ContainerOpenPacket(); + openPacket.setBlockPosition(packet.getBlockPosition()); + openPacket.setId((byte) 1); + openPacket.setType(ContainerType.JIGSAW_EDITOR); + openPacket.setUniqueEntityId(-1); + session.sendUpstreamPacket(openPacket); + } + } + } + Vector3i blockPos = packet.getBlockPosition(); // TODO: Find a better way to do this? switch (packet.getBlockFace()) { @@ -197,6 +218,18 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator= 2 && + session.getGameMode() == GameMode.CREATIVE && packet.getNbt().size() > 5) { + ContainerOpenPacket openPacket = new ContainerOpenPacket(); + openPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + openPacket.setId((byte) 1); + openPacket.setType(ContainerType.COMMAND_BLOCK); + openPacket.setUniqueEntityId(-1); + session.sendUpstreamPacket(openPacket); + } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java index 53607317a..305118e6f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java @@ -39,6 +39,7 @@ public class BlockStateValues { private static final Int2IntMap BANNER_COLORS = new Int2IntOpenHashMap(); private static final Int2ByteMap BED_COLORS = new Int2ByteOpenHashMap(); + private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap(); private static final Int2ObjectMap DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); private static final Map FLOWER_POT_BLOCKS = new HashMap<>(); @@ -67,6 +68,11 @@ public class BlockStateValues { return; } + if (entry.getKey().contains("command_block")) { + COMMAND_BLOCK_VALUES.put(javaBlockState, entry.getKey().contains("conditional=true") ? (byte) 1 : (byte) 0); + return; + } + if (entry.getValue().get("double_chest_position") != null) { boolean isX = (entry.getValue().get("x") != null); boolean isDirectionPositive = ((entry.getValue().get("x") != null && entry.getValue().get("x").asBoolean()) || @@ -138,6 +144,16 @@ public class BlockStateValues { return -1; } + /** + * The block state in Java and Bedrock both contain the conditional bit, however command block block entity tags + * in Bedrock need the conditional information. + * + * @return the list of all command blocks and if they are conditional (1 or 0) + */ + public static Int2ByteMap getCommandBlockValues() { + return COMMAND_BLOCK_VALUES; + } + /** * All double chest values are part of the block state in Java and part of the block entity tag in Bedrock. * This gives the DoubleChestValue that can be calculated into the final tag. 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 81c86c307..fc7c852cb 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 @@ -67,6 +67,11 @@ public class BlockTranslator { public static final Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap(); public static final Int2ObjectMap JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>(); + /** + * Runtime command block ID, used for fixing command block minecart appearances + */ + public static final int BEDROCK_RUNTIME_COMMAND_BLOCK_ID; + // For block breaking animation math public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet(); public static final int JAVA_RUNTIME_COBWEB_ID; @@ -115,6 +120,7 @@ public class BlockTranslator { int javaRuntimeId = -1; int bedrockRuntimeId = 0; int cobwebRuntimeId = -1; + int commandBlockRuntimeId = -1; int furnaceRuntimeId = -1; int furnaceLitRuntimeId = -1; int spawnerRuntimeId = -1; @@ -142,14 +148,6 @@ public class BlockTranslator { JAVA_RUNTIME_ID_TO_TOOL_TYPE.put(javaRuntimeId, toolTypeNode.textValue()); } - if (javaId.contains("wool")) { - JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId); - } - - if (javaId.contains("cobweb")) { - cobwebRuntimeId = javaRuntimeId; - } - JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId); // Used for adding all "special" Java block states to block state map @@ -205,15 +203,23 @@ public class BlockTranslator { } JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId); - if (javaId.startsWith("minecraft:furnace[facing=north")) { + if (javaId.contains("wool")) { + JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId); + + } else if (javaId.contains("cobweb")) { + cobwebRuntimeId = javaRuntimeId; + + } else if (javaId.equals("minecraft:command_block[conditional=false,facing=north]")) { + commandBlockRuntimeId = bedrockRuntimeId; + + } else if (javaId.startsWith("minecraft:furnace[facing=north")) { if (javaId.contains("lit=true")) { furnaceLitRuntimeId = javaRuntimeId; } else { furnaceRuntimeId = javaRuntimeId; } - } - if (javaId.startsWith("minecraft:spawner")) { + } else if (javaId.startsWith("minecraft:spawner")) { spawnerRuntimeId = javaRuntimeId; } @@ -225,6 +231,11 @@ public class BlockTranslator { } JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId; + if (commandBlockRuntimeId == -1) { + throw new AssertionError("Unable to find command block in palette"); + } + BEDROCK_RUNTIME_COMMAND_BLOCK_ID = commandBlockRuntimeId; + if (furnaceRuntimeId == -1) { throw new AssertionError("Unable to find furnace in palette"); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java index 9e86cb4cf..57393a6c5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java @@ -27,12 +27,9 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtType; import org.geysermc.connector.network.translators.item.translators.BannerTranslator; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -65,17 +62,4 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - CompoundTag tag = getConstantJavaTag(javaId, x, y, z); - tag.put(new ListTag("Patterns")); - return tag; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() - .putList("Patterns", NbtType.COMPOUND, new ArrayList<>()) - .build(); - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java index b84aad984..080bdc3b2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.network.translators.world.block.BlockStateValues; import java.util.HashMap; @@ -50,15 +49,4 @@ public class BedBlockEntityTranslator extends BlockEntityTranslator implements R return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - return null; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() - .putByte("color", (byte) 0) - .build(); - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java index a538c2dcc..54f593a61 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java @@ -28,9 +28,9 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; - import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.BlockEntityUtils; @@ -53,6 +53,7 @@ public abstract class BlockEntityTranslator { { // Bedrock/Java differences put("minecraft:enchanting_table", "EnchantTable"); + put("minecraft:jigsaw", "JigsawBlock"); put("minecraft:piston_head", "PistonArm"); put("minecraft:trapped_chest", "Chest"); // There are some legacy IDs sent but as far as I can tell they are not needed for things to work properly @@ -90,10 +91,6 @@ public abstract class BlockEntityTranslator { public abstract Map translateTag(CompoundTag tag, int blockState); - public abstract CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z); - - public abstract NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z); - public NbtMap getBlockEntityTag(String id, CompoundTag tag, int blockState) { int x = Integer.parseInt(String.valueOf(tag.getValue().get("x").getValue())); int y = Integer.parseInt(String.valueOf(tag.getValue().get("y").getValue())); @@ -124,7 +121,7 @@ public abstract class BlockEntityTranslator { } @SuppressWarnings("unchecked") - protected T getOrDefault(com.github.steveice10.opennbt.tag.builtin.Tag tag, T defaultValue) { + protected T getOrDefault(Tag tag, T defaultValue) { return (tag != null && tag.getValue() != null) ? (T) tag.getValue() : defaultValue; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java index e3d2c9f5e..d6ac0281b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java @@ -50,18 +50,6 @@ public class CampfireBlockEntityTranslator extends BlockEntityTranslator { return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - CompoundTag tag = getConstantJavaTag(javaId, x, y, z); - tag.put(new ListTag("Items")); - return tag; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z); - } - protected NbtMap getItem(CompoundTag tag) { ItemEntry entry = ItemRegistry.getItemEntry((String) tag.get("id").getValue()); NbtMapBuilder tagBuilder = NbtMap.builder() diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java new file mode 100644 index 000000000..6bc940adb --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.world.block.entity; + +import com.github.steveice10.opennbt.tag.builtin.*; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.utils.MessageUtils; + +import java.util.HashMap; +import java.util.Map; + +@BlockEntity(name = "CommandBlock", regex = "command_block") +public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { + + @Override + public Map translateTag(CompoundTag tag, int blockState) { + Map map = new HashMap<>(); + if (tag.size() < 5) { + return map; // These values aren't here + } + // Java infers from the block state, but Bedrock needs it in the tag + map.put("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0)); + // Java and Bedrock values + map.put("conditionMet", ((ByteTag) tag.get("conditionMet")).getValue()); + map.put("auto", ((ByteTag) tag.get("auto")).getValue()); + map.put("CustomName", MessageUtils.getBedrockMessage(((StringTag) tag.get("CustomName")).getValue())); + map.put("powered", ((ByteTag) tag.get("powered")).getValue()); + map.put("Command", ((StringTag) tag.get("Command")).getValue()); + map.put("SuccessCount", ((IntTag) tag.get("SuccessCount")).getValue()); + map.put("TrackOutput", ((ByteTag) tag.get("TrackOutput")).getValue()); + map.put("UpdateLastExecution", ((ByteTag) tag.get("UpdateLastExecution")).getValue()); + if (tag.get("LastExecution") != null) { + map.put("LastExecution", ((LongTag) tag.get("LastExecution")).getValue()); + } else { + map.put("LastExecution", (long) 0); + } + return map; + } + + @Override + public boolean isBlock(int blockState) { + return BlockStateValues.getCommandBlockValues().containsKey(blockState); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java index fa8bab3b0..5b59420e0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java @@ -27,7 +27,6 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockStateValues; @@ -92,13 +91,4 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - return null; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return null; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java index 6de136119..e9715bd32 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMap; import java.util.HashMap; import java.util.Map; @@ -39,13 +38,4 @@ public class EmptyBlockEntityTranslator extends BlockEntityTranslator { return new HashMap<>(); } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - return getConstantJavaTag(javaId, x, y, z); - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z); - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java index 784afed5b..af94c560d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java @@ -26,14 +26,12 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.LongTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.nukkitx.nbt.NbtList; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtType; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; -import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -56,25 +54,11 @@ public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator { return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - CompoundTag tag = getConstantJavaTag(javaId, x, y, z); - tag.put(new LongTag("Age")); - return tag; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() - .putList("ExitPortal", NbtType.INT, Arrays.asList(0, 0, 0)) - .build(); - } - private int getExitPortalCoordinate(CompoundTag tag, String axis) { // Return 0 if it doesn't exist, otherwise give proper value if (tag.get("ExitPortal") != null) { LinkedHashMap compoundTag = (LinkedHashMap) tag.get("ExitPortal").getValue(); - com.github.steveice10.opennbt.tag.builtin.IntTag intTag = (com.github.steveice10.opennbt.tag.builtin.IntTag) compoundTag.get(axis); + IntTag intTag = (IntTag) compoundTag.get(axis); return intTag.getValue(); } return 0; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java new file mode 100644 index 000000000..43ac1a96f --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.world.block.entity; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; + +import java.util.HashMap; +import java.util.Map; + +@BlockEntity(name = "JigsawBlock", regex = "jigsaw") +public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator { + + @Override + public Map translateTag(CompoundTag tag, int blockState) { + Map map = new HashMap<>(); + map.put("joint", ((StringTag) tag.get("joint")).getValue()); + map.put("name", ((StringTag) tag.get("name")).getValue()); + map.put("target_pool", ((StringTag) tag.get("pool")).getValue()); + map.put("final_state", ((StringTag) tag.get("final_state")).getValue()); + map.put("target", ((StringTag) tag.get("target")).getValue()); + return map; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java index 08a7ae187..08e3abaab 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.network.translators.world.block.BlockStateValues; import java.util.HashMap; @@ -46,15 +45,4 @@ public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator { return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - return null; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() - .putByte("facing", (byte) 1) - .build(); - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java index acec16c5c..b40ed42c9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java @@ -27,7 +27,6 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.mc.protocol.data.message.MessageSerializer; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.utils.MessageUtils; import org.geysermc.connector.utils.SignUtils; @@ -73,23 +72,6 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator { return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - CompoundTag tag = getConstantJavaTag(javaId, x, y, z); - tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text1", "{\"text\":\"\"}")); - tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text2", "{\"text\":\"\"}")); - tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text3", "{\"text\":\"\"}")); - tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text4", "{\"text\":\"\"}")); - return tag; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() - .putString("Text", "") - .build(); - } - /** * Maps a color stored in a sign's Color tag to a Bedrock Edition formatting code. *
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java index 9547ba2ff..6d350c0cc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.connector.network.translators.world.block.entity; -import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.network.translators.world.block.BlockStateValues; import java.util.HashMap; @@ -51,16 +50,4 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements return tags; } - @Override - public com.github.steveice10.opennbt.tag.builtin.CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - return null; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() - .putFloat("Rotation", 0f) - .putByte("SkullType", (byte) 0) - .build(); - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java index 3c443eeeb..2601e3de9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.entity.type.EntityType; import java.util.HashMap; @@ -86,16 +85,4 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { return tags; } - @Override - public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { - return null; - } - - @Override - public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { - return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() - .putByte("isMovable", (byte) 1) - .putString("id", "MobSpawner") - .build(); - } }