diff --git a/api/src/main/java/org/geysermc/api/Connector.java b/api/src/main/java/org/geysermc/api/Connector.java index e7bb26297..b305a197d 100644 --- a/api/src/main/java/org/geysermc/api/Connector.java +++ b/api/src/main/java/org/geysermc/api/Connector.java @@ -29,6 +29,8 @@ import org.geysermc.api.command.CommandMap; import org.geysermc.api.logger.Logger; import org.geysermc.api.plugin.PluginManager; +import java.util.concurrent.ScheduledExecutorService; + public interface Connector { /** @@ -52,6 +54,13 @@ public interface Connector { */ PluginManager getPluginManager(); + /** + * Returns the general thread pool + * + * @return the general thread pool + */ + ScheduledExecutorService getGeneralThreadPool(); + /** * Shuts down the connector */ diff --git a/api/src/main/java/org/geysermc/api/Geyser.java b/api/src/main/java/org/geysermc/api/Geyser.java index dc9f8983e..1d1a2e874 100644 --- a/api/src/main/java/org/geysermc/api/Geyser.java +++ b/api/src/main/java/org/geysermc/api/Geyser.java @@ -29,6 +29,8 @@ import org.geysermc.api.command.CommandMap; import org.geysermc.api.logger.Logger; import org.geysermc.api.plugin.PluginManager; +import java.util.concurrent.ScheduledExecutorService; + public class Geyser { private static Connector connector; @@ -77,4 +79,8 @@ public class Geyser { public static CommandMap getCommandMap() { return connector.getCommandMap(); } + + public static ScheduledExecutorService getGeneralThreadPool() { + return connector.getGeneralThreadPool(); + } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java new file mode 100644 index 000000000..ed988dcc1 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 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.inventory; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import lombok.Getter; +import lombok.Setter; + +public class Inventory { + + @Getter + private int id; + + @Getter + @Setter + private boolean open; + + @Getter + private WindowType windowType; + + @Getter + private int size; + + @Getter + @Setter + private String title; + + @Getter + @Setter + private ItemStack[] items; + + public Inventory(int id, WindowType windowType, int size) { + this.id = id; + this.windowType = windowType; + this.size = size; + + this.title = "Inventory"; + this.items = new ItemStack[size]; + } +} 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 c21252efa..ed72d1801 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 @@ -50,6 +50,7 @@ import org.geysermc.api.RemoteServer; import org.geysermc.api.session.AuthData; import org.geysermc.api.window.FormWindow; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.session.cache.InventoryCache; import org.geysermc.connector.network.session.cache.WindowCache; import org.geysermc.connector.network.translators.Registry; import org.geysermc.connector.utils.Toolbox; @@ -70,6 +71,9 @@ public class GeyserSession implements PlayerSession, Player { @Getter private AuthData authenticationData; + @Getter + private InventoryCache inventoryCache; + @Getter private WindowCache windowCache; @@ -82,6 +86,7 @@ public class GeyserSession implements PlayerSession, Player { this.connector = connector; this.upstream = bedrockServerSession; + this.inventoryCache = new InventoryCache(this); this.windowCache = new WindowCache(this); this.loggedIn = false; diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java new file mode 100644 index 000000000..b6c8b501a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 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.session.cache; + +import com.github.steveice10.packetlib.packet.Packet; +import lombok.Getter; +import lombok.Setter; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class InventoryCache { + + private GeyserSession session; + + @Getter + @Setter + private Inventory openInventory; + + @Getter + private Map inventories = new HashMap(); + + @Getter + private Map> cachedPackets = new HashMap>(); + + public InventoryCache(GeyserSession session) { + this.session = session; + + // This is the player's inventory + inventories.put(0, new Inventory(0, null, 45)); + } + + public Inventory getPlayerInventory() { + return inventories.get(0); + } + + public void cacheInventory(Inventory inventory) { + inventories.put(inventory.getId(), inventory); + } + + public void uncacheInventory(int id) { + inventories.remove(id); + } + + public void cachePacket(int id, Packet packet) { + List packets = cachedPackets.getOrDefault(id, new ArrayList()); + packets.add(packet); + cachedPackets.put(id, packets); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java index 0ce8b7c04..fc7de6144 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java @@ -1,3 +1,28 @@ +/* + * Copyright (c) 2019 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.session.cache; import com.nukkitx.protocol.bedrock.packet.ModalFormRequestPacket; @@ -12,13 +37,13 @@ public class WindowCache { private GeyserSession session; + @Getter + private Map windows = new HashMap(); + public WindowCache(GeyserSession session) { this.session = session; } - @Getter - private Map windows = new HashMap(); - public void addWindow(FormWindow window) { windows.put(windows.size() + 1, window); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java b/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java index 987fc4f27..a4efde575 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java @@ -50,9 +50,12 @@ public class Registry { public

void translate(Class clazz, P packet, GeyserSession session) { try { - ((PacketTranslator

) MAP.get(clazz)).translate(packet, session); + if (MAP.containsKey(clazz)) { + ((PacketTranslator

) MAP.get(clazz)).translate(packet, session); + } } catch (NullPointerException ex) { GeyserLogger.DEFAULT.debug("Could not translate packet " + packet.getClass().getSimpleName()); + ex.printStackTrace(); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index d1b629d21..4c42c1adc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java @@ -25,6 +25,7 @@ package org.geysermc.connector.network.translators; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerTitlePacket; @@ -32,6 +33,9 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntit import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionRotationPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityTeleportPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityVelocityPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerNotifyClientPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket; import com.nukkitx.nbt.CompoundTagBuilder; @@ -41,9 +45,13 @@ import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.packet.AnimatePacket; import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; +import lombok.Getter; import org.geysermc.connector.network.translators.bedrock.BedrockAnimateTranslator; import org.geysermc.connector.network.translators.bedrock.BedrockCommandRequestTranslator; import org.geysermc.connector.network.translators.bedrock.BedrockTextTranslator; +import org.geysermc.connector.network.translators.inventory.GenericInventoryTranslator; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.java.JavaChatTranslator; import org.geysermc.connector.network.translators.java.JavaEntityPositionRotationTranslator; import org.geysermc.connector.network.translators.java.JavaEntityPositionTranslator; @@ -51,14 +59,25 @@ import org.geysermc.connector.network.translators.java.JavaEntityTeleportTransla import org.geysermc.connector.network.translators.java.JavaEntityVelocityTranslator; import org.geysermc.connector.network.translators.java.JavaJoinGameTranslator; import org.geysermc.connector.network.translators.java.JavaNotifyClientTranslator; +import org.geysermc.connector.network.translators.java.JavaOpenWindowTranslator; +import org.geysermc.connector.network.translators.java.JavaSetSlotTranslator; import org.geysermc.connector.network.translators.java.JavaTitleTranslator; import org.geysermc.connector.network.translators.java.JavaUpdateTimeTranslator; +import org.geysermc.connector.network.translators.java.JavaWindowItemsTranslator; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; public class TranslatorsInit { + @Getter + private static ItemTranslator itemTranslator; + + @Getter + private static Map inventoryTranslators = new HashMap(); + private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag(); public static final byte[] EMPTY_LEVEL_CHUNK_DATA; @@ -86,9 +105,25 @@ public class TranslatorsInit { Registry.registerJava(ServerEntityTeleportPacket.class, new JavaEntityTeleportTranslator()); Registry.registerJava(ServerEntityVelocityPacket.class, new JavaEntityVelocityTranslator()); Registry.registerJava(ServerNotifyClientPacket.class, new JavaNotifyClientTranslator()); + Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator()); + Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator()); + Registry.registerJava(ServerSetSlotPacket.class, new JavaSetSlotTranslator()); Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator()); Registry.registerBedrock(CommandRequestPacket.class, new BedrockCommandRequestTranslator()); Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator()); + + itemTranslator = new ItemTranslator(); + + registerInventoryTranslators(); + } + + private static void registerInventoryTranslators() { + inventoryTranslators.put(WindowType.GENERIC_9X1, new GenericInventoryTranslator()); + inventoryTranslators.put(WindowType.GENERIC_9X2, new GenericInventoryTranslator()); + inventoryTranslators.put(WindowType.GENERIC_9X3, new GenericInventoryTranslator()); + inventoryTranslators.put(WindowType.GENERIC_9X4, new GenericInventoryTranslator()); + inventoryTranslators.put(WindowType.GENERIC_9X5, new GenericInventoryTranslator()); + inventoryTranslators.put(WindowType.GENERIC_9X6, new GenericInventoryTranslator()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java new file mode 100644 index 000000000..b6f36ac05 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 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.inventory; + +import com.flowpowered.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.utils.InventoryUtils; + +public class GenericInventoryTranslator extends InventoryTranslator { + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + // TODO: Add code here + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) 0); + containerOpenPacket.setBlockPosition(new Vector3i(0, 0, 0)); + session.getUpstream().sendPacket(containerOpenPacket); + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + ContainerId containerId = InventoryUtils.getContainerId(inventory.getId()); + if (containerId == null) + return; + + ItemData[] bedrockItems = new ItemData[inventory.getItems().length]; + for (int i = 0; i < bedrockItems.length; i++) { + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } + + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(containerId); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + ContainerId containerId = InventoryUtils.getContainerId(inventory.getId()); + if (containerId == null) + return; + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(containerId); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot])); + slotPacket.setInventorySlot(slot); + session.getUpstream().sendPacket(slotPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java new file mode 100644 index 000000000..0e244d3b3 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 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.inventory; + +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; + +public abstract class InventoryTranslator { + + public abstract void prepareInventory(GeyserSession session, Inventory inventory); + public abstract void openInventory(GeyserSession session, Inventory inventory); + public abstract void updateInventory(GeyserSession session, Inventory inventory); + public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot); + +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/BedrockItem.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/BedrockItem.java new file mode 100644 index 000000000..2537e5648 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/BedrockItem.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 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.item; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class BedrockItem { + + private String identifier; + private int id; + private int data; +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java new file mode 100644 index 000000000..c46c6ab4b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2019 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.item; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.DoubleTag; +import com.github.steveice10.opennbt.tag.builtin.FloatTag; +import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; +import com.github.steveice10.opennbt.tag.builtin.LongTag; +import com.github.steveice10.opennbt.tag.builtin.ShortTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; +import org.geysermc.connector.utils.Toolbox; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ItemTranslator { + + private static Map identifiers = new HashMap(); + + static { + // Key: java translation + // Value: bedrock translation + identifiers.put("grass_block", "grass"); + identifiers.put("granite", "stone:1"); + identifiers.put("polished_granite", "stone:2"); + identifiers.put("diorite", "stone:3"); + identifiers.put("polished_diorite", "stone:4"); + identifiers.put("andesite", "stone:5"); + identifiers.put("polished_andesite", "stone:6"); + identifiers.put("spurce_log", "log:1"); + identifiers.put("birch_log", "log:2"); + identifiers.put("jungle_log", "log:3"); + identifiers.put("acacia_log", "log:4"); + identifiers.put("dark_oak_log", "log:5"); + } + + public ItemStack translateToJava(ItemData data) { + JavaItem javaItem = getJavaItem(data); + + if (data.getTag() == null) { + return new ItemStack(javaItem.getId(), data.getCount()); + } + return new ItemStack(javaItem.getId(), data.getCount(), translateToJavaNBT(data.getTag())); + } + + public ItemData translateToBedrock(ItemStack stack) { + // Most likely air if null + if (stack == null) { + return ItemData.AIR; + } + + BedrockItem bedrockItem = getBedrockItem(stack); + if (stack.getNBT() == null) { + return ItemData.of(bedrockItem.getId(), (short) bedrockItem.getData(), stack.getAmount()); + } + return ItemData.of(bedrockItem.getId(), (short) bedrockItem.getData(), stack.getAmount(), translateToBedrockNBT(stack.getNBT())); + } + + public BedrockItem getBedrockItem(ItemStack stack) { + for (Map.Entry javaItems : Toolbox.JAVA_ITEMS.entrySet()) { + if (javaItems.getValue().getId() != stack.getId()) + continue; + + JavaItem javaItem = javaItems.getValue(); + String identifier = getBedrockIdentifier(javaItem.getIdentifier().replace("minecraft:", "")); + if (!Toolbox.BEDROCK_ITEMS.containsKey(identifier)) + continue; + + return Toolbox.BEDROCK_ITEMS.get(identifier); + } + + return new BedrockItem("minecraft:air", 0, 0); + } + + public JavaItem getJavaItem(ItemData data) { + for (Map.Entry bedrockItems : Toolbox.BEDROCK_ITEMS.entrySet()) { + if (bedrockItems.getValue().getId() != data.getId()) + continue; + + String identifier = getJavaIdentifier(bedrockItems.getKey().replace("minecraft:", "")); + if (!Toolbox.JAVA_ITEMS.containsKey(identifier)) + continue; + + return Toolbox.JAVA_ITEMS.get(identifier); + } + + return new JavaItem("minecraft:air", 0); + } + + public String getBedrockIdentifier(String javaIdentifier) { + if (!identifiers.containsKey(javaIdentifier)) + return "minecraft:" + javaIdentifier; + + return "minecraft:" + identifiers.get(javaIdentifier); + } + + public String getJavaIdentifier(String bedrockIdentifier) { + for (Map.Entry entry : identifiers.entrySet()) { + if (entry.getValue().equals(bedrockIdentifier)) { + return "minecraft:" + entry.getKey(); + } + } + + return "minecraft:" + bedrockIdentifier; + } + + private CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) { + CompoundTag javaTag = new CompoundTag(tag.getName()); + Map javaValue = javaTag.getValue(); + if (tag.getValue() != null && !tag.getValue().isEmpty()) { + for (String str : tag.getValue().keySet()) { + com.nukkitx.nbt.tag.Tag bedrockTag = tag.get(str); + Tag translatedTag = translateToJavaNBT(bedrockTag); + if (translatedTag == null) + continue; + + javaValue.put(str, translatedTag); + } + } + + return javaTag; + } + + private Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag tag) { + if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) { + com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag; + return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.ByteTag) { + com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag; + return new ByteTag(byteTag.getName(), byteTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) { + com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag; + return new DoubleTag(doubleTag.getName(), doubleTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.FloatTag) { + com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag; + return new FloatTag(floatTag.getName(), floatTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) { + com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag; + return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.IntTag) { + com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag; + return new IntTag(intTag.getName(), intTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) { + com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag; + return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.LongTag) { + com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag; + return new LongTag(longTag.getName(), longTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.ShortTag) { + com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag; + return new ShortTag(shortTag.getName(), shortTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.StringTag) { + com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag; + return new StringTag(stringTag.getName(), stringTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.ListTag) { + com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag; + + List tags = new ArrayList(); + for (Object value : listTag.getValue()) { + if (!(value instanceof com.nukkitx.nbt.tag.Tag)) + continue; + + com.nukkitx.nbt.tag.Tag tagValue = (com.nukkitx.nbt.tag.Tag) value; + Tag javaTag = translateToJavaNBT(tagValue); + if (javaTag != null) + tags.add(javaTag); + } + return new ListTag(listTag.getName(), tags); + } + + if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) { + return translateToJavaNBT((com.nukkitx.nbt.tag.CompoundTag) tag); + } + + return null; + } + + private com.nukkitx.nbt.tag.CompoundTag translateToBedrockNBT(CompoundTag tag) { + Map> javaValue = new HashMap>(); + if (tag.getValue() != null && !tag.getValue().isEmpty()) { + for (String str : tag.getValue().keySet()) { + Tag javaTag = tag.get(str); + com.nukkitx.nbt.tag.Tag translatedTag = translateToBedrockNBT(javaTag); + if (translatedTag == null) + continue; + + javaValue.put(str, translatedTag); + } + } + + com.nukkitx.nbt.tag.CompoundTag bedrockTag = new com.nukkitx.nbt.tag.CompoundTag(tag.getName(), javaValue); + return bedrockTag; + } + + private com.nukkitx.nbt.tag.Tag translateToBedrockNBT(Tag tag) { + if (tag instanceof ByteArrayTag) { + ByteArrayTag byteArrayTag = (ByteArrayTag) tag; + return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); + } + + if (tag instanceof ByteTag) { + ByteTag byteTag = (ByteTag) tag; + return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue()); + } + + if (tag instanceof DoubleTag) { + DoubleTag doubleTag = (DoubleTag) tag; + return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue()); + } + + if (tag instanceof FloatTag) { + FloatTag floatTag = (FloatTag) tag; + return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue()); + } + + if (tag instanceof IntArrayTag) { + IntArrayTag intArrayTag = (IntArrayTag) tag; + return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); + } + + if (tag instanceof IntTag) { + IntTag intTag = (IntTag) tag; + return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue()); + } + + if (tag instanceof LongArrayTag) { + LongArrayTag longArrayTag = (LongArrayTag) tag; + return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); + } + + if (tag instanceof LongTag) { + LongTag longTag = (LongTag) tag; + return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue()); + } + + if (tag instanceof ShortTag) { + ShortTag shortTag = (ShortTag) tag; + return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue()); + } + + if (tag instanceof StringTag) { + StringTag stringTag = (StringTag) tag; + return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), stringTag.getValue()); + } + + if (tag instanceof ListTag) { + ListTag listTag = (ListTag) tag; + + List tags = new ArrayList(); + for (Object value : listTag.getValue()) { + if (!(value instanceof Tag)) + continue; + + Tag tagValue = (Tag) value; + com.nukkitx.nbt.tag.Tag bedrockTag = translateToBedrockNBT(tagValue); + if (bedrockTag != null) + tags.add(bedrockTag); + } + // TODO: Fix unchecked call here + return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), listTag.getElementType(), tags); + } + + if (tag instanceof CompoundTag) { + return translateToBedrockNBT((CompoundTag) tag); + } + + return null; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/JavaItem.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/JavaItem.java new file mode 100644 index 000000000..174ed52c1 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/JavaItem.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 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.item; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class JavaItem { + + private String identifier; + private int id; +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaOpenWindowTranslator.java new file mode 100644 index 000000000..a2049e62c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaOpenWindowTranslator.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 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.java; + +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +public class JavaOpenWindowTranslator extends PacketTranslator { + + @Override + public void translate(ServerOpenWindowPacket packet, GeyserSession session) { + InventoryUtils.openInventory(session, packet); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaSetSlotTranslator.java new file mode 100644 index 000000000..fb643e2c4 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaSetSlotTranslator.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 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.java; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.cache.InventoryCache; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +public class JavaSetSlotTranslator extends PacketTranslator { + + @Override + public void translate(ServerSetSlotPacket packet, GeyserSession session) { + InventoryCache inventoryCache = session.getInventoryCache(); + if (!inventoryCache.getInventories().containsKey(packet.getWindowId())) { + inventoryCache.cachePacket(packet.getWindowId(), packet); + return; + } + + Inventory inventory = inventoryCache.getInventories().get(packet.getWindowId()); + if (packet.getWindowId() != 0 && inventory.getWindowType() == null) + return; + + // Player inventory + if (packet.getWindowId() == 0) { + if (packet.getSlot() >= inventory.getItems().length) + return; // Most likely not a player inventory + + ItemStack[] items = inventory.getItems(); + items[packet.getSlot()] = packet.getItem(); + inventory.setItems(items); + + InventoryUtils.refreshPlayerInventory(session, inventory); + + if (inventory.isOpen()) { + InventoryUtils.updateSlot(session, packet); + } else { + inventoryCache.cachePacket(packet.getWindowId(), packet); + } + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaWindowItemsTranslator.java new file mode 100644 index 000000000..b22a2a476 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaWindowItemsTranslator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 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.java; + +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.cache.InventoryCache; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +public class JavaWindowItemsTranslator extends PacketTranslator { + + @Override + public void translate(ServerWindowItemsPacket packet, GeyserSession session) { + InventoryCache inventoryCache = session.getInventoryCache(); + if (!inventoryCache.getInventories().containsKey(packet.getWindowId())) { + inventoryCache.cachePacket(packet.getWindowId(), packet); + return; + } + + Inventory inventory = inventoryCache.getInventories().get(packet.getWindowId()); + // Player inventory + if (packet.getWindowId() == 0) { + inventory.setItems(packet.getItems()); + InventoryUtils.refreshPlayerInventory(session, inventory); + return; + } + + InventoryUtils.updateInventory(session, packet); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java new file mode 100644 index 000000000..e1bb2c441 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -0,0 +1,122 @@ +package org.geysermc.connector.utils; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket; +import com.github.steveice10.packetlib.packet.Packet; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import org.geysermc.api.Geyser; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class InventoryUtils { + + public static void refreshPlayerInventory(GeyserSession session, Inventory inventory) { + InventoryContentPacket inventoryContentPacket = new InventoryContentPacket(); + inventoryContentPacket.setContainerId(ContainerId.INVENTORY); + + ItemData[] contents = new ItemData[40]; + // Inventory + for (int i = 9; i < 36; i++) { + contents[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } + + // Hotbar + for (int i = 36; i < 45; i++) { + contents[i - 36] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } + + // Armor + for (int i = 5; i < 9; i++) { + contents[i + 31] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } + + inventoryContentPacket.setContents(contents); + session.getUpstream().sendPacket(inventoryContentPacket); + } + + public static void openInventory(GeyserSession session, ServerOpenWindowPacket packet) { + Inventory inventory = new Inventory(packet.getWindowId(), packet.getType(), 45); // TODO: Find a way to set this value + session.getInventoryCache().getInventories().put(packet.getWindowId(), inventory); + session.getInventoryCache().setOpenInventory(inventory); + + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + translator.prepareInventory(session, inventory); + Geyser.getGeneralThreadPool().schedule(() -> { + List packets = session.getInventoryCache().getCachedPackets().get(inventory.getId()); + packets.forEach(itemPacket -> { + if (itemPacket != null) { + if (ServerWindowItemsPacket.class.isAssignableFrom(itemPacket.getClass())) { + updateInventory(session, (ServerWindowItemsPacket) itemPacket); + } + } + }); + }, 200, TimeUnit.MILLISECONDS); + } + + public static void updateInventory(GeyserSession session, ServerWindowItemsPacket packet) { + if (packet.getWindowId() == 0) + return; + + if (session.getInventoryCache().getOpenInventory() == null || !session.getInventoryCache().getInventories().containsKey(packet.getWindowId())) + return; + + Inventory openInventory = session.getInventoryCache().getOpenInventory(); + if (packet.getWindowId() != openInventory.getId()) + return; + + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(openInventory.getWindowType()); + if (translator == null) { + session.getDownstream().getSession().send(new ClientCloseWindowPacket(packet.getWindowId())); + return; + } + + openInventory.setItems(packet.getItems()); + translator.updateInventory(session, openInventory); + } + + public static void updateSlot(GeyserSession session, ServerSetSlotPacket packet) { + if (packet.getWindowId() == 0) + return; + + if (session.getInventoryCache().getOpenInventory() == null || !session.getInventoryCache().getInventories().containsKey(packet.getWindowId())) + return; + + Inventory openInventory = session.getInventoryCache().getOpenInventory(); + if (packet.getWindowId() != openInventory.getId()) + return; + + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(openInventory.getWindowType()); + if (translator == null) { + session.getDownstream().getSession().send(new ClientCloseWindowPacket(packet.getWindowId())); + return; + } + + if (packet.getSlot() >= openInventory.getSize()) { + session.getDownstream().getSession().send(new ClientCloseWindowPacket(packet.getWindowId())); + return; + } + + ItemStack[] items = openInventory.getItems(); + items[packet.getSlot()] = packet.getItem(); + translator.updateSlot(session, openInventory, packet.getSlot()); + } + + public static ContainerId getContainerId(int id) { + for (ContainerId value : ContainerId.values()) { + if (value.id() == id) + return value; + } + + return null; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java index 4a54bb018..20126e3dc 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -1,11 +1,14 @@ package org.geysermc.connector.utils; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.nukkitx.network.VarInts; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.v361.BedrockUtils; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import org.geysermc.connector.network.translators.item.BedrockItem; +import org.geysermc.connector.network.translators.item.JavaItem; import java.io.InputStream; import java.util.*; @@ -23,6 +26,16 @@ public class Toolbox { e.printStackTrace(); } + Map bedrockItems = new HashMap(); + for (Map e : entries) { + BedrockItem bedrockItem = new BedrockItem((String) e.get("name"), (int) e.get("id"), (int) e.get("data")); + if (bedrockItem.getData() != 0) { + bedrockItems.put(bedrockItem.getIdentifier() + ":" + bedrockItem.getData(), bedrockItem); + } else { + bedrockItems.put(bedrockItem.getIdentifier(), bedrockItem); + } + } + ByteBuf b = Unpooled.buffer(); VarInts.writeUnsignedInt(b, entries.size()); for (Map e : entries) { @@ -46,17 +59,43 @@ public class Toolbox { e.printStackTrace(); } - ArrayList l = new ArrayList<>(); + List l = new ArrayList<>(); for (HashMap e : s) { l.add(new StartGamePacket.ItemEntry((String) e.get("name"), (short) ((int) e.get("id")))); + if (!bedrockItems.containsKey(e.get("name"))) { + BedrockItem bedrockItem = new BedrockItem((String) e.get("name"), ((int) e.get("id")), 0); + bedrockItems.put(bedrockItem.getIdentifier(), bedrockItem); + } } ITEMS = l; + + BEDROCK_ITEMS = bedrockItems; + + InputStream javaItemStream = Toolbox.class.getClassLoader().getResourceAsStream("java_items.json"); + ObjectMapper javaItemMapper = new ObjectMapper(); + Map javaItemList = new HashMap(); + try { + javaItemList = javaItemMapper.readValue(javaItemStream, new TypeReference>(){}); + } catch (Exception ex) { + ex.printStackTrace(); + } + + Map javaItems = new HashMap(); + + for (String str : javaItemList.keySet()) { + javaItems.put(str, new JavaItem(str, (int) javaItemList.get(str).get("protocol_id"))); + } + + JAVA_ITEMS = javaItems; } public static final Collection ITEMS; public static final ByteBuf CACHED_PALLETE; + public static final Map BEDROCK_ITEMS; + public static final Map JAVA_ITEMS; + //public static final byte[] EMPTY_CHUNK; } \ No newline at end of file diff --git a/connector/src/main/resources/java_items.json b/connector/src/main/resources/java_items.json new file mode 100644 index 000000000..a205144cc --- /dev/null +++ b/connector/src/main/resources/java_items.json @@ -0,0 +1,2633 @@ +{ + "minecraft:air": { + "protocol_id": 0 + }, + "minecraft:stone": { + "protocol_id": 1 + }, + "minecraft:granite": { + "protocol_id": 2 + }, + "minecraft:polished_granite": { + "protocol_id": 3 + }, + "minecraft:diorite": { + "protocol_id": 4 + }, + "minecraft:polished_diorite": { + "protocol_id": 5 + }, + "minecraft:andesite": { + "protocol_id": 6 + }, + "minecraft:polished_andesite": { + "protocol_id": 7 + }, + "minecraft:grass_block": { + "protocol_id": 8 + }, + "minecraft:dirt": { + "protocol_id": 9 + }, + "minecraft:coarse_dirt": { + "protocol_id": 10 + }, + "minecraft:podzol": { + "protocol_id": 11 + }, + "minecraft:cobblestone": { + "protocol_id": 12 + }, + "minecraft:oak_planks": { + "protocol_id": 13 + }, + "minecraft:spruce_planks": { + "protocol_id": 14 + }, + "minecraft:birch_planks": { + "protocol_id": 15 + }, + "minecraft:jungle_planks": { + "protocol_id": 16 + }, + "minecraft:acacia_planks": { + "protocol_id": 17 + }, + "minecraft:dark_oak_planks": { + "protocol_id": 18 + }, + "minecraft:oak_sapling": { + "protocol_id": 19 + }, + "minecraft:spruce_sapling": { + "protocol_id": 20 + }, + "minecraft:birch_sapling": { + "protocol_id": 21 + }, + "minecraft:jungle_sapling": { + "protocol_id": 22 + }, + "minecraft:acacia_sapling": { + "protocol_id": 23 + }, + "minecraft:dark_oak_sapling": { + "protocol_id": 24 + }, + "minecraft:bedrock": { + "protocol_id": 25 + }, + "minecraft:sand": { + "protocol_id": 26 + }, + "minecraft:red_sand": { + "protocol_id": 27 + }, + "minecraft:gravel": { + "protocol_id": 28 + }, + "minecraft:gold_ore": { + "protocol_id": 29 + }, + "minecraft:iron_ore": { + "protocol_id": 30 + }, + "minecraft:coal_ore": { + "protocol_id": 31 + }, + "minecraft:oak_log": { + "protocol_id": 32 + }, + "minecraft:spruce_log": { + "protocol_id": 33 + }, + "minecraft:birch_log": { + "protocol_id": 34 + }, + "minecraft:jungle_log": { + "protocol_id": 35 + }, + "minecraft:acacia_log": { + "protocol_id": 36 + }, + "minecraft:dark_oak_log": { + "protocol_id": 37 + }, + "minecraft:stripped_oak_log": { + "protocol_id": 38 + }, + "minecraft:stripped_spruce_log": { + "protocol_id": 39 + }, + "minecraft:stripped_birch_log": { + "protocol_id": 40 + }, + "minecraft:stripped_jungle_log": { + "protocol_id": 41 + }, + "minecraft:stripped_acacia_log": { + "protocol_id": 42 + }, + "minecraft:stripped_dark_oak_log": { + "protocol_id": 43 + }, + "minecraft:stripped_oak_wood": { + "protocol_id": 44 + }, + "minecraft:stripped_spruce_wood": { + "protocol_id": 45 + }, + "minecraft:stripped_birch_wood": { + "protocol_id": 46 + }, + "minecraft:stripped_jungle_wood": { + "protocol_id": 47 + }, + "minecraft:stripped_acacia_wood": { + "protocol_id": 48 + }, + "minecraft:stripped_dark_oak_wood": { + "protocol_id": 49 + }, + "minecraft:oak_wood": { + "protocol_id": 50 + }, + "minecraft:spruce_wood": { + "protocol_id": 51 + }, + "minecraft:birch_wood": { + "protocol_id": 52 + }, + "minecraft:jungle_wood": { + "protocol_id": 53 + }, + "minecraft:acacia_wood": { + "protocol_id": 54 + }, + "minecraft:dark_oak_wood": { + "protocol_id": 55 + }, + "minecraft:oak_leaves": { + "protocol_id": 56 + }, + "minecraft:spruce_leaves": { + "protocol_id": 57 + }, + "minecraft:birch_leaves": { + "protocol_id": 58 + }, + "minecraft:jungle_leaves": { + "protocol_id": 59 + }, + "minecraft:acacia_leaves": { + "protocol_id": 60 + }, + "minecraft:dark_oak_leaves": { + "protocol_id": 61 + }, + "minecraft:sponge": { + "protocol_id": 62 + }, + "minecraft:wet_sponge": { + "protocol_id": 63 + }, + "minecraft:glass": { + "protocol_id": 64 + }, + "minecraft:lapis_ore": { + "protocol_id": 65 + }, + "minecraft:lapis_block": { + "protocol_id": 66 + }, + "minecraft:dispenser": { + "protocol_id": 67 + }, + "minecraft:sandstone": { + "protocol_id": 68 + }, + "minecraft:chiseled_sandstone": { + "protocol_id": 69 + }, + "minecraft:cut_sandstone": { + "protocol_id": 70 + }, + "minecraft:note_block": { + "protocol_id": 71 + }, + "minecraft:powered_rail": { + "protocol_id": 72 + }, + "minecraft:detector_rail": { + "protocol_id": 73 + }, + "minecraft:sticky_piston": { + "protocol_id": 74 + }, + "minecraft:cobweb": { + "protocol_id": 75 + }, + "minecraft:grass": { + "protocol_id": 76 + }, + "minecraft:fern": { + "protocol_id": 77 + }, + "minecraft:dead_bush": { + "protocol_id": 78 + }, + "minecraft:seagrass": { + "protocol_id": 79 + }, + "minecraft:sea_pickle": { + "protocol_id": 80 + }, + "minecraft:piston": { + "protocol_id": 81 + }, + "minecraft:white_wool": { + "protocol_id": 82 + }, + "minecraft:orange_wool": { + "protocol_id": 83 + }, + "minecraft:magenta_wool": { + "protocol_id": 84 + }, + "minecraft:light_blue_wool": { + "protocol_id": 85 + }, + "minecraft:yellow_wool": { + "protocol_id": 86 + }, + "minecraft:lime_wool": { + "protocol_id": 87 + }, + "minecraft:pink_wool": { + "protocol_id": 88 + }, + "minecraft:gray_wool": { + "protocol_id": 89 + }, + "minecraft:light_gray_wool": { + "protocol_id": 90 + }, + "minecraft:cyan_wool": { + "protocol_id": 91 + }, + "minecraft:purple_wool": { + "protocol_id": 92 + }, + "minecraft:blue_wool": { + "protocol_id": 93 + }, + "minecraft:brown_wool": { + "protocol_id": 94 + }, + "minecraft:green_wool": { + "protocol_id": 95 + }, + "minecraft:red_wool": { + "protocol_id": 96 + }, + "minecraft:black_wool": { + "protocol_id": 97 + }, + "minecraft:dandelion": { + "protocol_id": 98 + }, + "minecraft:poppy": { + "protocol_id": 99 + }, + "minecraft:blue_orchid": { + "protocol_id": 100 + }, + "minecraft:allium": { + "protocol_id": 101 + }, + "minecraft:azure_bluet": { + "protocol_id": 102 + }, + "minecraft:red_tulip": { + "protocol_id": 103 + }, + "minecraft:orange_tulip": { + "protocol_id": 104 + }, + "minecraft:white_tulip": { + "protocol_id": 105 + }, + "minecraft:pink_tulip": { + "protocol_id": 106 + }, + "minecraft:oxeye_daisy": { + "protocol_id": 107 + }, + "minecraft:cornflower": { + "protocol_id": 108 + }, + "minecraft:lily_of_the_valley": { + "protocol_id": 109 + }, + "minecraft:wither_rose": { + "protocol_id": 110 + }, + "minecraft:brown_mushroom": { + "protocol_id": 111 + }, + "minecraft:red_mushroom": { + "protocol_id": 112 + }, + "minecraft:gold_block": { + "protocol_id": 113 + }, + "minecraft:iron_block": { + "protocol_id": 114 + }, + "minecraft:oak_slab": { + "protocol_id": 115 + }, + "minecraft:spruce_slab": { + "protocol_id": 116 + }, + "minecraft:birch_slab": { + "protocol_id": 117 + }, + "minecraft:jungle_slab": { + "protocol_id": 118 + }, + "minecraft:acacia_slab": { + "protocol_id": 119 + }, + "minecraft:dark_oak_slab": { + "protocol_id": 120 + }, + "minecraft:stone_slab": { + "protocol_id": 121 + }, + "minecraft:smooth_stone_slab": { + "protocol_id": 122 + }, + "minecraft:sandstone_slab": { + "protocol_id": 123 + }, + "minecraft:cut_sandstone_slab": { + "protocol_id": 124 + }, + "minecraft:petrified_oak_slab": { + "protocol_id": 125 + }, + "minecraft:cobblestone_slab": { + "protocol_id": 126 + }, + "minecraft:brick_slab": { + "protocol_id": 127 + }, + "minecraft:stone_brick_slab": { + "protocol_id": 128 + }, + "minecraft:nether_brick_slab": { + "protocol_id": 129 + }, + "minecraft:quartz_slab": { + "protocol_id": 130 + }, + "minecraft:red_sandstone_slab": { + "protocol_id": 131 + }, + "minecraft:cut_red_sandstone_slab": { + "protocol_id": 132 + }, + "minecraft:purpur_slab": { + "protocol_id": 133 + }, + "minecraft:prismarine_slab": { + "protocol_id": 134 + }, + "minecraft:prismarine_brick_slab": { + "protocol_id": 135 + }, + "minecraft:dark_prismarine_slab": { + "protocol_id": 136 + }, + "minecraft:smooth_quartz": { + "protocol_id": 137 + }, + "minecraft:smooth_red_sandstone": { + "protocol_id": 138 + }, + "minecraft:smooth_sandstone": { + "protocol_id": 139 + }, + "minecraft:smooth_stone": { + "protocol_id": 140 + }, + "minecraft:bricks": { + "protocol_id": 141 + }, + "minecraft:tnt": { + "protocol_id": 142 + }, + "minecraft:bookshelf": { + "protocol_id": 143 + }, + "minecraft:mossy_cobblestone": { + "protocol_id": 144 + }, + "minecraft:obsidian": { + "protocol_id": 145 + }, + "minecraft:torch": { + "protocol_id": 146 + }, + "minecraft:end_rod": { + "protocol_id": 147 + }, + "minecraft:chorus_plant": { + "protocol_id": 148 + }, + "minecraft:chorus_flower": { + "protocol_id": 149 + }, + "minecraft:purpur_block": { + "protocol_id": 150 + }, + "minecraft:purpur_pillar": { + "protocol_id": 151 + }, + "minecraft:purpur_stairs": { + "protocol_id": 152 + }, + "minecraft:spawner": { + "protocol_id": 153 + }, + "minecraft:oak_stairs": { + "protocol_id": 154 + }, + "minecraft:chest": { + "protocol_id": 155 + }, + "minecraft:diamond_ore": { + "protocol_id": 156 + }, + "minecraft:diamond_block": { + "protocol_id": 157 + }, + "minecraft:crafting_table": { + "protocol_id": 158 + }, + "minecraft:farmland": { + "protocol_id": 159 + }, + "minecraft:furnace": { + "protocol_id": 160 + }, + "minecraft:ladder": { + "protocol_id": 161 + }, + "minecraft:rail": { + "protocol_id": 162 + }, + "minecraft:cobblestone_stairs": { + "protocol_id": 163 + }, + "minecraft:lever": { + "protocol_id": 164 + }, + "minecraft:stone_pressure_plate": { + "protocol_id": 165 + }, + "minecraft:oak_pressure_plate": { + "protocol_id": 166 + }, + "minecraft:spruce_pressure_plate": { + "protocol_id": 167 + }, + "minecraft:birch_pressure_plate": { + "protocol_id": 168 + }, + "minecraft:jungle_pressure_plate": { + "protocol_id": 169 + }, + "minecraft:acacia_pressure_plate": { + "protocol_id": 170 + }, + "minecraft:dark_oak_pressure_plate": { + "protocol_id": 171 + }, + "minecraft:redstone_ore": { + "protocol_id": 172 + }, + "minecraft:redstone_torch": { + "protocol_id": 173 + }, + "minecraft:stone_button": { + "protocol_id": 174 + }, + "minecraft:snow": { + "protocol_id": 175 + }, + "minecraft:ice": { + "protocol_id": 176 + }, + "minecraft:snow_block": { + "protocol_id": 177 + }, + "minecraft:cactus": { + "protocol_id": 178 + }, + "minecraft:clay": { + "protocol_id": 179 + }, + "minecraft:jukebox": { + "protocol_id": 180 + }, + "minecraft:oak_fence": { + "protocol_id": 181 + }, + "minecraft:spruce_fence": { + "protocol_id": 182 + }, + "minecraft:birch_fence": { + "protocol_id": 183 + }, + "minecraft:jungle_fence": { + "protocol_id": 184 + }, + "minecraft:acacia_fence": { + "protocol_id": 185 + }, + "minecraft:dark_oak_fence": { + "protocol_id": 186 + }, + "minecraft:pumpkin": { + "protocol_id": 187 + }, + "minecraft:carved_pumpkin": { + "protocol_id": 188 + }, + "minecraft:netherrack": { + "protocol_id": 189 + }, + "minecraft:soul_sand": { + "protocol_id": 190 + }, + "minecraft:glowstone": { + "protocol_id": 191 + }, + "minecraft:jack_o_lantern": { + "protocol_id": 192 + }, + "minecraft:oak_trapdoor": { + "protocol_id": 193 + }, + "minecraft:spruce_trapdoor": { + "protocol_id": 194 + }, + "minecraft:birch_trapdoor": { + "protocol_id": 195 + }, + "minecraft:jungle_trapdoor": { + "protocol_id": 196 + }, + "minecraft:acacia_trapdoor": { + "protocol_id": 197 + }, + "minecraft:dark_oak_trapdoor": { + "protocol_id": 198 + }, + "minecraft:infested_stone": { + "protocol_id": 199 + }, + "minecraft:infested_cobblestone": { + "protocol_id": 200 + }, + "minecraft:infested_stone_bricks": { + "protocol_id": 201 + }, + "minecraft:infested_mossy_stone_bricks": { + "protocol_id": 202 + }, + "minecraft:infested_cracked_stone_bricks": { + "protocol_id": 203 + }, + "minecraft:infested_chiseled_stone_bricks": { + "protocol_id": 204 + }, + "minecraft:stone_bricks": { + "protocol_id": 205 + }, + "minecraft:mossy_stone_bricks": { + "protocol_id": 206 + }, + "minecraft:cracked_stone_bricks": { + "protocol_id": 207 + }, + "minecraft:chiseled_stone_bricks": { + "protocol_id": 208 + }, + "minecraft:brown_mushroom_block": { + "protocol_id": 209 + }, + "minecraft:red_mushroom_block": { + "protocol_id": 210 + }, + "minecraft:mushroom_stem": { + "protocol_id": 211 + }, + "minecraft:iron_bars": { + "protocol_id": 212 + }, + "minecraft:glass_pane": { + "protocol_id": 213 + }, + "minecraft:melon": { + "protocol_id": 214 + }, + "minecraft:vine": { + "protocol_id": 215 + }, + "minecraft:oak_fence_gate": { + "protocol_id": 216 + }, + "minecraft:spruce_fence_gate": { + "protocol_id": 217 + }, + "minecraft:birch_fence_gate": { + "protocol_id": 218 + }, + "minecraft:jungle_fence_gate": { + "protocol_id": 219 + }, + "minecraft:acacia_fence_gate": { + "protocol_id": 220 + }, + "minecraft:dark_oak_fence_gate": { + "protocol_id": 221 + }, + "minecraft:brick_stairs": { + "protocol_id": 222 + }, + "minecraft:stone_brick_stairs": { + "protocol_id": 223 + }, + "minecraft:mycelium": { + "protocol_id": 224 + }, + "minecraft:lily_pad": { + "protocol_id": 225 + }, + "minecraft:nether_bricks": { + "protocol_id": 226 + }, + "minecraft:nether_brick_fence": { + "protocol_id": 227 + }, + "minecraft:nether_brick_stairs": { + "protocol_id": 228 + }, + "minecraft:enchanting_table": { + "protocol_id": 229 + }, + "minecraft:end_portal_frame": { + "protocol_id": 230 + }, + "minecraft:end_stone": { + "protocol_id": 231 + }, + "minecraft:end_stone_bricks": { + "protocol_id": 232 + }, + "minecraft:dragon_egg": { + "protocol_id": 233 + }, + "minecraft:redstone_lamp": { + "protocol_id": 234 + }, + "minecraft:sandstone_stairs": { + "protocol_id": 235 + }, + "minecraft:emerald_ore": { + "protocol_id": 236 + }, + "minecraft:ender_chest": { + "protocol_id": 237 + }, + "minecraft:tripwire_hook": { + "protocol_id": 238 + }, + "minecraft:emerald_block": { + "protocol_id": 239 + }, + "minecraft:spruce_stairs": { + "protocol_id": 240 + }, + "minecraft:birch_stairs": { + "protocol_id": 241 + }, + "minecraft:jungle_stairs": { + "protocol_id": 242 + }, + "minecraft:command_block": { + "protocol_id": 243 + }, + "minecraft:beacon": { + "protocol_id": 244 + }, + "minecraft:cobblestone_wall": { + "protocol_id": 245 + }, + "minecraft:mossy_cobblestone_wall": { + "protocol_id": 246 + }, + "minecraft:brick_wall": { + "protocol_id": 247 + }, + "minecraft:prismarine_wall": { + "protocol_id": 248 + }, + "minecraft:red_sandstone_wall": { + "protocol_id": 249 + }, + "minecraft:mossy_stone_brick_wall": { + "protocol_id": 250 + }, + "minecraft:granite_wall": { + "protocol_id": 251 + }, + "minecraft:stone_brick_wall": { + "protocol_id": 252 + }, + "minecraft:nether_brick_wall": { + "protocol_id": 253 + }, + "minecraft:andesite_wall": { + "protocol_id": 254 + }, + "minecraft:red_nether_brick_wall": { + "protocol_id": 255 + }, + "minecraft:sandstone_wall": { + "protocol_id": 256 + }, + "minecraft:end_stone_brick_wall": { + "protocol_id": 257 + }, + "minecraft:diorite_wall": { + "protocol_id": 258 + }, + "minecraft:oak_button": { + "protocol_id": 259 + }, + "minecraft:spruce_button": { + "protocol_id": 260 + }, + "minecraft:birch_button": { + "protocol_id": 261 + }, + "minecraft:jungle_button": { + "protocol_id": 262 + }, + "minecraft:acacia_button": { + "protocol_id": 263 + }, + "minecraft:dark_oak_button": { + "protocol_id": 264 + }, + "minecraft:anvil": { + "protocol_id": 265 + }, + "minecraft:chipped_anvil": { + "protocol_id": 266 + }, + "minecraft:damaged_anvil": { + "protocol_id": 267 + }, + "minecraft:trapped_chest": { + "protocol_id": 268 + }, + "minecraft:light_weighted_pressure_plate": { + "protocol_id": 269 + }, + "minecraft:heavy_weighted_pressure_plate": { + "protocol_id": 270 + }, + "minecraft:daylight_detector": { + "protocol_id": 271 + }, + "minecraft:redstone_block": { + "protocol_id": 272 + }, + "minecraft:nether_quartz_ore": { + "protocol_id": 273 + }, + "minecraft:hopper": { + "protocol_id": 274 + }, + "minecraft:chiseled_quartz_block": { + "protocol_id": 275 + }, + "minecraft:quartz_block": { + "protocol_id": 276 + }, + "minecraft:quartz_pillar": { + "protocol_id": 277 + }, + "minecraft:quartz_stairs": { + "protocol_id": 278 + }, + "minecraft:activator_rail": { + "protocol_id": 279 + }, + "minecraft:dropper": { + "protocol_id": 280 + }, + "minecraft:white_terracotta": { + "protocol_id": 281 + }, + "minecraft:orange_terracotta": { + "protocol_id": 282 + }, + "minecraft:magenta_terracotta": { + "protocol_id": 283 + }, + "minecraft:light_blue_terracotta": { + "protocol_id": 284 + }, + "minecraft:yellow_terracotta": { + "protocol_id": 285 + }, + "minecraft:lime_terracotta": { + "protocol_id": 286 + }, + "minecraft:pink_terracotta": { + "protocol_id": 287 + }, + "minecraft:gray_terracotta": { + "protocol_id": 288 + }, + "minecraft:light_gray_terracotta": { + "protocol_id": 289 + }, + "minecraft:cyan_terracotta": { + "protocol_id": 290 + }, + "minecraft:purple_terracotta": { + "protocol_id": 291 + }, + "minecraft:blue_terracotta": { + "protocol_id": 292 + }, + "minecraft:brown_terracotta": { + "protocol_id": 293 + }, + "minecraft:green_terracotta": { + "protocol_id": 294 + }, + "minecraft:red_terracotta": { + "protocol_id": 295 + }, + "minecraft:black_terracotta": { + "protocol_id": 296 + }, + "minecraft:barrier": { + "protocol_id": 297 + }, + "minecraft:iron_trapdoor": { + "protocol_id": 298 + }, + "minecraft:hay_block": { + "protocol_id": 299 + }, + "minecraft:white_carpet": { + "protocol_id": 300 + }, + "minecraft:orange_carpet": { + "protocol_id": 301 + }, + "minecraft:magenta_carpet": { + "protocol_id": 302 + }, + "minecraft:light_blue_carpet": { + "protocol_id": 303 + }, + "minecraft:yellow_carpet": { + "protocol_id": 304 + }, + "minecraft:lime_carpet": { + "protocol_id": 305 + }, + "minecraft:pink_carpet": { + "protocol_id": 306 + }, + "minecraft:gray_carpet": { + "protocol_id": 307 + }, + "minecraft:light_gray_carpet": { + "protocol_id": 308 + }, + "minecraft:cyan_carpet": { + "protocol_id": 309 + }, + "minecraft:purple_carpet": { + "protocol_id": 310 + }, + "minecraft:blue_carpet": { + "protocol_id": 311 + }, + "minecraft:brown_carpet": { + "protocol_id": 312 + }, + "minecraft:green_carpet": { + "protocol_id": 313 + }, + "minecraft:red_carpet": { + "protocol_id": 314 + }, + "minecraft:black_carpet": { + "protocol_id": 315 + }, + "minecraft:terracotta": { + "protocol_id": 316 + }, + "minecraft:coal_block": { + "protocol_id": 317 + }, + "minecraft:packed_ice": { + "protocol_id": 318 + }, + "minecraft:acacia_stairs": { + "protocol_id": 319 + }, + "minecraft:dark_oak_stairs": { + "protocol_id": 320 + }, + "minecraft:slime_block": { + "protocol_id": 321 + }, + "minecraft:grass_path": { + "protocol_id": 322 + }, + "minecraft:sunflower": { + "protocol_id": 323 + }, + "minecraft:lilac": { + "protocol_id": 324 + }, + "minecraft:rose_bush": { + "protocol_id": 325 + }, + "minecraft:peony": { + "protocol_id": 326 + }, + "minecraft:tall_grass": { + "protocol_id": 327 + }, + "minecraft:large_fern": { + "protocol_id": 328 + }, + "minecraft:white_stained_glass": { + "protocol_id": 329 + }, + "minecraft:orange_stained_glass": { + "protocol_id": 330 + }, + "minecraft:magenta_stained_glass": { + "protocol_id": 331 + }, + "minecraft:light_blue_stained_glass": { + "protocol_id": 332 + }, + "minecraft:yellow_stained_glass": { + "protocol_id": 333 + }, + "minecraft:lime_stained_glass": { + "protocol_id": 334 + }, + "minecraft:pink_stained_glass": { + "protocol_id": 335 + }, + "minecraft:gray_stained_glass": { + "protocol_id": 336 + }, + "minecraft:light_gray_stained_glass": { + "protocol_id": 337 + }, + "minecraft:cyan_stained_glass": { + "protocol_id": 338 + }, + "minecraft:purple_stained_glass": { + "protocol_id": 339 + }, + "minecraft:blue_stained_glass": { + "protocol_id": 340 + }, + "minecraft:brown_stained_glass": { + "protocol_id": 341 + }, + "minecraft:green_stained_glass": { + "protocol_id": 342 + }, + "minecraft:red_stained_glass": { + "protocol_id": 343 + }, + "minecraft:black_stained_glass": { + "protocol_id": 344 + }, + "minecraft:white_stained_glass_pane": { + "protocol_id": 345 + }, + "minecraft:orange_stained_glass_pane": { + "protocol_id": 346 + }, + "minecraft:magenta_stained_glass_pane": { + "protocol_id": 347 + }, + "minecraft:light_blue_stained_glass_pane": { + "protocol_id": 348 + }, + "minecraft:yellow_stained_glass_pane": { + "protocol_id": 349 + }, + "minecraft:lime_stained_glass_pane": { + "protocol_id": 350 + }, + "minecraft:pink_stained_glass_pane": { + "protocol_id": 351 + }, + "minecraft:gray_stained_glass_pane": { + "protocol_id": 352 + }, + "minecraft:light_gray_stained_glass_pane": { + "protocol_id": 353 + }, + "minecraft:cyan_stained_glass_pane": { + "protocol_id": 354 + }, + "minecraft:purple_stained_glass_pane": { + "protocol_id": 355 + }, + "minecraft:blue_stained_glass_pane": { + "protocol_id": 356 + }, + "minecraft:brown_stained_glass_pane": { + "protocol_id": 357 + }, + "minecraft:green_stained_glass_pane": { + "protocol_id": 358 + }, + "minecraft:red_stained_glass_pane": { + "protocol_id": 359 + }, + "minecraft:black_stained_glass_pane": { + "protocol_id": 360 + }, + "minecraft:prismarine": { + "protocol_id": 361 + }, + "minecraft:prismarine_bricks": { + "protocol_id": 362 + }, + "minecraft:dark_prismarine": { + "protocol_id": 363 + }, + "minecraft:prismarine_stairs": { + "protocol_id": 364 + }, + "minecraft:prismarine_brick_stairs": { + "protocol_id": 365 + }, + "minecraft:dark_prismarine_stairs": { + "protocol_id": 366 + }, + "minecraft:sea_lantern": { + "protocol_id": 367 + }, + "minecraft:red_sandstone": { + "protocol_id": 368 + }, + "minecraft:chiseled_red_sandstone": { + "protocol_id": 369 + }, + "minecraft:cut_red_sandstone": { + "protocol_id": 370 + }, + "minecraft:red_sandstone_stairs": { + "protocol_id": 371 + }, + "minecraft:repeating_command_block": { + "protocol_id": 372 + }, + "minecraft:chain_command_block": { + "protocol_id": 373 + }, + "minecraft:magma_block": { + "protocol_id": 374 + }, + "minecraft:nether_wart_block": { + "protocol_id": 375 + }, + "minecraft:red_nether_bricks": { + "protocol_id": 376 + }, + "minecraft:bone_block": { + "protocol_id": 377 + }, + "minecraft:structure_void": { + "protocol_id": 378 + }, + "minecraft:observer": { + "protocol_id": 379 + }, + "minecraft:shulker_box": { + "protocol_id": 380 + }, + "minecraft:white_shulker_box": { + "protocol_id": 381 + }, + "minecraft:orange_shulker_box": { + "protocol_id": 382 + }, + "minecraft:magenta_shulker_box": { + "protocol_id": 383 + }, + "minecraft:light_blue_shulker_box": { + "protocol_id": 384 + }, + "minecraft:yellow_shulker_box": { + "protocol_id": 385 + }, + "minecraft:lime_shulker_box": { + "protocol_id": 386 + }, + "minecraft:pink_shulker_box": { + "protocol_id": 387 + }, + "minecraft:gray_shulker_box": { + "protocol_id": 388 + }, + "minecraft:light_gray_shulker_box": { + "protocol_id": 389 + }, + "minecraft:cyan_shulker_box": { + "protocol_id": 390 + }, + "minecraft:purple_shulker_box": { + "protocol_id": 391 + }, + "minecraft:blue_shulker_box": { + "protocol_id": 392 + }, + "minecraft:brown_shulker_box": { + "protocol_id": 393 + }, + "minecraft:green_shulker_box": { + "protocol_id": 394 + }, + "minecraft:red_shulker_box": { + "protocol_id": 395 + }, + "minecraft:black_shulker_box": { + "protocol_id": 396 + }, + "minecraft:white_glazed_terracotta": { + "protocol_id": 397 + }, + "minecraft:orange_glazed_terracotta": { + "protocol_id": 398 + }, + "minecraft:magenta_glazed_terracotta": { + "protocol_id": 399 + }, + "minecraft:light_blue_glazed_terracotta": { + "protocol_id": 400 + }, + "minecraft:yellow_glazed_terracotta": { + "protocol_id": 401 + }, + "minecraft:lime_glazed_terracotta": { + "protocol_id": 402 + }, + "minecraft:pink_glazed_terracotta": { + "protocol_id": 403 + }, + "minecraft:gray_glazed_terracotta": { + "protocol_id": 404 + }, + "minecraft:light_gray_glazed_terracotta": { + "protocol_id": 405 + }, + "minecraft:cyan_glazed_terracotta": { + "protocol_id": 406 + }, + "minecraft:purple_glazed_terracotta": { + "protocol_id": 407 + }, + "minecraft:blue_glazed_terracotta": { + "protocol_id": 408 + }, + "minecraft:brown_glazed_terracotta": { + "protocol_id": 409 + }, + "minecraft:green_glazed_terracotta": { + "protocol_id": 410 + }, + "minecraft:red_glazed_terracotta": { + "protocol_id": 411 + }, + "minecraft:black_glazed_terracotta": { + "protocol_id": 412 + }, + "minecraft:white_concrete": { + "protocol_id": 413 + }, + "minecraft:orange_concrete": { + "protocol_id": 414 + }, + "minecraft:magenta_concrete": { + "protocol_id": 415 + }, + "minecraft:light_blue_concrete": { + "protocol_id": 416 + }, + "minecraft:yellow_concrete": { + "protocol_id": 417 + }, + "minecraft:lime_concrete": { + "protocol_id": 418 + }, + "minecraft:pink_concrete": { + "protocol_id": 419 + }, + "minecraft:gray_concrete": { + "protocol_id": 420 + }, + "minecraft:light_gray_concrete": { + "protocol_id": 421 + }, + "minecraft:cyan_concrete": { + "protocol_id": 422 + }, + "minecraft:purple_concrete": { + "protocol_id": 423 + }, + "minecraft:blue_concrete": { + "protocol_id": 424 + }, + "minecraft:brown_concrete": { + "protocol_id": 425 + }, + "minecraft:green_concrete": { + "protocol_id": 426 + }, + "minecraft:red_concrete": { + "protocol_id": 427 + }, + "minecraft:black_concrete": { + "protocol_id": 428 + }, + "minecraft:white_concrete_powder": { + "protocol_id": 429 + }, + "minecraft:orange_concrete_powder": { + "protocol_id": 430 + }, + "minecraft:magenta_concrete_powder": { + "protocol_id": 431 + }, + "minecraft:light_blue_concrete_powder": { + "protocol_id": 432 + }, + "minecraft:yellow_concrete_powder": { + "protocol_id": 433 + }, + "minecraft:lime_concrete_powder": { + "protocol_id": 434 + }, + "minecraft:pink_concrete_powder": { + "protocol_id": 435 + }, + "minecraft:gray_concrete_powder": { + "protocol_id": 436 + }, + "minecraft:light_gray_concrete_powder": { + "protocol_id": 437 + }, + "minecraft:cyan_concrete_powder": { + "protocol_id": 438 + }, + "minecraft:purple_concrete_powder": { + "protocol_id": 439 + }, + "minecraft:blue_concrete_powder": { + "protocol_id": 440 + }, + "minecraft:brown_concrete_powder": { + "protocol_id": 441 + }, + "minecraft:green_concrete_powder": { + "protocol_id": 442 + }, + "minecraft:red_concrete_powder": { + "protocol_id": 443 + }, + "minecraft:black_concrete_powder": { + "protocol_id": 444 + }, + "minecraft:turtle_egg": { + "protocol_id": 445 + }, + "minecraft:dead_tube_coral_block": { + "protocol_id": 446 + }, + "minecraft:dead_brain_coral_block": { + "protocol_id": 447 + }, + "minecraft:dead_bubble_coral_block": { + "protocol_id": 448 + }, + "minecraft:dead_fire_coral_block": { + "protocol_id": 449 + }, + "minecraft:dead_horn_coral_block": { + "protocol_id": 450 + }, + "minecraft:tube_coral_block": { + "protocol_id": 451 + }, + "minecraft:brain_coral_block": { + "protocol_id": 452 + }, + "minecraft:bubble_coral_block": { + "protocol_id": 453 + }, + "minecraft:fire_coral_block": { + "protocol_id": 454 + }, + "minecraft:horn_coral_block": { + "protocol_id": 455 + }, + "minecraft:tube_coral": { + "protocol_id": 456 + }, + "minecraft:brain_coral": { + "protocol_id": 457 + }, + "minecraft:bubble_coral": { + "protocol_id": 458 + }, + "minecraft:fire_coral": { + "protocol_id": 459 + }, + "minecraft:horn_coral": { + "protocol_id": 460 + }, + "minecraft:dead_brain_coral": { + "protocol_id": 461 + }, + "minecraft:dead_bubble_coral": { + "protocol_id": 462 + }, + "minecraft:dead_fire_coral": { + "protocol_id": 463 + }, + "minecraft:dead_horn_coral": { + "protocol_id": 464 + }, + "minecraft:dead_tube_coral": { + "protocol_id": 465 + }, + "minecraft:tube_coral_fan": { + "protocol_id": 466 + }, + "minecraft:brain_coral_fan": { + "protocol_id": 467 + }, + "minecraft:bubble_coral_fan": { + "protocol_id": 468 + }, + "minecraft:fire_coral_fan": { + "protocol_id": 469 + }, + "minecraft:horn_coral_fan": { + "protocol_id": 470 + }, + "minecraft:dead_tube_coral_fan": { + "protocol_id": 471 + }, + "minecraft:dead_brain_coral_fan": { + "protocol_id": 472 + }, + "minecraft:dead_bubble_coral_fan": { + "protocol_id": 473 + }, + "minecraft:dead_fire_coral_fan": { + "protocol_id": 474 + }, + "minecraft:dead_horn_coral_fan": { + "protocol_id": 475 + }, + "minecraft:blue_ice": { + "protocol_id": 476 + }, + "minecraft:conduit": { + "protocol_id": 477 + }, + "minecraft:polished_granite_stairs": { + "protocol_id": 478 + }, + "minecraft:smooth_red_sandstone_stairs": { + "protocol_id": 479 + }, + "minecraft:mossy_stone_brick_stairs": { + "protocol_id": 480 + }, + "minecraft:polished_diorite_stairs": { + "protocol_id": 481 + }, + "minecraft:mossy_cobblestone_stairs": { + "protocol_id": 482 + }, + "minecraft:end_stone_brick_stairs": { + "protocol_id": 483 + }, + "minecraft:stone_stairs": { + "protocol_id": 484 + }, + "minecraft:smooth_sandstone_stairs": { + "protocol_id": 485 + }, + "minecraft:smooth_quartz_stairs": { + "protocol_id": 486 + }, + "minecraft:granite_stairs": { + "protocol_id": 487 + }, + "minecraft:andesite_stairs": { + "protocol_id": 488 + }, + "minecraft:red_nether_brick_stairs": { + "protocol_id": 489 + }, + "minecraft:polished_andesite_stairs": { + "protocol_id": 490 + }, + "minecraft:diorite_stairs": { + "protocol_id": 491 + }, + "minecraft:polished_granite_slab": { + "protocol_id": 492 + }, + "minecraft:smooth_red_sandstone_slab": { + "protocol_id": 493 + }, + "minecraft:mossy_stone_brick_slab": { + "protocol_id": 494 + }, + "minecraft:polished_diorite_slab": { + "protocol_id": 495 + }, + "minecraft:mossy_cobblestone_slab": { + "protocol_id": 496 + }, + "minecraft:end_stone_brick_slab": { + "protocol_id": 497 + }, + "minecraft:smooth_sandstone_slab": { + "protocol_id": 498 + }, + "minecraft:smooth_quartz_slab": { + "protocol_id": 499 + }, + "minecraft:granite_slab": { + "protocol_id": 500 + }, + "minecraft:andesite_slab": { + "protocol_id": 501 + }, + "minecraft:red_nether_brick_slab": { + "protocol_id": 502 + }, + "minecraft:polished_andesite_slab": { + "protocol_id": 503 + }, + "minecraft:diorite_slab": { + "protocol_id": 504 + }, + "minecraft:scaffolding": { + "protocol_id": 505 + }, + "minecraft:iron_door": { + "protocol_id": 506 + }, + "minecraft:oak_door": { + "protocol_id": 507 + }, + "minecraft:spruce_door": { + "protocol_id": 508 + }, + "minecraft:birch_door": { + "protocol_id": 509 + }, + "minecraft:jungle_door": { + "protocol_id": 510 + }, + "minecraft:acacia_door": { + "protocol_id": 511 + }, + "minecraft:dark_oak_door": { + "protocol_id": 512 + }, + "minecraft:repeater": { + "protocol_id": 513 + }, + "minecraft:comparator": { + "protocol_id": 514 + }, + "minecraft:structure_block": { + "protocol_id": 515 + }, + "minecraft:jigsaw": { + "protocol_id": 516 + }, + "minecraft:composter": { + "protocol_id": 517 + }, + "minecraft:turtle_helmet": { + "protocol_id": 518 + }, + "minecraft:scute": { + "protocol_id": 519 + }, + "minecraft:iron_shovel": { + "protocol_id": 520 + }, + "minecraft:iron_pickaxe": { + "protocol_id": 521 + }, + "minecraft:iron_axe": { + "protocol_id": 522 + }, + "minecraft:flint_and_steel": { + "protocol_id": 523 + }, + "minecraft:apple": { + "protocol_id": 524 + }, + "minecraft:bow": { + "protocol_id": 525 + }, + "minecraft:arrow": { + "protocol_id": 526 + }, + "minecraft:coal": { + "protocol_id": 527 + }, + "minecraft:charcoal": { + "protocol_id": 528 + }, + "minecraft:diamond": { + "protocol_id": 529 + }, + "minecraft:iron_ingot": { + "protocol_id": 530 + }, + "minecraft:gold_ingot": { + "protocol_id": 531 + }, + "minecraft:iron_sword": { + "protocol_id": 532 + }, + "minecraft:wooden_sword": { + "protocol_id": 533 + }, + "minecraft:wooden_shovel": { + "protocol_id": 534 + }, + "minecraft:wooden_pickaxe": { + "protocol_id": 535 + }, + "minecraft:wooden_axe": { + "protocol_id": 536 + }, + "minecraft:stone_sword": { + "protocol_id": 537 + }, + "minecraft:stone_shovel": { + "protocol_id": 538 + }, + "minecraft:stone_pickaxe": { + "protocol_id": 539 + }, + "minecraft:stone_axe": { + "protocol_id": 540 + }, + "minecraft:diamond_sword": { + "protocol_id": 541 + }, + "minecraft:diamond_shovel": { + "protocol_id": 542 + }, + "minecraft:diamond_pickaxe": { + "protocol_id": 543 + }, + "minecraft:diamond_axe": { + "protocol_id": 544 + }, + "minecraft:stick": { + "protocol_id": 545 + }, + "minecraft:bowl": { + "protocol_id": 546 + }, + "minecraft:mushroom_stew": { + "protocol_id": 547 + }, + "minecraft:golden_sword": { + "protocol_id": 548 + }, + "minecraft:golden_shovel": { + "protocol_id": 549 + }, + "minecraft:golden_pickaxe": { + "protocol_id": 550 + }, + "minecraft:golden_axe": { + "protocol_id": 551 + }, + "minecraft:string": { + "protocol_id": 552 + }, + "minecraft:feather": { + "protocol_id": 553 + }, + "minecraft:gunpowder": { + "protocol_id": 554 + }, + "minecraft:wooden_hoe": { + "protocol_id": 555 + }, + "minecraft:stone_hoe": { + "protocol_id": 556 + }, + "minecraft:iron_hoe": { + "protocol_id": 557 + }, + "minecraft:diamond_hoe": { + "protocol_id": 558 + }, + "minecraft:golden_hoe": { + "protocol_id": 559 + }, + "minecraft:wheat_seeds": { + "protocol_id": 560 + }, + "minecraft:wheat": { + "protocol_id": 561 + }, + "minecraft:bread": { + "protocol_id": 562 + }, + "minecraft:leather_helmet": { + "protocol_id": 563 + }, + "minecraft:leather_chestplate": { + "protocol_id": 564 + }, + "minecraft:leather_leggings": { + "protocol_id": 565 + }, + "minecraft:leather_boots": { + "protocol_id": 566 + }, + "minecraft:chainmail_helmet": { + "protocol_id": 567 + }, + "minecraft:chainmail_chestplate": { + "protocol_id": 568 + }, + "minecraft:chainmail_leggings": { + "protocol_id": 569 + }, + "minecraft:chainmail_boots": { + "protocol_id": 570 + }, + "minecraft:iron_helmet": { + "protocol_id": 571 + }, + "minecraft:iron_chestplate": { + "protocol_id": 572 + }, + "minecraft:iron_leggings": { + "protocol_id": 573 + }, + "minecraft:iron_boots": { + "protocol_id": 574 + }, + "minecraft:diamond_helmet": { + "protocol_id": 575 + }, + "minecraft:diamond_chestplate": { + "protocol_id": 576 + }, + "minecraft:diamond_leggings": { + "protocol_id": 577 + }, + "minecraft:diamond_boots": { + "protocol_id": 578 + }, + "minecraft:golden_helmet": { + "protocol_id": 579 + }, + "minecraft:golden_chestplate": { + "protocol_id": 580 + }, + "minecraft:golden_leggings": { + "protocol_id": 581 + }, + "minecraft:golden_boots": { + "protocol_id": 582 + }, + "minecraft:flint": { + "protocol_id": 583 + }, + "minecraft:porkchop": { + "protocol_id": 584 + }, + "minecraft:cooked_porkchop": { + "protocol_id": 585 + }, + "minecraft:painting": { + "protocol_id": 586 + }, + "minecraft:golden_apple": { + "protocol_id": 587 + }, + "minecraft:enchanted_golden_apple": { + "protocol_id": 588 + }, + "minecraft:oak_sign": { + "protocol_id": 589 + }, + "minecraft:spruce_sign": { + "protocol_id": 590 + }, + "minecraft:birch_sign": { + "protocol_id": 591 + }, + "minecraft:jungle_sign": { + "protocol_id": 592 + }, + "minecraft:acacia_sign": { + "protocol_id": 593 + }, + "minecraft:dark_oak_sign": { + "protocol_id": 594 + }, + "minecraft:bucket": { + "protocol_id": 595 + }, + "minecraft:water_bucket": { + "protocol_id": 596 + }, + "minecraft:lava_bucket": { + "protocol_id": 597 + }, + "minecraft:minecart": { + "protocol_id": 598 + }, + "minecraft:saddle": { + "protocol_id": 599 + }, + "minecraft:redstone": { + "protocol_id": 600 + }, + "minecraft:snowball": { + "protocol_id": 601 + }, + "minecraft:oak_boat": { + "protocol_id": 602 + }, + "minecraft:leather": { + "protocol_id": 603 + }, + "minecraft:milk_bucket": { + "protocol_id": 604 + }, + "minecraft:pufferfish_bucket": { + "protocol_id": 605 + }, + "minecraft:salmon_bucket": { + "protocol_id": 606 + }, + "minecraft:cod_bucket": { + "protocol_id": 607 + }, + "minecraft:tropical_fish_bucket": { + "protocol_id": 608 + }, + "minecraft:brick": { + "protocol_id": 609 + }, + "minecraft:clay_ball": { + "protocol_id": 610 + }, + "minecraft:sugar_cane": { + "protocol_id": 611 + }, + "minecraft:kelp": { + "protocol_id": 612 + }, + "minecraft:dried_kelp_block": { + "protocol_id": 613 + }, + "minecraft:bamboo": { + "protocol_id": 614 + }, + "minecraft:paper": { + "protocol_id": 615 + }, + "minecraft:book": { + "protocol_id": 616 + }, + "minecraft:slime_ball": { + "protocol_id": 617 + }, + "minecraft:chest_minecart": { + "protocol_id": 618 + }, + "minecraft:furnace_minecart": { + "protocol_id": 619 + }, + "minecraft:egg": { + "protocol_id": 620 + }, + "minecraft:compass": { + "protocol_id": 621 + }, + "minecraft:fishing_rod": { + "protocol_id": 622 + }, + "minecraft:clock": { + "protocol_id": 623 + }, + "minecraft:glowstone_dust": { + "protocol_id": 624 + }, + "minecraft:cod": { + "protocol_id": 625 + }, + "minecraft:salmon": { + "protocol_id": 626 + }, + "minecraft:tropical_fish": { + "protocol_id": 627 + }, + "minecraft:pufferfish": { + "protocol_id": 628 + }, + "minecraft:cooked_cod": { + "protocol_id": 629 + }, + "minecraft:cooked_salmon": { + "protocol_id": 630 + }, + "minecraft:ink_sac": { + "protocol_id": 631 + }, + "minecraft:red_dye": { + "protocol_id": 632 + }, + "minecraft:green_dye": { + "protocol_id": 633 + }, + "minecraft:cocoa_beans": { + "protocol_id": 634 + }, + "minecraft:lapis_lazuli": { + "protocol_id": 635 + }, + "minecraft:purple_dye": { + "protocol_id": 636 + }, + "minecraft:cyan_dye": { + "protocol_id": 637 + }, + "minecraft:light_gray_dye": { + "protocol_id": 638 + }, + "minecraft:gray_dye": { + "protocol_id": 639 + }, + "minecraft:pink_dye": { + "protocol_id": 640 + }, + "minecraft:lime_dye": { + "protocol_id": 641 + }, + "minecraft:yellow_dye": { + "protocol_id": 642 + }, + "minecraft:light_blue_dye": { + "protocol_id": 643 + }, + "minecraft:magenta_dye": { + "protocol_id": 644 + }, + "minecraft:orange_dye": { + "protocol_id": 645 + }, + "minecraft:bone_meal": { + "protocol_id": 646 + }, + "minecraft:blue_dye": { + "protocol_id": 647 + }, + "minecraft:brown_dye": { + "protocol_id": 648 + }, + "minecraft:black_dye": { + "protocol_id": 649 + }, + "minecraft:white_dye": { + "protocol_id": 650 + }, + "minecraft:bone": { + "protocol_id": 651 + }, + "minecraft:sugar": { + "protocol_id": 652 + }, + "minecraft:cake": { + "protocol_id": 653 + }, + "minecraft:white_bed": { + "protocol_id": 654 + }, + "minecraft:orange_bed": { + "protocol_id": 655 + }, + "minecraft:magenta_bed": { + "protocol_id": 656 + }, + "minecraft:light_blue_bed": { + "protocol_id": 657 + }, + "minecraft:yellow_bed": { + "protocol_id": 658 + }, + "minecraft:lime_bed": { + "protocol_id": 659 + }, + "minecraft:pink_bed": { + "protocol_id": 660 + }, + "minecraft:gray_bed": { + "protocol_id": 661 + }, + "minecraft:light_gray_bed": { + "protocol_id": 662 + }, + "minecraft:cyan_bed": { + "protocol_id": 663 + }, + "minecraft:purple_bed": { + "protocol_id": 664 + }, + "minecraft:blue_bed": { + "protocol_id": 665 + }, + "minecraft:brown_bed": { + "protocol_id": 666 + }, + "minecraft:green_bed": { + "protocol_id": 667 + }, + "minecraft:red_bed": { + "protocol_id": 668 + }, + "minecraft:black_bed": { + "protocol_id": 669 + }, + "minecraft:cookie": { + "protocol_id": 670 + }, + "minecraft:filled_map": { + "protocol_id": 671 + }, + "minecraft:shears": { + "protocol_id": 672 + }, + "minecraft:melon_slice": { + "protocol_id": 673 + }, + "minecraft:dried_kelp": { + "protocol_id": 674 + }, + "minecraft:pumpkin_seeds": { + "protocol_id": 675 + }, + "minecraft:melon_seeds": { + "protocol_id": 676 + }, + "minecraft:beef": { + "protocol_id": 677 + }, + "minecraft:cooked_beef": { + "protocol_id": 678 + }, + "minecraft:chicken": { + "protocol_id": 679 + }, + "minecraft:cooked_chicken": { + "protocol_id": 680 + }, + "minecraft:rotten_flesh": { + "protocol_id": 681 + }, + "minecraft:ender_pearl": { + "protocol_id": 682 + }, + "minecraft:blaze_rod": { + "protocol_id": 683 + }, + "minecraft:ghast_tear": { + "protocol_id": 684 + }, + "minecraft:gold_nugget": { + "protocol_id": 685 + }, + "minecraft:nether_wart": { + "protocol_id": 686 + }, + "minecraft:potion": { + "protocol_id": 687 + }, + "minecraft:glass_bottle": { + "protocol_id": 688 + }, + "minecraft:spider_eye": { + "protocol_id": 689 + }, + "minecraft:fermented_spider_eye": { + "protocol_id": 690 + }, + "minecraft:blaze_powder": { + "protocol_id": 691 + }, + "minecraft:magma_cream": { + "protocol_id": 692 + }, + "minecraft:brewing_stand": { + "protocol_id": 693 + }, + "minecraft:cauldron": { + "protocol_id": 694 + }, + "minecraft:ender_eye": { + "protocol_id": 695 + }, + "minecraft:glistering_melon_slice": { + "protocol_id": 696 + }, + "minecraft:bat_spawn_egg": { + "protocol_id": 697 + }, + "minecraft:blaze_spawn_egg": { + "protocol_id": 698 + }, + "minecraft:cat_spawn_egg": { + "protocol_id": 699 + }, + "minecraft:cave_spider_spawn_egg": { + "protocol_id": 700 + }, + "minecraft:chicken_spawn_egg": { + "protocol_id": 701 + }, + "minecraft:cod_spawn_egg": { + "protocol_id": 702 + }, + "minecraft:cow_spawn_egg": { + "protocol_id": 703 + }, + "minecraft:creeper_spawn_egg": { + "protocol_id": 704 + }, + "minecraft:dolphin_spawn_egg": { + "protocol_id": 705 + }, + "minecraft:donkey_spawn_egg": { + "protocol_id": 706 + }, + "minecraft:drowned_spawn_egg": { + "protocol_id": 707 + }, + "minecraft:elder_guardian_spawn_egg": { + "protocol_id": 708 + }, + "minecraft:enderman_spawn_egg": { + "protocol_id": 709 + }, + "minecraft:endermite_spawn_egg": { + "protocol_id": 710 + }, + "minecraft:evoker_spawn_egg": { + "protocol_id": 711 + }, + "minecraft:fox_spawn_egg": { + "protocol_id": 712 + }, + "minecraft:ghast_spawn_egg": { + "protocol_id": 713 + }, + "minecraft:guardian_spawn_egg": { + "protocol_id": 714 + }, + "minecraft:horse_spawn_egg": { + "protocol_id": 715 + }, + "minecraft:husk_spawn_egg": { + "protocol_id": 716 + }, + "minecraft:llama_spawn_egg": { + "protocol_id": 717 + }, + "minecraft:magma_cube_spawn_egg": { + "protocol_id": 718 + }, + "minecraft:mooshroom_spawn_egg": { + "protocol_id": 719 + }, + "minecraft:mule_spawn_egg": { + "protocol_id": 720 + }, + "minecraft:ocelot_spawn_egg": { + "protocol_id": 721 + }, + "minecraft:panda_spawn_egg": { + "protocol_id": 722 + }, + "minecraft:parrot_spawn_egg": { + "protocol_id": 723 + }, + "minecraft:phantom_spawn_egg": { + "protocol_id": 724 + }, + "minecraft:pig_spawn_egg": { + "protocol_id": 725 + }, + "minecraft:pillager_spawn_egg": { + "protocol_id": 726 + }, + "minecraft:polar_bear_spawn_egg": { + "protocol_id": 727 + }, + "minecraft:pufferfish_spawn_egg": { + "protocol_id": 728 + }, + "minecraft:rabbit_spawn_egg": { + "protocol_id": 729 + }, + "minecraft:ravager_spawn_egg": { + "protocol_id": 730 + }, + "minecraft:salmon_spawn_egg": { + "protocol_id": 731 + }, + "minecraft:sheep_spawn_egg": { + "protocol_id": 732 + }, + "minecraft:shulker_spawn_egg": { + "protocol_id": 733 + }, + "minecraft:silverfish_spawn_egg": { + "protocol_id": 734 + }, + "minecraft:skeleton_spawn_egg": { + "protocol_id": 735 + }, + "minecraft:skeleton_horse_spawn_egg": { + "protocol_id": 736 + }, + "minecraft:slime_spawn_egg": { + "protocol_id": 737 + }, + "minecraft:spider_spawn_egg": { + "protocol_id": 738 + }, + "minecraft:squid_spawn_egg": { + "protocol_id": 739 + }, + "minecraft:stray_spawn_egg": { + "protocol_id": 740 + }, + "minecraft:trader_llama_spawn_egg": { + "protocol_id": 741 + }, + "minecraft:tropical_fish_spawn_egg": { + "protocol_id": 742 + }, + "minecraft:turtle_spawn_egg": { + "protocol_id": 743 + }, + "minecraft:vex_spawn_egg": { + "protocol_id": 744 + }, + "minecraft:villager_spawn_egg": { + "protocol_id": 745 + }, + "minecraft:vindicator_spawn_egg": { + "protocol_id": 746 + }, + "minecraft:wandering_trader_spawn_egg": { + "protocol_id": 747 + }, + "minecraft:witch_spawn_egg": { + "protocol_id": 748 + }, + "minecraft:wither_skeleton_spawn_egg": { + "protocol_id": 749 + }, + "minecraft:wolf_spawn_egg": { + "protocol_id": 750 + }, + "minecraft:zombie_spawn_egg": { + "protocol_id": 751 + }, + "minecraft:zombie_horse_spawn_egg": { + "protocol_id": 752 + }, + "minecraft:zombie_pigman_spawn_egg": { + "protocol_id": 753 + }, + "minecraft:zombie_villager_spawn_egg": { + "protocol_id": 754 + }, + "minecraft:experience_bottle": { + "protocol_id": 755 + }, + "minecraft:fire_charge": { + "protocol_id": 756 + }, + "minecraft:writable_book": { + "protocol_id": 757 + }, + "minecraft:written_book": { + "protocol_id": 758 + }, + "minecraft:emerald": { + "protocol_id": 759 + }, + "minecraft:item_frame": { + "protocol_id": 760 + }, + "minecraft:flower_pot": { + "protocol_id": 761 + }, + "minecraft:carrot": { + "protocol_id": 762 + }, + "minecraft:potato": { + "protocol_id": 763 + }, + "minecraft:baked_potato": { + "protocol_id": 764 + }, + "minecraft:poisonous_potato": { + "protocol_id": 765 + }, + "minecraft:map": { + "protocol_id": 766 + }, + "minecraft:golden_carrot": { + "protocol_id": 767 + }, + "minecraft:skeleton_skull": { + "protocol_id": 768 + }, + "minecraft:wither_skeleton_skull": { + "protocol_id": 769 + }, + "minecraft:player_head": { + "protocol_id": 770 + }, + "minecraft:zombie_head": { + "protocol_id": 771 + }, + "minecraft:creeper_head": { + "protocol_id": 772 + }, + "minecraft:dragon_head": { + "protocol_id": 773 + }, + "minecraft:carrot_on_a_stick": { + "protocol_id": 774 + }, + "minecraft:nether_star": { + "protocol_id": 775 + }, + "minecraft:pumpkin_pie": { + "protocol_id": 776 + }, + "minecraft:firework_rocket": { + "protocol_id": 777 + }, + "minecraft:firework_star": { + "protocol_id": 778 + }, + "minecraft:enchanted_book": { + "protocol_id": 779 + }, + "minecraft:nether_brick": { + "protocol_id": 780 + }, + "minecraft:quartz": { + "protocol_id": 781 + }, + "minecraft:tnt_minecart": { + "protocol_id": 782 + }, + "minecraft:hopper_minecart": { + "protocol_id": 783 + }, + "minecraft:prismarine_shard": { + "protocol_id": 784 + }, + "minecraft:prismarine_crystals": { + "protocol_id": 785 + }, + "minecraft:rabbit": { + "protocol_id": 786 + }, + "minecraft:cooked_rabbit": { + "protocol_id": 787 + }, + "minecraft:rabbit_stew": { + "protocol_id": 788 + }, + "minecraft:rabbit_foot": { + "protocol_id": 789 + }, + "minecraft:rabbit_hide": { + "protocol_id": 790 + }, + "minecraft:armor_stand": { + "protocol_id": 791 + }, + "minecraft:iron_horse_armor": { + "protocol_id": 792 + }, + "minecraft:golden_horse_armor": { + "protocol_id": 793 + }, + "minecraft:diamond_horse_armor": { + "protocol_id": 794 + }, + "minecraft:leather_horse_armor": { + "protocol_id": 795 + }, + "minecraft:lead": { + "protocol_id": 796 + }, + "minecraft:name_tag": { + "protocol_id": 797 + }, + "minecraft:command_block_minecart": { + "protocol_id": 798 + }, + "minecraft:mutton": { + "protocol_id": 799 + }, + "minecraft:cooked_mutton": { + "protocol_id": 800 + }, + "minecraft:white_banner": { + "protocol_id": 801 + }, + "minecraft:orange_banner": { + "protocol_id": 802 + }, + "minecraft:magenta_banner": { + "protocol_id": 803 + }, + "minecraft:light_blue_banner": { + "protocol_id": 804 + }, + "minecraft:yellow_banner": { + "protocol_id": 805 + }, + "minecraft:lime_banner": { + "protocol_id": 806 + }, + "minecraft:pink_banner": { + "protocol_id": 807 + }, + "minecraft:gray_banner": { + "protocol_id": 808 + }, + "minecraft:light_gray_banner": { + "protocol_id": 809 + }, + "minecraft:cyan_banner": { + "protocol_id": 810 + }, + "minecraft:purple_banner": { + "protocol_id": 811 + }, + "minecraft:blue_banner": { + "protocol_id": 812 + }, + "minecraft:brown_banner": { + "protocol_id": 813 + }, + "minecraft:green_banner": { + "protocol_id": 814 + }, + "minecraft:red_banner": { + "protocol_id": 815 + }, + "minecraft:black_banner": { + "protocol_id": 816 + }, + "minecraft:end_crystal": { + "protocol_id": 817 + }, + "minecraft:chorus_fruit": { + "protocol_id": 818 + }, + "minecraft:popped_chorus_fruit": { + "protocol_id": 819 + }, + "minecraft:beetroot": { + "protocol_id": 820 + }, + "minecraft:beetroot_seeds": { + "protocol_id": 821 + }, + "minecraft:beetroot_soup": { + "protocol_id": 822 + }, + "minecraft:dragon_breath": { + "protocol_id": 823 + }, + "minecraft:splash_potion": { + "protocol_id": 824 + }, + "minecraft:spectral_arrow": { + "protocol_id": 825 + }, + "minecraft:tipped_arrow": { + "protocol_id": 826 + }, + "minecraft:lingering_potion": { + "protocol_id": 827 + }, + "minecraft:shield": { + "protocol_id": 828 + }, + "minecraft:elytra": { + "protocol_id": 829 + }, + "minecraft:spruce_boat": { + "protocol_id": 830 + }, + "minecraft:birch_boat": { + "protocol_id": 831 + }, + "minecraft:jungle_boat": { + "protocol_id": 832 + }, + "minecraft:acacia_boat": { + "protocol_id": 833 + }, + "minecraft:dark_oak_boat": { + "protocol_id": 834 + }, + "minecraft:totem_of_undying": { + "protocol_id": 835 + }, + "minecraft:shulker_shell": { + "protocol_id": 836 + }, + "minecraft:iron_nugget": { + "protocol_id": 837 + }, + "minecraft:knowledge_book": { + "protocol_id": 838 + }, + "minecraft:debug_stick": { + "protocol_id": 839 + }, + "minecraft:music_disc_13": { + "protocol_id": 840 + }, + "minecraft:music_disc_cat": { + "protocol_id": 841 + }, + "minecraft:music_disc_blocks": { + "protocol_id": 842 + }, + "minecraft:music_disc_chirp": { + "protocol_id": 843 + }, + "minecraft:music_disc_far": { + "protocol_id": 844 + }, + "minecraft:music_disc_mall": { + "protocol_id": 845 + }, + "minecraft:music_disc_mellohi": { + "protocol_id": 846 + }, + "minecraft:music_disc_stal": { + "protocol_id": 847 + }, + "minecraft:music_disc_strad": { + "protocol_id": 848 + }, + "minecraft:music_disc_ward": { + "protocol_id": 849 + }, + "minecraft:music_disc_11": { + "protocol_id": 850 + }, + "minecraft:music_disc_wait": { + "protocol_id": 851 + }, + "minecraft:trident": { + "protocol_id": 852 + }, + "minecraft:phantom_membrane": { + "protocol_id": 853 + }, + "minecraft:nautilus_shell": { + "protocol_id": 854 + }, + "minecraft:heart_of_the_sea": { + "protocol_id": 855 + }, + "minecraft:crossbow": { + "protocol_id": 856 + }, + "minecraft:suspicious_stew": { + "protocol_id": 857 + }, + "minecraft:loom": { + "protocol_id": 858 + }, + "minecraft:flower_banner_pattern": { + "protocol_id": 859 + }, + "minecraft:creeper_banner_pattern": { + "protocol_id": 860 + }, + "minecraft:skull_banner_pattern": { + "protocol_id": 861 + }, + "minecraft:mojang_banner_pattern": { + "protocol_id": 862 + }, + "minecraft:globe_banner_pattern": { + "protocol_id": 863 + }, + "minecraft:barrel": { + "protocol_id": 864 + }, + "minecraft:smoker": { + "protocol_id": 865 + }, + "minecraft:blast_furnace": { + "protocol_id": 866 + }, + "minecraft:cartography_table": { + "protocol_id": 867 + }, + "minecraft:fletching_table": { + "protocol_id": 868 + }, + "minecraft:grindstone": { + "protocol_id": 869 + }, + "minecraft:lectern": { + "protocol_id": 870 + }, + "minecraft:smithing_table": { + "protocol_id": 871 + }, + "minecraft:stonecutter": { + "protocol_id": 872 + }, + "minecraft:bell": { + "protocol_id": 873 + }, + "minecraft:lantern": { + "protocol_id": 874 + }, + "minecraft:sweet_berries": { + "protocol_id": 875 + }, + "minecraft:campfire": { + "protocol_id": 876 + } +} \ No newline at end of file