From 3067c7274665fdd9d511e04dd94e05bd8cfea196 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 19 Oct 2019 23:54:30 -0800 Subject: [PATCH 01/32] Use chunk cache and fix ChunkPosition getChunkBlock() in ChunkPosition returned incorrect values when negative numbers were inputted. ChunkPosition did not function correctly when used as a key for maps because it did not override equals() and hashCode() --- .../player/JavaPlayerActionAckTranslator.java | 1 + .../java/world/JavaBlockChangeTranslator.java | 4 ++- .../java/world/JavaChunkDataTranslator.java | 1 + .../world/JavaMultiBlockChangeTranslator.java | 1 + .../connector/world/chunk/ChunkPosition.java | 32 +++++++++++++------ 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java index 3213a2fd..cf5c26bc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java @@ -40,6 +40,7 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator { @Override public void translate(ServerBlockChangePacket packet, GeyserSession session) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); BlockChangeRecord record = packet.getRecord(); + session.getChunkCache().updateBlock(record.getPosition(), record.getBlock()); + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setBlockPosition(Vector3i.from( record.getPosition().getX(), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java index a620197e..2082157e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java @@ -18,6 +18,7 @@ public class JavaChunkDataTranslator extends PacketTranslator { Vector2i chunkPos = session.getLastChunkPosition(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java index 14864b8c..b78e366c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java @@ -40,6 +40,7 @@ public class JavaMultiBlockChangeTranslator extends PacketTranslator Date: Sun, 20 Oct 2019 13:25:41 -0800 Subject: [PATCH 02/32] Work on inventory transactions work in progress --- .../connector/inventory/Inventory.java | 27 +- .../connector/inventory/PlayerInventory.java | 14 +- .../network/session/GeyserSession.java | 8 + .../network/session/cache/InventoryCache.java | 12 - .../network/translators/TranslatorsInit.java | 46 ++-- .../BedrockContainerCloseTranslator.java | 56 ++++ ...BedrockInventoryTransactionTranslator.java | 254 +++++++++++++++++- .../inventory/ChestInventoryTranslator.java | 163 +++++++++++ .../DispenserInventoryTranslator.java | 87 ++++++ .../inventory/FurnaceInventoryTranslator.java | 108 ++++++++ .../inventory/GenericInventoryTranslator.java | 74 ----- .../inventory/HopperInventoryTranslator.java | 87 ++++++ .../inventory/InventoryTranslator.java | 62 ++++- .../inventory/PlayerInventoryTranslator.java | 138 ++++++++++ .../translators/item/ItemTranslator.java | 3 +- .../inventory/OpenWindowPacketTranslator.java | 22 -- .../window/JavaCloseWindowTranslator.java | 43 +++ .../JavaConfirmTransactionTranslator.java | 46 ++++ .../java/window/JavaSetSlotTranslator.java | 61 +++-- .../window/JavaWindowItemsTranslator.java | 20 +- .../window/JavaWindowPropertyTranslator.java | 24 ++ .../connector/utils/InventoryUtils.java | 128 +++------ 22 files changed, 1214 insertions(+), 269 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/inventory/OpenWindowPacketTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 801f670c..215ac597 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -27,6 +27,7 @@ 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 com.nukkitx.math.vector.Vector3i; import lombok.Getter; import lombok.Setter; @@ -42,9 +43,6 @@ public class Inventory { @Getter protected WindowType windowType; - @Getter - protected int size; - @Getter @Setter protected String title; @@ -53,20 +51,31 @@ public class Inventory { @Setter protected ItemStack[] items; - public Inventory(int id, WindowType windowType, int size) { - this("Inventory", id, windowType, size); + @Getter + @Setter + protected Vector3i holderPosition = Vector3i.ZERO; + + @Getter + @Setter + protected long holderId = -1; + + protected short transactionId = 1; + + public Inventory(int id, WindowType windowType) { + this("Inventory", id, windowType); } - public Inventory(String title, int id, WindowType windowType, int size) { + public Inventory(String title, int id, WindowType windowType) { this.title = title; this.id = id; this.windowType = windowType; - this.size = size; - - this.items = new ItemStack[size]; } public ItemStack getItem(int slot) { return items[slot]; } + + public short getNextTransactionId() { + return transactionId++; + } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java index 424570b9..44ad3cb6 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -35,12 +35,22 @@ public class PlayerInventory extends Inventory { @Setter private int heldItemSlot; - public PlayerInventory() { - super(0, null, 45); + @Getter + private ItemStack cursor; + public PlayerInventory() { + super(0, null); + + items = new ItemStack[45]; heldItemSlot = 0; } + public void setCursor(ItemStack stack) { + if (stack != null && stack.getId() == 0) + stack = null; + cursor = stack; + } + public ItemStack getItemInHand() { return items[heldItemSlot]; } 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 a4f57c08..9bce0e7c 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 @@ -99,6 +99,14 @@ public class GeyserSession implements Player { @Setter private BlockFace blockDiggingFace = BlockFace.DOWN; + @Getter + @Setter + private int lastClickedSlot; + + @Getter + @Setter + private int reopeningWindow = -1; + public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { this.connector = connector; this.upstream = new UpstreamSession(bedrockServerSession); 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 index 4eea1de2..9277ce5d 100644 --- 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 @@ -25,15 +25,12 @@ 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 { @@ -47,9 +44,6 @@ public class InventoryCache { @Getter private Map inventories = new HashMap(); - @Getter - private Map> cachedPackets = new HashMap>(); - public InventoryCache(GeyserSession session) { this.session = session; } @@ -65,10 +59,4 @@ public class InventoryCache { 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/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index d4bc5b45..74c50dbf 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.*; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.*; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket; @@ -36,9 +37,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerD import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket; -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.window.*; import com.github.steveice10.mc.protocol.packet.ingame.server.world.*; import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.NbtUtils; @@ -48,25 +47,23 @@ import com.nukkitx.protocol.bedrock.packet.*; import lombok.Getter; import org.geysermc.connector.network.translators.bedrock.*; import org.geysermc.connector.network.translators.block.BlockTranslator; -import org.geysermc.connector.network.translators.inventory.GenericInventoryTranslator; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.inventory.*; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.java.*; import org.geysermc.connector.network.translators.java.entity.*; import org.geysermc.connector.network.translators.java.entity.player.*; import org.geysermc.connector.network.translators.java.entity.spawn.*; -import org.geysermc.connector.network.translators.java.inventory.OpenWindowPacketTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaDisplayScoreboardTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaTeamTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaUpdateScoreTranslator; -import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator; -import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator; -import org.geysermc.connector.network.translators.java.window.JavaWindowItemsTranslator; +import org.geysermc.connector.network.translators.java.window.*; import org.geysermc.connector.network.translators.java.world.*; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; public class TranslatorsInit { @@ -77,7 +74,7 @@ public class TranslatorsInit { private static BlockTranslator blockTranslator; @Getter - private static InventoryTranslator inventoryTranslator = new GenericInventoryTranslator(); + private static Map inventoryTranslators = new HashMap(); private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag(); public static final byte[] EMPTY_LEVEL_CHUNK_DATA; @@ -132,9 +129,6 @@ public class TranslatorsInit { Registry.registerJava(ServerNotifyClientPacket.class, new JavaNotifyClientTranslator()); Registry.registerJava(ServerChunkDataPacket.class, new JavaChunkDataTranslator()); Registry.registerJava(ServerEntityDestroyPacket.class, new JavaEntityDestroyTranslator()); - Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator()); - Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator()); - Registry.registerJava(ServerSetSlotPacket.class, new JavaSetSlotTranslator()); Registry.registerJava(ServerScoreboardObjectivePacket.class, new JavaScoreboardObjectiveTranslator()); Registry.registerJava(ServerDisplayScoreboardPacket.class, new JavaDisplayScoreboardTranslator()); Registry.registerJava(ServerUpdateScorePacket.class, new JavaUpdateScoreTranslator()); @@ -142,7 +136,12 @@ public class TranslatorsInit { Registry.registerJava(ServerBlockChangePacket.class, new JavaBlockChangeTranslator()); Registry.registerJava(ServerMultiBlockChangePacket.class, new JavaMultiBlockChangeTranslator()); - Registry.registerJava(ServerOpenWindowPacket.class, new OpenWindowPacketTranslator()); + Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator()); + Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator()); + Registry.registerJava(ServerSetSlotPacket.class, new JavaSetSlotTranslator()); + Registry.registerJava(ServerCloseWindowPacket.class, new JavaCloseWindowTranslator()); + Registry.registerJava(ServerConfirmTransactionPacket.class, new JavaConfirmTransactionTranslator()); + Registry.registerJava(ServerWindowPropertyPacket.class, new JavaWindowPropertyTranslator()); Registry.registerBedrock(AnimatePacket.class, new BedrockAnimateTranslator()); Registry.registerBedrock(CommandRequestPacket.class, new BedrockCommandRequestTranslator()); @@ -153,6 +152,7 @@ public class TranslatorsInit { Registry.registerBedrock(SetLocalPlayerAsInitializedPacket.class, new BedrockPlayerInitializedTranslator()); Registry.registerBedrock(InteractPacket.class, new BedrockInteractTranslator()); Registry.registerBedrock(TextPacket.class, new BedrockTextTranslator()); + Registry.registerBedrock(ContainerClosePacket.class, new BedrockContainerCloseTranslator()); itemTranslator = new ItemTranslator(); blockTranslator = new BlockTranslator(); @@ -161,11 +161,17 @@ public class TranslatorsInit { } 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());*/ + inventoryTranslators.put(null, new PlayerInventoryTranslator()); //player inventory + inventoryTranslators.put(WindowType.GENERIC_9X1, new ChestInventoryTranslator(9)); + inventoryTranslators.put(WindowType.GENERIC_9X2, new ChestInventoryTranslator(18)); + inventoryTranslators.put(WindowType.GENERIC_9X3, new ChestInventoryTranslator(27)); + inventoryTranslators.put(WindowType.GENERIC_9X4, new ChestInventoryTranslator(36)); + inventoryTranslators.put(WindowType.GENERIC_9X5, new ChestInventoryTranslator(45)); + inventoryTranslators.put(WindowType.GENERIC_9X6, new ChestInventoryTranslator(54)); + inventoryTranslators.put(WindowType.GENERIC_3X3, new DispenserInventoryTranslator()); + inventoryTranslators.put(WindowType.HOPPER, new HopperInventoryTranslator()); + inventoryTranslators.put(WindowType.FURNACE, new FurnaceInventoryTranslator()); + inventoryTranslators.put(WindowType.BLAST_FURNACE, new FurnaceInventoryTranslator()); + inventoryTranslators.put(WindowType.SMOKER, new FurnaceInventoryTranslator()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java new file mode 100644 index 00000000..de6a9d8c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -0,0 +1,56 @@ +/* + * 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.bedrock; + +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket; +import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +public class BedrockContainerCloseTranslator extends PacketTranslator { + + @Override + public void translate(ContainerClosePacket packet, GeyserSession session) { + byte windowId = packet.getWindowId() == -1 ? 0 : packet.getWindowId(); //player inventory + if (session.getReopeningWindow() != -1) { + Inventory inventory = session.getInventoryCache().getInventories().get(session.getReopeningWindow()); + session.setReopeningWindow(-1); + if (inventory != null) { + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + translator.openInventory(session, inventory); + translator.updateInventory(session, inventory); + return; + } + } + ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId); + session.getDownstream().getSession().send(closeWindowPacket); + InventoryUtils.closeInventory(session, windowId); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 1e6b44a9..e3301604 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -25,6 +25,10 @@ package org.geysermc.connector.network.translators.bedrock; +import com.github.steveice10.mc.protocol.data.game.window.*; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.nukkitx.math.vector.Vector3f; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; @@ -33,18 +37,266 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket; -import com.nukkitx.math.vector.Vector3f; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventorySource; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.PlayerEntity; +import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; public class BedrockInventoryTransactionTranslator extends PacketTranslator { @Override public void translate(InventoryTransactionPacket packet, GeyserSession session) { switch (packet.getTransactionType()) { + case NORMAL: + Inventory inventory = session.getInventoryCache().getOpenInventory(); + if (inventory == null) + inventory = session.getInventory(); + InventoryTranslator translator; + translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + //find the world interaction and/or cursor action if present + InventoryAction worldAction = null; + InventoryAction cursorAction = null; + for (InventoryAction action : packet.getActions()) { + if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) { + if (worldAction == null) { + worldAction = action; + } else { + return; + } + } else if (action.getSource().getContainerId() == ContainerId.CURSOR) { + if (cursorAction == null) { + cursorAction = action; + } else { + return; + } + } + } + if (packet.getActions().size() == 2) { + if (worldAction != null && worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { + //find container action + InventoryAction containerAction = null; + for (InventoryAction action : packet.getActions()) { + if (action.getSource().getType() == InventorySource.Type.CONTAINER || action.getSource().getType() == InventorySource.Type.UNTRACKED_INTERACTION_UI) { + containerAction = action; + break; + } + } + if (containerAction != null) { + //quick dropping from hotbar? + if (session.getInventoryCache().getOpenInventory() == null && containerAction.getSource().getContainerId() == ContainerId.INVENTORY) { + if (containerAction.getSlot() == session.getInventory().getHeldItemSlot()) { + ClientPlayerActionPacket actionPacket = new ClientPlayerActionPacket( + containerAction.getToItem().getCount() == 0 ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM, + new Position(0, 0, 0), BlockFace.DOWN); + session.getDownstream().getSession().send(actionPacket); + return; + } + } + boolean leftClick = containerAction.getToItem().getCount() == 0; + if (containerAction.getSource().getContainerId() != ContainerId.CURSOR) { //dropping directly from inventory + int javaSlot = translator.bedrockSlotToJava(containerAction); + ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + javaSlot, null, WindowAction.DROP_ITEM, + leftClick ? DropItemParam.DROP_SELECTED_STACK : DropItemParam.DROP_FROM_SELECTED); + session.getDownstream().getSession().send(dropPacket); + return; + } else { //clicking outside of inventory + ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + -999, null, WindowAction.CLICK_ITEM, + leftClick ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK); + session.getDownstream().getSession().send(dropPacket); + return; + } + } + } else if (cursorAction != null) { + //find container action + InventoryAction containerAction = null; + for (InventoryAction action : packet.getActions()) { + if (action != cursorAction && (action.getSource().getType() == InventorySource.Type.CONTAINER || action.getSource().getType() == InventorySource.Type.UNTRACKED_INTERACTION_UI)) { + containerAction = action; + break; + } + } + if (containerAction != null) { + if (InventoryUtils.canCombine(cursorAction.getFromItem(), cursorAction.getToItem()) + && cursorAction.getToItem().getCount() > cursorAction.getFromItem().getCount()) { //fill stack + int javaSlot = session.getLastClickedSlot(); + ClientWindowActionPacket fillStackPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + javaSlot, null, WindowAction.FILL_STACK, FillStackParam.FILL); + session.getDownstream().getSession().send(fillStackPacket); + translator.updateInventory(session, inventory); //bedrock fill stack can sometimes differ from java version, refresh and let server change slots + System.out.println(fillStackPacket); + return; + } else { + //left/right click + int javaSlot = translator.bedrockSlotToJava(containerAction); + boolean rightClick; + if (cursorAction.getFromItem().getCount() == 0) { //picking up item + rightClick = containerAction.getToItem().getCount() != 0; + } else { //releasing item + rightClick = cursorAction.getToItem().getCount() != 0 && cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount() == 1; + } + ItemStack translatedCursor = TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getFromItem()); + boolean refresh = !Objects.equals(session.getInventory().getCursor(), translatedCursor.getId() == 0 ? null : translatedCursor); //refresh slot if there is a cursor mismatch + ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(), + inventory.getNextTransactionId(), javaSlot, + refresh ? new ItemStack(1, 127, new CompoundTag("")) : InventoryUtils.fixNbt(TranslatorsInit.getItemTranslator().translateToJava(containerAction.getFromItem())), //send invalid item stack to refresh slot + WindowAction.CLICK_ITEM, rightClick ? ClickItemParam.RIGHT_CLICK : ClickItemParam.LEFT_CLICK); + System.out.println(clickPacket); + session.getDownstream().getSession().send(clickPacket); + inventory.getItems()[javaSlot] = TranslatorsInit.getItemTranslator().translateToJava(containerAction.getToItem()); + translator.updateSlot(session, inventory, javaSlot); + session.getInventory().setCursor(TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getToItem())); + session.setLastClickedSlot(javaSlot); + return; + } + } + } else if (packet.getActions().stream().allMatch(p -> p.getSource().getType() == InventorySource.Type.CONTAINER || p.getSource().getType() == InventorySource.Type.UNTRACKED_INTERACTION_UI)) { + //either moving 1 item or swapping 2 slots (touchscreen or one slot shift click) + InventoryAction fromAction; + InventoryAction toAction; + //find source slot + if (packet.getActions().get(0).getFromItem().getCount() > packet.getActions().get(0).getToItem().getCount()) { + fromAction = packet.getActions().get(0); + toAction = packet.getActions().get(1); + } else { + fromAction = packet.getActions().get(1); + toAction = packet.getActions().get(0); + } + int fromSlot = translator.bedrockSlotToJava(fromAction); + int toSlot = translator.bedrockSlotToJava(toAction); + + //check if dealing with output only slot like furnace. this is to handle a situation where the output slot was partially emptied without right clicking (touchscreen or full inventory) + //this is only possible by shift clicking + if (translator.isOutputSlot(fromAction) && fromAction.getToItem().getCount() != 0) { + ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + fromSlot, InventoryUtils.fixNbt(inventory.getItem(fromSlot)), WindowAction.SHIFT_CLICK_ITEM, ShiftClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(shiftClickPacket); + inventory.getItems()[toSlot] = TranslatorsInit.getItemTranslator().translateToJava(toAction.getToItem()); + inventory.getItems()[fromSlot] = TranslatorsInit.getItemTranslator().translateToJava(fromAction.getToItem()); + return; + } else { + //pickup fromAction item + ClientWindowActionPacket leftClick1Packet = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + fromSlot, InventoryUtils.fixNbt(TranslatorsInit.getItemTranslator().translateToJava(fromAction.getFromItem())), WindowAction.CLICK_ITEM, + ClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(leftClick1Packet); + System.out.println(leftClick1Packet); + //release fromAction item into toAction slot + ClientWindowActionPacket leftClick2Packet = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + toSlot, InventoryUtils.fixNbt(TranslatorsInit.getItemTranslator().translateToJava(toAction.getFromItem())), WindowAction.CLICK_ITEM, + ClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(leftClick2Packet); + System.out.println(leftClick2Packet); + //test if swapping two items or moving one item + //if swapping then complete it + if (fromAction.getToItem().getId() != 0) { + ClientWindowActionPacket leftClick3Packet = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + fromSlot, null, WindowAction.CLICK_ITEM, + ClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(leftClick3Packet); + } + inventory.getItems()[toSlot] = TranslatorsInit.getItemTranslator().translateToJava(toAction.getToItem()); + inventory.getItems()[fromSlot] = TranslatorsInit.getItemTranslator().translateToJava(fromAction.getToItem()); + return; + } + } + } else if (packet.getActions().size() > 2) { + //shift click or fill stack? + ItemData firstItem; + if (packet.getActions().get(0).getFromItem().getId() != 0) { + firstItem = packet.getActions().get(0).getFromItem(); + } else { + firstItem = packet.getActions().get(0).getToItem(); + } + List sourceActions = new ArrayList<>(packet.getActions().size()); + List destActions = new ArrayList<>(packet.getActions().size()); + boolean sameItems = true; + for (InventoryAction action : packet.getActions()) { + if (action.getFromItem().getCount() > action.getToItem().getCount()) { + if (!InventoryUtils.canCombine(action.getFromItem(), firstItem)) + sameItems = false; + sourceActions.add(action); + } else { + if (!InventoryUtils.canCombine(action.getToItem(), firstItem)) + sameItems = false; + destActions.add(action); + } + } + if (sameItems) { + if (sourceActions.size() == 1) { //shift click + InventoryAction sourceAction = sourceActions.get(0); + //in java edition, shift clicked item must move across hotbar and main inventory + if (sourceAction.getSource().getContainerId() == ContainerId.INVENTORY) { + for (InventoryAction action : packet.getActions()) { + if (action != sourceAction && action.getSource().getContainerId() == ContainerId.INVENTORY) { + if ((sourceAction.getSlot() < 9 && action.getSlot() < 9) || (sourceAction.getSlot() >= 9 && action.getSlot() >= 9)) { + //shift click not compatible with java edition. refresh inventory and abort + translator.updateInventory(session, inventory); + return; + } + } + } + } + int javaSlot = translator.bedrockSlotToJava(sourceAction); + ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + javaSlot, InventoryUtils.fixNbt(inventory.getItem(javaSlot)), WindowAction.SHIFT_CLICK_ITEM, ShiftClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(shiftClickPacket); + return; + } else if (destActions.size() == 1) { //fill stack + InventoryAction destAction = destActions.get(0); + int javaSlot; + if (destAction != cursorAction) { //if touchscreen + javaSlot = translator.bedrockSlotToJava(destAction); + ClientWindowActionPacket leftClickPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + javaSlot, InventoryUtils.fixNbt(inventory.getItem(javaSlot)), WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(leftClickPacket); + } else { + javaSlot = session.getLastClickedSlot(); + } + ClientWindowActionPacket fillStackPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + javaSlot, null, WindowAction.FILL_STACK, FillStackParam.FILL); + session.getDownstream().getSession().send(fillStackPacket); + if (destAction != cursorAction) { //if touchscreen + ClientWindowActionPacket leftClickPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + javaSlot, null, WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(leftClickPacket); + inventory.getItems()[javaSlot] = TranslatorsInit.getItemTranslator().translateToJava(destAction.getToItem()); + } + translator.updateInventory(session, inventory); + return; + } + } + } + + //refresh inventory, transaction was not translated + translator.updateInventory(session, inventory); + break; + case INVENTORY_MISMATCH: + InventorySlotPacket cursorPacket = new InventorySlotPacket(); + cursorPacket.setContainerId(ContainerId.CURSOR); + cursorPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(session.getInventory().getCursor())); + session.getUpstream().sendPacket(cursorPacket); + + Inventory inv = session.getInventoryCache().getOpenInventory(); + if (inv == null) + inv = session.getInventory(); + TranslatorsInit.getInventoryTranslators().get(inv.getWindowType()).updateInventory(session, inv); case ITEM_USE: if (packet.getActionType() == 1) { ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java new file mode 100644 index 00000000..bd2aa581 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java @@ -0,0 +1,163 @@ +/* + * 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.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.*; +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.block.BlockEntry; +import org.geysermc.connector.world.GlobalBlockPalette; + +public class ChestInventoryTranslator extends InventoryTranslator { + public ChestInventoryTranslator(int size) { + super(size); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + Vector3i position = session.getPlayerEntity().getPosition().toInt(); + position = position.add(Vector3i.UP); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(position); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); //chest + blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.getUpstream().sendPacket(blockPacket); + if (size > 27) { + Vector3i pairPosition = position.add(Vector3i.UNIT_X); + blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(pairPosition); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); + blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.getUpstream().sendPacket(blockPacket); + + CompoundTag tag = CompoundTag.EMPTY.toBuilder() + .stringTag("id", "Chest") + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .intTag("pairx", pairPosition.getX()) + .intTag("pairz", pairPosition.getZ()).buildRootTag(); + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(position); + session.getUpstream().sendPacket(dataPacket); + + tag = CompoundTag.EMPTY.toBuilder() + .stringTag("id", "Chest") + .intTag("x", pairPosition.getX()) + .intTag("y", pairPosition.getY()) + .intTag("z", pairPosition.getZ()) + .intTag("pairx", position.getX()) + .intTag("pairz", position.getZ()).buildRootTag(); + dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(pairPosition); + session.getUpstream().sendPacket(dataPacket); + } + inventory.setHolderPosition(position); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.CONTAINER.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.getUpstream().sendPacket(containerOpenPacket); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + Vector3i holderPos = inventory.getHolderPosition(); + Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + session.getUpstream().sendPacket(blockPacket); + + if (this.size > 27) { + holderPos = holderPos.add(Vector3i.UNIT_X); + pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + realBlock = session.getChunkCache().getBlockAt(pos); + blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + session.getUpstream().sendPacket(blockPacket); + } + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + //need to pad empty slots for 1x9, 2x9, 4x9, and 5x9 + int paddedSize; + if (this.size > 27) { + paddedSize = 54; + } else { + paddedSize = 27; + } + ItemData[] bedrockItems = new ItemData[paddedSize]; + for (int i = 0; i < bedrockItems.length; i++) { + if (i <= this.size) { + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } else { + bedrockItems[i] = ItemData.AIR; + } + } + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(inventory.getId()); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + + Inventory playerInventory = session.getInventory(); + for (int i = 0; i < 36; i++) { + playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; + } + TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java new file mode 100644 index 00000000..6fe4f102 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java @@ -0,0 +1,87 @@ +/* + * 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.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.block.BlockEntry; +import org.geysermc.connector.world.GlobalBlockPalette; + +public class DispenserInventoryTranslator extends InventoryTranslator { + public DispenserInventoryTranslator() { + super(9); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + Vector3i position = session.getPlayerEntity().getPosition().toInt(); + position = position.add(Vector3i.UP); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(position); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(23 << 4)); //dispenser + blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.getUpstream().sendPacket(blockPacket); + inventory.setHolderPosition(position); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.DISPENSER.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.getUpstream().sendPacket(containerOpenPacket); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + Vector3i holderPos = inventory.getHolderPosition(); + Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + session.getUpstream().sendPacket(blockPacket); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java new file mode 100644 index 00000000..d46bcde0 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -0,0 +1,108 @@ +/* + * 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.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.*; +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.block.BlockEntry; +import org.geysermc.connector.world.GlobalBlockPalette; + +public class FurnaceInventoryTranslator extends InventoryTranslator { + public FurnaceInventoryTranslator() { + super(3); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + Vector3i position = session.getPlayerEntity().getPosition().toInt(); + position = position.add(Vector3i.UP); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(position); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(61 << 4)); //furnace + blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.getUpstream().sendPacket(blockPacket); + inventory.setHolderPosition(position); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.FURNACE.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.getUpstream().sendPacket(containerOpenPacket); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + //bedrock protocol library is currently missing property mappings for windows. only the furnace arrow will update for now + ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); + dataPacket.setWindowId((byte) inventory.getId()); + switch (key) { + case 0: + dataPacket.setProperty(ContainerSetDataPacket.Property.FURNACE_LIT_TIME); + break; + case 1: + dataPacket.setProperty(ContainerSetDataPacket.Property.FURNACE_LIT_DURATION); + break; + case 2: + dataPacket.setProperty(ContainerSetDataPacket.Property.FURNACE_TICK_COUNT); + break; + default: + return; + } + dataPacket.setValue((short) value); + session.getUpstream().sendPacket(dataPacket); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + Vector3i holderPos = inventory.getHolderPosition(); + Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + session.getUpstream().sendPacket(blockPacket); + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return action.getSlot() == 2; + } +} 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 deleted file mode 100644 index 862117f9..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GenericInventoryTranslator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.nukkitx.math.vector.Vector3i; -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; - -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(Vector3i.ZERO); - session.getUpstream().sendPacket(containerOpenPacket); - } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - 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(inventory.getId()); - contentPacket.setContents(bedrockItems); - session.getUpstream().sendPacket(contentPacket); - } - - @Override - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(inventory.getId()); - 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/HopperInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java new file mode 100644 index 00000000..28203d35 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java @@ -0,0 +1,87 @@ +/* + * 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.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.block.BlockEntry; +import org.geysermc.connector.world.GlobalBlockPalette; + +public class HopperInventoryTranslator extends InventoryTranslator { + public HopperInventoryTranslator() { + super(5); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + Vector3i position = session.getPlayerEntity().getPosition().toInt(); + position = position.add(Vector3i.UP); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(position); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(154 << 4)); //hopper + blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.getUpstream().sendPacket(blockPacket); + inventory.setHolderPosition(position); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.HOPPER.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.getUpstream().sendPacket(containerOpenPacket); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + Vector3i holderPos = inventory.getHolderPosition(); + Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + session.getUpstream().sendPacket(blockPacket); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return false; + } +} 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 index 0e244d3b..5a31a040 100644 --- 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 @@ -25,14 +25,72 @@ package org.geysermc.connector.network.translators.inventory; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.TranslatorsInit; public abstract class InventoryTranslator { + public final int size; + + InventoryTranslator(int size) { + this.size = size; + } 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); + public abstract void closeInventory(GeyserSession session, Inventory inventory); + public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value); + public void updateInventory(GeyserSession session, Inventory inventory) { + ItemData[] bedrockItems = new ItemData[this.size]; + for (int i = 0; i < bedrockItems.length; i++) { + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(inventory.getId()); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + + Inventory playerInventory = session.getInventory(); + for (int i = 0; i < 36; i++) { + playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; + } + TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); + } + + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + if (slot >= this.size) { + Inventory playerInventory = session.getInventory(); + playerInventory.getItems()[(slot + 9) - this.size] = inventory.getItem(slot); + TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateSlot(session, playerInventory, (slot + 9) - this.size); + } else { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(inventory.getId()); + slotPacket.setInventorySlot(slot); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot])); + session.getUpstream().sendPacket(slotPacket); + } + } + + public int bedrockSlotToJava(InventoryAction action) { + int slotnum = action.getSlot(); + if (action.getSource().getContainerId() == ContainerId.INVENTORY) { + //hotbar + if (slotnum >= 9) { + return slotnum + this.size - 9; + } else { + return slotnum + this.size + 27; + } + } else { + return slotnum; + } + } + + public abstract boolean isOutputSlot(InventoryAction action); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java new file mode 100644 index 00000000..153713d7 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -0,0 +1,138 @@ +/* + * 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.nukkitx.protocol.bedrock.data.*; +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; + +public class PlayerInventoryTranslator extends InventoryTranslator { + public PlayerInventoryTranslator() { + super(45); + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + InventoryContentPacket inventoryContentPacket = new InventoryContentPacket(); + inventoryContentPacket.setContainerId(ContainerId.INVENTORY); + + ItemData[] contents = new ItemData[36]; + // 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]); + } + + inventoryContentPacket.setContents(contents); + session.getUpstream().sendPacket(inventoryContentPacket); + + // Armor + InventoryContentPacket armorContentPacket = new InventoryContentPacket(); + armorContentPacket.setContainerId(ContainerId.ARMOR); + contents = new ItemData[4]; + for (int i = 5; i < 9; i++) { + contents[i - 5] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } + armorContentPacket.setContents(contents); + session.getUpstream().sendPacket(armorContentPacket); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + if (slot >= 5 && slot <= 44) { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + if (slot >= 9) { + slotPacket.setContainerId(ContainerId.INVENTORY); + if (slot >= 36) { + slotPacket.setInventorySlot(slot - 36); + } else { + slotPacket.setInventorySlot(slot); + } + } else { + slotPacket.setContainerId(ContainerId.ARMOR); + slotPacket.setInventorySlot(slot - 5); + } + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(slot))); + session.getUpstream().sendPacket(slotPacket); + } else if (slot == 0) { + //TODO: crafting output + } + } + + @Override + public int bedrockSlotToJava(InventoryAction action) { + int slotnum = action.getSlot(); + switch (action.getSource().getContainerId()) { + case ContainerId.INVENTORY: + // Inventory + if (slotnum >= 9 && slotnum <= 35) { + return slotnum; + } + // Hotbar + if (slotnum >= 0 && slotnum <= 8) { + return slotnum + 36; + } + break; + case ContainerId.ARMOR: + if (slotnum >= 0 && slotnum <= 3) { + return slotnum + 5; + } + break; + case ContainerId.CRAFTING_ADD_INGREDIENT: + case ContainerId.CRAFTING_REMOVE_INGREDIENT: + return slotnum + 1; + } + return slotnum; + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return false; + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + } +} 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 index b8d56ccf..f60b56f7 100644 --- 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 @@ -91,7 +91,6 @@ public class ItemTranslator { 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); @@ -99,7 +98,7 @@ public class ItemTranslator { if (translatedTag == null) continue; - javaValue.put(str, translatedTag); + javaTag.getValue().put(str, translatedTag); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/inventory/OpenWindowPacketTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/inventory/OpenWindowPacketTranslator.java deleted file mode 100644 index 1b6ab8dc..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/inventory/OpenWindowPacketTranslator.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.geysermc.connector.network.translators.java.inventory; - -import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket; -import com.nukkitx.protocol.bedrock.data.ContainerId; -import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.TranslatorsInit; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; - -public class OpenWindowPacketTranslator extends PacketTranslator { - @Override - public void translate(ServerOpenWindowPacket packet, GeyserSession session) { - System.out.println("debug: " + packet.getType()); - InventoryTranslator translator = TranslatorsInit.getInventoryTranslator(); - - translator.openInventory(session, new Inventory(packet.getName(), packet.getWindowId(), packet.getType(), 54)); - - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java new file mode 100644 index 00000000..dcb0c9fe --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -0,0 +1,43 @@ +/* + * 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.window; + +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket; +import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +public class JavaCloseWindowTranslator extends PacketTranslator { + + @Override + public void translate(ServerCloseWindowPacket packet, GeyserSession session) { + ContainerClosePacket closePacket = new ContainerClosePacket(); + closePacket.setWindowId((byte)packet.getWindowId()); + session.getUpstream().sendPacket(closePacket); + InventoryUtils.closeInventory(session, packet.getWindowId()); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java new file mode 100644 index 00000000..fc935662 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java @@ -0,0 +1,46 @@ +/* + * 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.window; + +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerConfirmTransactionPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +public class JavaConfirmTransactionTranslator extends PacketTranslator { + + @Override + public void translate(ServerConfirmTransactionPacket packet, GeyserSession session) { + System.out.println(packet); + if (!packet.isAccepted()) { + ClientConfirmTransactionPacket confirmPacket = new ClientConfirmTransactionPacket(packet.getWindowId(), packet.getActionId(), true); + session.getDownstream().getSession().send(confirmPacket); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index eca93a88..d67ad027 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -25,44 +25,57 @@ package org.geysermc.connector.network.translators.java.window; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; +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.session.cache.InventoryCache; import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.utils.InventoryUtils; +import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +import java.util.Objects; 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); + if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor + if (Objects.equals(session.getInventory().getCursor(), packet.getItem())) + return; + + //bedrock client is bugged when changing the cursor. reopen inventory after changing it + if (packet.getItem() == null && session.getInventory().getCursor() != null) { + InventorySlotPacket cursorPacket = new InventorySlotPacket(); + cursorPacket.setContainerId(ContainerId.CURSOR); + cursorPacket.setSlot(ItemData.AIR); + session.getUpstream().sendPacket(cursorPacket); + + Inventory inventory = session.getInventoryCache().getOpenInventory(); + if (inventory != null) { + session.setReopeningWindow(inventory.getId()); + } else { + inventory = session.getInventory(); + } + ContainerClosePacket closePacket = new ContainerClosePacket(); + closePacket.setWindowId((byte)inventory.getId()); + session.getUpstream().sendPacket(closePacket); + } + + session.getInventory().setCursor(packet.getItem()); return; } - Inventory inventory = inventoryCache.getInventories().get(packet.getWindowId()); - if (packet.getWindowId() != 0 && inventory.getWindowType() == null) + Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId()); + if (inventory == null || (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); - } + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + if (translator != null) { + inventory.getItems()[packet.getSlot()] = packet.getItem(); + translator.updateSlot(session, inventory, packet.getSlot()); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java index 8f27e0ee..ce6b4f6c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java @@ -30,26 +30,22 @@ 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.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; 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); + Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId()); + if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null)) return; - } - Inventory inventory = inventoryCache.getInventories().get(packet.getWindowId()); - // Player inventory - if (packet.getWindowId() == 0) { - inventory.setItems(packet.getItems()); - InventoryUtils.refreshPlayerInventory(session, inventory); - return; + inventory.setItems(packet.getItems()); + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + if (translator != null) { + translator.updateInventory(session, inventory); } - - InventoryUtils.updateInventory(session, packet); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java new file mode 100644 index 00000000..2127a94b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java @@ -0,0 +1,24 @@ +package org.geysermc.connector.network.translators.java.window; + +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowPropertyPacket; +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.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +public class JavaWindowPropertyTranslator extends PacketTranslator { + + @Override + public void translate(ServerWindowPropertyPacket packet, GeyserSession session) { + Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId()); + if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null)) + return; + + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + if (translator != null) { + translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue()); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index a56b6ed7..b979aadb 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -1,113 +1,63 @@ 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.data.game.window.WindowType; 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.github.steveice10.opennbt.tag.builtin.CompoundTag; 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.Objects; 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.getInventoryTranslator(); - 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); + Inventory inventory = new Inventory(packet.getWindowId(), packet.getType()); + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + if (translator != null) { + session.getInventoryCache().cacheInventory(inventory); + session.getInventoryCache().setOpenInventory(inventory); + translator.prepareInventory(session, inventory); + //TODO: find better way to handle double chest delay + if (inventory.getWindowType() == WindowType.GENERIC_9X4 || inventory.getWindowType() == WindowType.GENERIC_9X5 || inventory.getWindowType() == WindowType.GENERIC_9X6) { + Geyser.getGeneralThreadPool().schedule(() -> { + translator.openInventory(session, inventory); + translator.updateInventory(session, inventory); + }, 200, TimeUnit.MILLISECONDS); + } else { + translator.openInventory(session, inventory); + } + } } - 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.getInventoryTranslator(); - if (translator == null) { - session.getDownstream().getSession().send(new ClientCloseWindowPacket(packet.getWindowId())); - return; + public static void closeInventory(GeyserSession session, int windowId) { + if (windowId != 0) { + Inventory inventory = session.getInventoryCache().getInventories().get(windowId); + if (inventory != null) { + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + translator.closeInventory(session, inventory); + session.getInventoryCache().uncacheInventory(windowId); + } + session.getInventoryCache().setOpenInventory(null); } - - openInventory.setItems(packet.getItems()); - translator.updateInventory(session, openInventory); } - public static void updateSlot(GeyserSession session, ServerSetSlotPacket packet) { - if (packet.getWindowId() == 0) - return; + //currently, ItemStack.equals() does not check the item id + public static boolean canCombine(ItemData stack1, ItemData stack2) { + if (stack1 == null || stack2 == null) + return false; + return stack1.getId() == stack2.getId() && stack1.equals(stack2, false, true, true); + } - 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.getInventoryTranslator(); - 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()); + //NPE if nbt tag is null + public static ItemStack fixNbt(ItemStack stack) { + if (stack == null) + return null; + return new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() == null ? new CompoundTag("") : stack.getNbt()); } } From 3812712a06faedca6e50117cb02d5a566c51030b Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 20 Oct 2019 13:29:21 -0800 Subject: [PATCH 03/32] Remove debug messages --- .../bedrock/BedrockInventoryTransactionTranslator.java | 4 ---- .../java/window/JavaConfirmTransactionTranslator.java | 1 - 2 files changed, 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index e3301604..78509d12 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -140,7 +140,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Sun, 20 Oct 2019 13:52:21 -0800 Subject: [PATCH 04/32] Add delay when reopening inventory --- .../java/window/JavaSetSlotTranslator.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index d67ad027..0392a52c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -30,6 +30,7 @@ import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; +import org.geysermc.api.Geyser; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -37,6 +38,7 @@ import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import java.util.Objects; +import java.util.concurrent.TimeUnit; public class JavaSetSlotTranslator extends PacketTranslator { @@ -53,15 +55,17 @@ public class JavaSetSlotTranslator extends PacketTranslator cursorPacket.setSlot(ItemData.AIR); session.getUpstream().sendPacket(cursorPacket); - Inventory inventory = session.getInventoryCache().getOpenInventory(); - if (inventory != null) { - session.setReopeningWindow(inventory.getId()); - } else { - inventory = session.getInventory(); - } - ContainerClosePacket closePacket = new ContainerClosePacket(); - closePacket.setWindowId((byte)inventory.getId()); - session.getUpstream().sendPacket(closePacket); + Geyser.getGeneralThreadPool().schedule(() -> { + Inventory inventory = session.getInventoryCache().getOpenInventory(); + if (inventory != null) { + session.setReopeningWindow(inventory.getId()); + } else { + inventory = session.getInventory(); + } + ContainerClosePacket closePacket = new ContainerClosePacket(); + closePacket.setWindowId((byte) inventory.getId()); + session.getUpstream().sendPacket(closePacket); + }, 150, TimeUnit.MILLISECONDS); } session.getInventory().setCursor(packet.getItem()); From 06358b2449c11ec84761fd568fa7c4ccd7575d4b Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 20 Oct 2019 15:24:29 -0800 Subject: [PATCH 05/32] Update JavaSetSlotTranslator.java --- .../java/window/JavaSetSlotTranslator.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 0392a52c..562eb193 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -55,17 +55,15 @@ public class JavaSetSlotTranslator extends PacketTranslator cursorPacket.setSlot(ItemData.AIR); session.getUpstream().sendPacket(cursorPacket); - Geyser.getGeneralThreadPool().schedule(() -> { - Inventory inventory = session.getInventoryCache().getOpenInventory(); - if (inventory != null) { - session.setReopeningWindow(inventory.getId()); - } else { - inventory = session.getInventory(); - } - ContainerClosePacket closePacket = new ContainerClosePacket(); - closePacket.setWindowId((byte) inventory.getId()); - session.getUpstream().sendPacket(closePacket); - }, 150, TimeUnit.MILLISECONDS); + Inventory inventory = session.getInventoryCache().getOpenInventory(); + if (inventory != null) { + session.setReopeningWindow(inventory.getId()); + } else { + inventory = session.getInventory(); + } + ContainerClosePacket closePacket = new ContainerClosePacket(); + closePacket.setWindowId((byte) inventory.getId()); + Geyser.getGeneralThreadPool().schedule(() -> session.getUpstream().sendPacket(closePacket), 150, TimeUnit.MILLISECONDS); } session.getInventory().setCursor(packet.getItem()); From 4074582059be6d5ee40124e0cb2ee8b35570336c Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 20 Oct 2019 19:41:46 -0800 Subject: [PATCH 06/32] Close open inventory before opening a new one --- .../network/translators/TranslatorsInit.java | 12 +- .../DoubleChestInventoryTranslator.java | 157 ++++++++++++++++++ ...va => SingleChestInventoryTranslator.java} | 57 +------ .../java/window/JavaOpenWindowTranslator.java | 29 +++- .../connector/utils/InventoryUtils.java | 8 +- 5 files changed, 199 insertions(+), 64 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ChestInventoryTranslator.java => SingleChestInventoryTranslator.java} (66%) 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 74c50dbf..09741a23 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 @@ -162,12 +162,12 @@ public class TranslatorsInit { private static void registerInventoryTranslators() { inventoryTranslators.put(null, new PlayerInventoryTranslator()); //player inventory - inventoryTranslators.put(WindowType.GENERIC_9X1, new ChestInventoryTranslator(9)); - inventoryTranslators.put(WindowType.GENERIC_9X2, new ChestInventoryTranslator(18)); - inventoryTranslators.put(WindowType.GENERIC_9X3, new ChestInventoryTranslator(27)); - inventoryTranslators.put(WindowType.GENERIC_9X4, new ChestInventoryTranslator(36)); - inventoryTranslators.put(WindowType.GENERIC_9X5, new ChestInventoryTranslator(45)); - inventoryTranslators.put(WindowType.GENERIC_9X6, new ChestInventoryTranslator(54)); + inventoryTranslators.put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9)); + inventoryTranslators.put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18)); + inventoryTranslators.put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27)); + inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); + inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); + inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); inventoryTranslators.put(WindowType.GENERIC_3X3, new DispenserInventoryTranslator()); inventoryTranslators.put(WindowType.HOPPER, new HopperInventoryTranslator()); inventoryTranslators.put(WindowType.FURNACE, new FurnaceInventoryTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java new file mode 100644 index 00000000..027c59c6 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -0,0 +1,157 @@ +/* + * 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.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +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.block.BlockEntry; +import org.geysermc.connector.world.GlobalBlockPalette; + +public class DoubleChestInventoryTranslator extends InventoryTranslator { + public DoubleChestInventoryTranslator(int size) { + super(size); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); + Vector3i pairPosition = position.add(Vector3i.UNIT_X); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(position); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); //chest + blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.getUpstream().sendPacket(blockPacket); + + CompoundTag tag = CompoundTag.EMPTY.toBuilder() + .stringTag("id", "Chest") + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .intTag("pairx", pairPosition.getX()) + .intTag("pairz", pairPosition.getZ()).buildRootTag(); + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(position); + session.getUpstream().sendPacket(dataPacket); + + blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(pairPosition); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); + blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.getUpstream().sendPacket(blockPacket); + + tag = CompoundTag.EMPTY.toBuilder() + .stringTag("id", "Chest") + .intTag("x", pairPosition.getX()) + .intTag("y", pairPosition.getY()) + .intTag("z", pairPosition.getZ()) + .intTag("pairx", position.getX()) + .intTag("pairz", position.getZ()).buildRootTag(); + dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(pairPosition); + session.getUpstream().sendPacket(dataPacket); + + inventory.setHolderPosition(position); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.CONTAINER.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.getUpstream().sendPacket(containerOpenPacket); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + Vector3i holderPos = inventory.getHolderPosition(); + Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + session.getUpstream().sendPacket(blockPacket); + + holderPos = holderPos.add(Vector3i.UNIT_X); + pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + realBlock = session.getChunkCache().getBlockAt(pos); + blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + session.getUpstream().sendPacket(blockPacket); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + //need to pad empty slots for 4x9, and 5x9 + final int paddedSize = 54; + ItemData[] bedrockItems = new ItemData[paddedSize]; + for (int i = 0; i < bedrockItems.length; i++) { + if (i <= this.size) { + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } else { + bedrockItems[i] = ItemData.AIR; + } + } + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(inventory.getId()); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + + Inventory playerInventory = session.getInventory(); + for (int i = 0; i < 36; i++) { + playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; + } + TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java similarity index 66% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index bd2aa581..fd58e7c6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -39,8 +39,8 @@ import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.block.BlockEntry; import org.geysermc.connector.world.GlobalBlockPalette; -public class ChestInventoryTranslator extends InventoryTranslator { - public ChestInventoryTranslator(int size) { +public class SingleChestInventoryTranslator extends InventoryTranslator { + public SingleChestInventoryTranslator(int size) { super(size); } @@ -54,39 +54,6 @@ public class ChestInventoryTranslator extends InventoryTranslator { blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); //chest blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); - if (size > 27) { - Vector3i pairPosition = position.add(Vector3i.UNIT_X); - blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); - blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - session.getUpstream().sendPacket(blockPacket); - - CompoundTag tag = CompoundTag.EMPTY.toBuilder() - .stringTag("id", "Chest") - .intTag("x", position.getX()) - .intTag("y", position.getY()) - .intTag("z", position.getZ()) - .intTag("pairx", pairPosition.getX()) - .intTag("pairz", pairPosition.getZ()).buildRootTag(); - BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); - dataPacket.setData(tag); - dataPacket.setBlockPosition(position); - session.getUpstream().sendPacket(dataPacket); - - tag = CompoundTag.EMPTY.toBuilder() - .stringTag("id", "Chest") - .intTag("x", pairPosition.getX()) - .intTag("y", pairPosition.getY()) - .intTag("z", pairPosition.getZ()) - .intTag("pairx", position.getX()) - .intTag("pairz", position.getZ()).buildRootTag(); - dataPacket = new BlockEntityDataPacket(); - dataPacket.setData(tag); - dataPacket.setBlockPosition(pairPosition); - session.getUpstream().sendPacket(dataPacket); - } inventory.setHolderPosition(position); } @@ -110,17 +77,6 @@ public class ChestInventoryTranslator extends InventoryTranslator { blockPacket.setBlockPosition(holderPos); blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); session.getUpstream().sendPacket(blockPacket); - - if (this.size > 27) { - holderPos = holderPos.add(Vector3i.UNIT_X); - pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - realBlock = session.getChunkCache().getBlockAt(pos); - blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); - session.getUpstream().sendPacket(blockPacket); - } } @Override @@ -129,13 +85,8 @@ public class ChestInventoryTranslator extends InventoryTranslator { @Override public void updateInventory(GeyserSession session, Inventory inventory) { - //need to pad empty slots for 1x9, 2x9, 4x9, and 5x9 - int paddedSize; - if (this.size > 27) { - paddedSize = 54; - } else { - paddedSize = 27; - } + //need to pad empty slots for 1x9 and 2x9 + final int paddedSize = 27; ItemData[] bedrockItems = new ItemData[paddedSize]; for (int i = 0; i < bedrockItems.length; i++) { if (i <= this.size) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index b5e0447c..95aa618c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -25,15 +25,42 @@ package org.geysermc.connector.network.translators.java.window; +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 org.geysermc.api.Geyser; +import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.utils.InventoryUtils; +import java.util.concurrent.TimeUnit; + public class JavaOpenWindowTranslator extends PacketTranslator { @Override public void translate(ServerOpenWindowPacket packet, GeyserSession session) { - InventoryUtils.openInventory(session, packet); + InventoryTranslator newTranslator = TranslatorsInit.getInventoryTranslators().get(packet.getType()); + if (newTranslator == null) { + ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId()); + session.getDownstream().getSession().send(closeWindowPacket); + return; + } + Inventory openInventory = session.getInventoryCache().getOpenInventory(); + Inventory newInventory = new Inventory(packet.getWindowId(), packet.getType()); + newInventory.setItems(new ItemStack[newTranslator.size + 36]); + session.getInventoryCache().cacheInventory(newInventory); + if (openInventory != null) { + InventoryTranslator openTranslator = TranslatorsInit.getInventoryTranslators().get(openInventory.getWindowType()); + if (!openTranslator.getClass().equals(newTranslator.getClass())) { + InventoryUtils.closeInventory(session, openInventory.getId()); + Geyser.getGeneralThreadPool().schedule(() -> InventoryUtils.openInventory(session, newInventory), 350, TimeUnit.MILLISECONDS); + return; + } + } + + InventoryUtils.openInventory(session, newInventory); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index b979aadb..2663ab37 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -9,6 +9,7 @@ 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.DoubleChestInventoryTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import java.util.Objects; @@ -16,21 +17,20 @@ import java.util.concurrent.TimeUnit; public class InventoryUtils { - public static void openInventory(GeyserSession session, ServerOpenWindowPacket packet) { - Inventory inventory = new Inventory(packet.getWindowId(), packet.getType()); + public static void openInventory(GeyserSession session, Inventory inventory) { InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); if (translator != null) { - session.getInventoryCache().cacheInventory(inventory); session.getInventoryCache().setOpenInventory(inventory); translator.prepareInventory(session, inventory); //TODO: find better way to handle double chest delay - if (inventory.getWindowType() == WindowType.GENERIC_9X4 || inventory.getWindowType() == WindowType.GENERIC_9X5 || inventory.getWindowType() == WindowType.GENERIC_9X6) { + if (translator instanceof DoubleChestInventoryTranslator) { Geyser.getGeneralThreadPool().schedule(() -> { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); }, 200, TimeUnit.MILLISECONDS); } else { translator.openInventory(session, inventory); + translator.updateInventory(session, inventory); } } } From 08357ed8b2ae7836f26b6dcd63b82277675a7607 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 21 Oct 2019 00:12:27 -0800 Subject: [PATCH 07/32] Uncache chunks --- .../network/translators/TranslatorsInit.java | 1 + .../java/JavaRespawnTranslator.java | 1 + .../java/world/JavaUnloadChunkTranslator.java | 39 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java 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 09741a23..46c13d3d 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 @@ -135,6 +135,7 @@ public class TranslatorsInit { Registry.registerJava(ServerTeamPacket.class, new JavaTeamTranslator()); Registry.registerJava(ServerBlockChangePacket.class, new JavaBlockChangeTranslator()); Registry.registerJava(ServerMultiBlockChangePacket.class, new JavaMultiBlockChangeTranslator()); + Registry.registerJava(ServerUnloadChunkPacket.class, new JavaUnloadChunkTranslator()); Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator()); Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java index f5f86e19..4661b1cf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java @@ -44,6 +44,7 @@ public class JavaRespawnTranslator extends PacketTranslator if (entity.getDimension() == getDimension(packet.getDimension())) return; + session.getChunkCache().getChunks().clear(); entity.setDimension(getDimension(packet.getDimension())); ChangeDimensionPacket changeDimensionPacket = new ChangeDimensionPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java new file mode 100644 index 00000000..b727f440 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.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.world; + +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUnloadChunkPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.world.chunk.ChunkPosition; + +public class JavaUnloadChunkTranslator extends PacketTranslator { + + @Override + public void translate(ServerUnloadChunkPacket packet, GeyserSession session) { + session.getChunkCache().removeChunk(new ChunkPosition(packet.getX(), packet.getZ())); + } +} From 12c049709a8274c17705f9a7a0d1e99a293bb250 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 21 Oct 2019 03:16:02 -0800 Subject: [PATCH 08/32] Fix item nbt translator Mineplex server seemed to be sensitive about quotes in string tags --- .../connector/network/translators/item/ItemTranslator.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 index f60b56f7..071ab75d 100644 --- 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 @@ -91,6 +91,7 @@ public class ItemTranslator { 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); @@ -98,10 +99,11 @@ public class ItemTranslator { if (translatedTag == null) continue; - javaTag.getValue().put(str, translatedTag); + javaValue.put(str, translatedTag); } } + javaTag.setValue(javaValue); return javaTag; } @@ -153,7 +155,7 @@ public class ItemTranslator { 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()); + return new StringTag(stringTag.getName(), '"' + stringTag.getValue() + '"'); } if (tag instanceof com.nukkitx.nbt.tag.ListTag) { From 38fd5376e7364c9d4105f6969a5a79aaa62d66cf Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 21 Oct 2019 16:07:07 -0800 Subject: [PATCH 09/32] Revert storing chunks in chunk cache --- .../java/entity/player/JavaPlayerActionAckTranslator.java | 1 - .../translators/java/world/JavaBlockChangeTranslator.java | 2 -- .../network/translators/java/world/JavaChunkDataTranslator.java | 1 - .../translators/java/world/JavaMultiBlockChangeTranslator.java | 1 - 4 files changed, 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java index cf5c26bc..3213a2fd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java @@ -40,7 +40,6 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator { Vector2i chunkPos = session.getLastChunkPosition(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java index b78e366c..14864b8c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java @@ -40,7 +40,6 @@ public class JavaMultiBlockChangeTranslator extends PacketTranslator Date: Tue, 22 Oct 2019 15:31:03 -0800 Subject: [PATCH 10/32] Various fixes Fix offhand, use AtomicInteger for transaction id, send null stack instead of air, and clear open inventory on dimension change --- .../connector/inventory/Inventory.java | 20 ++++++---- .../connector/inventory/PlayerInventory.java | 4 +- ...BedrockInventoryTransactionTranslator.java | 37 +++++++++---------- .../inventory/PlayerInventoryTranslator.java | 15 +++++++- .../java/JavaRespawnTranslator.java | 1 + .../java/window/JavaOpenWindowTranslator.java | 15 ++++++-- .../window/JavaWindowItemsTranslator.java | 11 ++++-- .../connector/utils/InventoryUtils.java | 6 +-- 8 files changed, 69 insertions(+), 40 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 215ac597..2147b070 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -31,6 +31,8 @@ import com.nukkitx.math.vector.Vector3i; import lombok.Getter; import lombok.Setter; +import java.util.concurrent.atomic.AtomicInteger; + public class Inventory { @Getter @@ -43,6 +45,9 @@ public class Inventory { @Getter protected WindowType windowType; + @Getter + protected final int size; + @Getter @Setter protected String title; @@ -59,23 +64,22 @@ public class Inventory { @Setter protected long holderId = -1; - protected short transactionId = 1; + @Getter + protected AtomicInteger transactionId = new AtomicInteger(1); - public Inventory(int id, WindowType windowType) { - this("Inventory", id, windowType); + public Inventory(int id, WindowType windowType, int size) { + this("Inventory", id, windowType, size); } - public Inventory(String title, int id, WindowType windowType) { + public Inventory(String title, int id, WindowType windowType, int size) { this.title = title; this.id = id; this.windowType = windowType; + this.size = size; + this.items = new ItemStack[size]; } public ItemStack getItem(int slot) { return items[slot]; } - - public short getNextTransactionId() { - return transactionId++; - } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java index 44ad3cb6..4fd3bcd8 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -39,9 +39,7 @@ public class PlayerInventory extends Inventory { private ItemStack cursor; public PlayerInventory() { - super(0, null); - - items = new ItemStack[45]; + super(0, null, 46); heldItemSlot = 0; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 78509d12..c0b805aa 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -45,7 +45,6 @@ import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -110,13 +109,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator cursorAction.getFromItem().getCount()) { //fill stack int javaSlot = session.getLastClickedSlot(); - ClientWindowActionPacket fillStackPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getNextTransactionId(), + ClientWindowActionPacket fillStackPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), javaSlot, null, WindowAction.FILL_STACK, FillStackParam.FILL); session.getDownstream().getSession().send(fillStackPacket); translator.updateInventory(session, inventory); //bedrock fill stack can sometimes differ from java version, refresh and let server change slots @@ -153,8 +152,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator if (entity.getDimension() == getDimension(packet.getDimension())) return; + session.getInventoryCache().setOpenInventory(null); session.getChunkCache().getChunks().clear(); entity.setDimension(getDimension(packet.getDimension())); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 95aa618c..9e336ebd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.java.window; 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.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import org.geysermc.api.Geyser; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -42,15 +43,23 @@ public class JavaOpenWindowTranslator extends PacketTranslator { @@ -42,7 +42,12 @@ public class JavaWindowItemsTranslator extends PacketTranslator Date: Fri, 1 Nov 2019 01:07:13 -0800 Subject: [PATCH 11/32] Add inventory names Some translation identifiers such as "container.blast_furnace" are not being translated yet --- .../DispenserInventoryTranslator.java | 12 ++++++++++++ .../DoubleChestInventoryTranslator.java | 6 ++++-- .../inventory/FurnaceInventoryTranslator.java | 10 ++++++++++ .../inventory/HopperInventoryTranslator.java | 12 ++++++++++++ .../SingleChestInventoryTranslator.java | 10 ++++++++++ .../java/window/JavaOpenWindowTranslator.java | 19 +++++++++++++++++-- 6 files changed, 65 insertions(+), 4 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java index 6fe4f102..9f361f39 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java @@ -27,8 +27,10 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.inventory.Inventory; @@ -52,6 +54,16 @@ public class DispenserInventoryTranslator extends InventoryTranslator { blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); inventory.setHolderPosition(position); + + CompoundTag tag = CompoundTag.EMPTY.toBuilder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(position); + session.getUpstream().sendPacket(dataPacket); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index 027c59c6..d52e9447 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -63,7 +63,8 @@ public class DoubleChestInventoryTranslator extends InventoryTranslator { .intTag("y", position.getY()) .intTag("z", position.getZ()) .intTag("pairx", pairPosition.getX()) - .intTag("pairz", pairPosition.getZ()).buildRootTag(); + .intTag("pairz", pairPosition.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag); dataPacket.setBlockPosition(position); @@ -82,7 +83,8 @@ public class DoubleChestInventoryTranslator extends InventoryTranslator { .intTag("y", pairPosition.getY()) .intTag("z", pairPosition.getZ()) .intTag("pairx", position.getX()) - .intTag("pairz", position.getZ()).buildRootTag(); + .intTag("pairz", position.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag); dataPacket.setBlockPosition(pairPosition); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index d46bcde0..c65fca02 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -55,6 +55,16 @@ public class FurnaceInventoryTranslator extends InventoryTranslator { blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); inventory.setHolderPosition(position); + + CompoundTag tag = CompoundTag.EMPTY.toBuilder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(position); + session.getUpstream().sendPacket(dataPacket); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java index 28203d35..cf877d0f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java @@ -27,8 +27,10 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.inventory.Inventory; @@ -52,6 +54,16 @@ public class HopperInventoryTranslator extends InventoryTranslator { blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); inventory.setHolderPosition(position); + + CompoundTag tag = CompoundTag.EMPTY.toBuilder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(position); + session.getUpstream().sendPacket(dataPacket); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index fd58e7c6..ef8f97cc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -55,6 +55,16 @@ public class SingleChestInventoryTranslator extends InventoryTranslator { blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); inventory.setHolderPosition(position); + + CompoundTag tag = CompoundTag.EMPTY.toBuilder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(position); + session.getUpstream().sendPacket(dataPacket); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 9e336ebd..eab7bee2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -25,9 +25,10 @@ package org.geysermc.connector.network.translators.java.window; -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.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import org.geysermc.api.Geyser; import org.geysermc.connector.inventory.Inventory; @@ -59,7 +60,21 @@ public class JavaOpenWindowTranslator extends PacketTranslator Date: Tue, 5 Nov 2019 14:17:22 -0900 Subject: [PATCH 12/32] Implement some more windows anvil, brewing stand, crafting table (still no crafting yet), shulker box --- .../network/translators/TranslatorsInit.java | 20 +++- .../BedrockContainerCloseTranslator.java | 11 +- ...BedrockInventoryTransactionTranslator.java | 93 ++++++++++------ .../inventory/AnvilInventoryTranslator.java | 60 ++++++++++ ...tor.java => BlockInventoryTranslator.java} | 25 ++--- .../BrewingStandInventoryTranslator.java | 100 +++++++++++++++++ .../ContainerInventoryTranslator.java | 103 ++++++++++++++++++ .../DispenserInventoryTranslator.java | 99 ----------------- .../DoubleChestInventoryTranslator.java | 34 +----- .../EnchantmentInventoryTranslator.java | 41 +++++++ .../inventory/FurnaceInventoryTranslator.java | 59 +--------- .../inventory/InventoryTranslator.java | 56 +--------- .../inventory/PlayerInventoryTranslator.java | 5 + .../SingleChestInventoryTranslator.java | 68 +----------- 14 files changed, 421 insertions(+), 353 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{HopperInventoryTranslator.java => BlockInventoryTranslator.java} (89%) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java 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 46c13d3d..3e5af466 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 @@ -43,6 +43,7 @@ import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.nbt.stream.NBTOutputStream; import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.packet.*; import lombok.Getter; import org.geysermc.connector.network.translators.bedrock.*; @@ -169,10 +170,19 @@ public class TranslatorsInit { inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); - inventoryTranslators.put(WindowType.GENERIC_3X3, new DispenserInventoryTranslator()); - inventoryTranslators.put(WindowType.HOPPER, new HopperInventoryTranslator()); - inventoryTranslators.put(WindowType.FURNACE, new FurnaceInventoryTranslator()); - inventoryTranslators.put(WindowType.BLAST_FURNACE, new FurnaceInventoryTranslator()); - inventoryTranslators.put(WindowType.SMOKER, new FurnaceInventoryTranslator()); + inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingStandInventoryTranslator()); + inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator()); + //inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO + + InventoryTranslator furnace = new FurnaceInventoryTranslator(); + inventoryTranslators.put(WindowType.FURNACE, furnace); + inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace); + inventoryTranslators.put(WindowType.SMOKER, furnace); + + inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, 23 << 4, ContainerType.DISPENSER)); + inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, 154 << 4, ContainerType.HOPPER)); + inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(36, 205 << 4, ContainerType.CONTAINER)); + inventoryTranslators.put(WindowType.CRAFTING, new BlockInventoryTranslator(10, 58 << 4, ContainerType.WORKBENCH)); + //inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, 138 << 4, ContainerType.BEACON)); //TODO } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index de6a9d8c..71cc9f0d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -38,7 +38,16 @@ public class BedrockContainerCloseTranslator extends PacketTranslator actions = packet.getActions(); + if (inventory.getWindowType() == WindowType.ANVIL) { + InventoryAction anvilResult = null; + InventoryAction anvilInput = null; + for (InventoryAction action : packet.getActions()) { + if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) { + anvilResult = action; + } else if (action.getSource().getContainerId() == ContainerId.CONTAINER_INPUT) { + anvilInput = action; + } + } + ItemData itemName = null; + if (anvilResult != null) { + itemName = anvilResult.getFromItem(); + actions = new ArrayList<>(2); + for (InventoryAction action : packet.getActions()) { //packet sent by client when grabbing anvil output needs useless actions stripped + if (!(action.getSource().getContainerId() == ContainerId.CONTAINER_INPUT || action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL)) { + actions.add(action); + } + } + } else if (anvilInput != null) { + itemName = anvilInput.getToItem(); + } + if (itemName != null) { + String rename; + com.nukkitx.nbt.tag.CompoundTag tag = itemName.getTag(); + if (tag != null) { + rename = tag.getAsCompound("display").getAsString("Name"); + } else { + rename = ""; + } + ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename); + session.getDownstream().getSession().send(renameItemPacket); + } + } + + if (actions.size() == 2) { if (worldAction != null && worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { //find container action InventoryAction containerAction = null; - for (InventoryAction action : packet.getActions()) { - if (action.getSource().getType() == InventorySource.Type.CONTAINER || action.getSource().getType() == InventorySource.Type.UNTRACKED_INTERACTION_UI) { + for (InventoryAction action : actions) { + if (action != worldAction) { containerAction = action; break; } @@ -125,8 +154,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator p.getSource().getType() == InventorySource.Type.CONTAINER || p.getSource().getType() == InventorySource.Type.UNTRACKED_INTERACTION_UI)) { + } else { //either moving 1 item or swapping 2 slots (touchscreen or one slot shift click) InventoryAction fromAction; InventoryAction toAction; //find source slot - if (packet.getActions().get(0).getFromItem().getCount() > packet.getActions().get(0).getToItem().getCount()) { - fromAction = packet.getActions().get(0); - toAction = packet.getActions().get(1); + if (actions.get(0).getFromItem().getCount() > actions.get(0).getToItem().getCount()) { + fromAction = actions.get(0); + toAction = actions.get(1); } else { - fromAction = packet.getActions().get(1); - toAction = packet.getActions().get(0); + fromAction = actions.get(1); + toAction = actions.get(0); } int fromSlot = translator.bedrockSlotToJava(fromAction); int toSlot = translator.bedrockSlotToJava(toAction); @@ -211,18 +240,18 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator 2) { + } else if (actions.size() > 2) { //shift click or fill stack? ItemData firstItem; - if (packet.getActions().get(0).getFromItem().getId() != 0) { - firstItem = packet.getActions().get(0).getFromItem(); + if (actions.get(0).getFromItem().getId() != 0) { + firstItem = actions.get(0).getFromItem(); } else { - firstItem = packet.getActions().get(0).getToItem(); + firstItem = actions.get(0).getToItem(); } - List sourceActions = new ArrayList<>(packet.getActions().size()); - List destActions = new ArrayList<>(packet.getActions().size()); + List sourceActions = new ArrayList<>(actions.size()); + List destActions = new ArrayList<>(actions.size()); boolean sameItems = true; - for (InventoryAction action : packet.getActions()) { + for (InventoryAction action : actions) { if (action.getFromItem().getCount() > action.getToItem().getCount()) { if (!InventoryUtils.canCombine(action.getFromItem(), firstItem)) sameItems = false; @@ -238,7 +267,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator= 9 && action.getSlot() >= 9)) { //shift click not compatible with java edition. refresh inventory and abort diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java new file mode 100644 index 00000000..9c027dc2 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java @@ -0,0 +1,60 @@ +/* + * 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.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; + +public class AnvilInventoryTranslator extends BlockInventoryTranslator { + public AnvilInventoryTranslator() { + super(3, 145 << 4, ContainerType.ANVIL); + } + + @Override + public int bedrockSlotToJava(InventoryAction action) { + int slotnum = action.getSlot(); + if (action.getSource().getContainerId() == ContainerId.INVENTORY) { + //hotbar + if (slotnum >= 9) { + return slotnum + this.size - 9; + } else { + return slotnum + this.size + 27; + } + } else { + if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) { + return 2; + } else { + return slotnum; + } + } + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return action.getSource().getContainerId() == ContainerId.ANVIL_RESULT; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java similarity index 89% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java index cf877d0f..065d63dc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/HopperInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java @@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; @@ -38,9 +37,14 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.block.BlockEntry; import org.geysermc.connector.world.GlobalBlockPalette; -public class HopperInventoryTranslator extends InventoryTranslator { - public HopperInventoryTranslator() { - super(5); +public class BlockInventoryTranslator extends ContainerInventoryTranslator { + protected final int blockId; + protected final ContainerType containerType; + + public BlockInventoryTranslator(int size, int blockId, ContainerType containerType) { + super(size); + this.blockId = blockId; + this.containerType = containerType; } @Override @@ -50,7 +54,7 @@ public class HopperInventoryTranslator extends InventoryTranslator { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(154 << 4)); //hopper + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(blockId)); blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); inventory.setHolderPosition(position); @@ -70,7 +74,7 @@ public class HopperInventoryTranslator extends InventoryTranslator { public void openInventory(GeyserSession session, Inventory inventory) { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); containerOpenPacket.setWindowId((byte) inventory.getId()); - containerOpenPacket.setType((byte) ContainerType.HOPPER.id()); + containerOpenPacket.setType((byte) containerType.id()); containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); session.getUpstream().sendPacket(containerOpenPacket); @@ -87,13 +91,4 @@ public class HopperInventoryTranslator extends InventoryTranslator { blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); session.getUpstream().sendPacket(blockPacket); } - - @Override - public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - } - - @Override - public boolean isOutputSlot(InventoryAction action) { - return false; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java new file mode 100644 index 00000000..92eb4bc8 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java @@ -0,0 +1,100 @@ +/* + * 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.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; + +public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { + public BrewingStandInventoryTranslator() { + super(5, 117 << 4, ContainerType.BREWING_STAND); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + //bedrock protocol library is currently missing property mappings for windows. + ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); + dataPacket.setWindowId((byte) inventory.getId()); + switch (key) { + case 0: + dataPacket.setProperty(ContainerSetDataPacket.Property.BREWING_STAND_BREW_TIME); + break; + case 1: + dataPacket.setProperty(ContainerSetDataPacket.Property.BREWING_STAND_FUEL_AMOUNT); + break; + default: + return; + } + dataPacket.setValue((short) value); + session.getUpstream().sendPacket(dataPacket); + } + + @Override + public int bedrockSlotToJava(InventoryAction action) { + int slotnum = action.getSlot(); + if (action.getSource().getContainerId() == ContainerId.INVENTORY) { + //hotbar + if (slotnum >= 9) { + return slotnum + this.size - 9; + } else { + return slotnum + this.size + 27; + } + } else { + switch (slotnum) { + case 0: + return 3; + case 1: + return 0; + case 2: + return 1; + case 3: + return 2; + default: + return slotnum; + } + } + } + + @Override + public int javaSlotToBedrock(int slotnum) { + switch (slotnum) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 3; + case 3: + return 0; + default: + return slotnum; + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java new file mode 100644 index 00000000..5c3ae3c8 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java @@ -0,0 +1,103 @@ +/* + * 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.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.ItemData; +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; + +public abstract class ContainerInventoryTranslator extends InventoryTranslator { + public ContainerInventoryTranslator(int size) { + super(size); + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + ItemData[] bedrockItems = new ItemData[this.size]; + for (int i = 0; i < bedrockItems.length; i++) { + bedrockItems[javaSlotToBedrock(i)] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + } + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(inventory.getId()); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + + Inventory playerInventory = session.getInventory(); + for (int i = 0; i < 36; i++) { + playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; + } + TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + if (slot >= this.size) { + Inventory playerInventory = session.getInventory(); + playerInventory.getItems()[(slot + 9) - this.size] = inventory.getItem(slot); + TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateSlot(session, playerInventory, (slot + 9) - this.size); + } else { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(inventory.getId()); + slotPacket.setInventorySlot(javaSlotToBedrock(slot)); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot])); + session.getUpstream().sendPacket(slotPacket); + } + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + } + + @Override + public int bedrockSlotToJava(InventoryAction action) { + int slotnum = action.getSlot(); + if (action.getSource().getContainerId() == ContainerId.INVENTORY) { + //hotbar + if (slotnum >= 9) { + return slotnum + this.size - 9; + } else { + return slotnum + this.size + 27; + } + } else { + return slotnum; + } + } + + @Override + public int javaSlotToBedrock(int slot) { + return slot; + } + + @Override + public boolean isOutputSlot(InventoryAction action) { + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java deleted file mode 100644 index 9f361f39..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DispenserInventoryTranslator.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.tag.CompoundTag; -import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; -import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; -import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.block.BlockEntry; -import org.geysermc.connector.world.GlobalBlockPalette; - -public class DispenserInventoryTranslator extends InventoryTranslator { - public DispenserInventoryTranslator() { - super(9); - } - - @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - Vector3i position = session.getPlayerEntity().getPosition().toInt(); - position = position.add(Vector3i.UP); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(23 << 4)); //dispenser - blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - session.getUpstream().sendPacket(blockPacket); - inventory.setHolderPosition(position); - - CompoundTag tag = CompoundTag.EMPTY.toBuilder() - .intTag("x", position.getX()) - .intTag("y", position.getY()) - .intTag("z", position.getZ()) - .stringTag("CustomName", inventory.getTitle()).buildRootTag(); - BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); - dataPacket.setData(tag); - dataPacket.setBlockPosition(position); - session.getUpstream().sendPacket(dataPacket); - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setWindowId((byte) inventory.getId()); - containerOpenPacket.setType((byte) ContainerType.DISPENSER.id()); - containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); - containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); - session.getUpstream().sendPacket(containerOpenPacket); - } - - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - Vector3i holderPos = inventory.getHolderPosition(); - Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); - session.getUpstream().sendPacket(blockPacket); - } - - @Override - public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - } - - @Override - public boolean isOutputSlot(InventoryAction action) { - return false; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index d52e9447..4b90ba07 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -29,10 +29,8 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; -import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.inventory.Inventory; @@ -41,9 +39,9 @@ import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.block.BlockEntry; import org.geysermc.connector.world.GlobalBlockPalette; -public class DoubleChestInventoryTranslator extends InventoryTranslator { +public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { public DoubleChestInventoryTranslator(int size) { - super(size); + super(size, 54 << 4, ContainerType.CONTAINER); } @Override @@ -53,7 +51,7 @@ public class DoubleChestInventoryTranslator extends InventoryTranslator { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); //chest + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(blockId)); blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); @@ -73,7 +71,7 @@ public class DoubleChestInventoryTranslator extends InventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); + blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(blockId)); blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); @@ -93,16 +91,6 @@ public class DoubleChestInventoryTranslator extends InventoryTranslator { inventory.setHolderPosition(position); } - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setWindowId((byte) inventory.getId()); - containerOpenPacket.setType((byte) ContainerType.CONTAINER.id()); - containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); - containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); - session.getUpstream().sendPacket(containerOpenPacket); - } - @Override public void closeInventory(GeyserSession session, Inventory inventory) { Vector3i holderPos = inventory.getHolderPosition(); @@ -124,15 +112,10 @@ public class DoubleChestInventoryTranslator extends InventoryTranslator { session.getUpstream().sendPacket(blockPacket); } - @Override - public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - } - @Override public void updateInventory(GeyserSession session, Inventory inventory) { - //need to pad empty slots for 4x9, and 5x9 - final int paddedSize = 54; - ItemData[] bedrockItems = new ItemData[paddedSize]; + //need to pad empty slots for 4x9 and 5x9 + ItemData[] bedrockItems = new ItemData[54]; for (int i = 0; i < bedrockItems.length; i++) { if (i <= this.size) { bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); @@ -151,9 +134,4 @@ public class DoubleChestInventoryTranslator extends InventoryTranslator { } TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); } - - @Override - public boolean isOutputSlot(InventoryAction action) { - return false; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java new file mode 100644 index 00000000..410bdc6a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java @@ -0,0 +1,41 @@ +/* + * 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.nukkitx.protocol.bedrock.data.ContainerType; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; + +public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { + public EnchantmentInventoryTranslator() { + super(2, 116 << 4, ContainerType.ENCHANTMENT); + } + + @Override + public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index c65fca02..c5296d37 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -25,56 +25,15 @@ package org.geysermc.connector.network.translators.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.tag.CompoundTag; -import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.data.InventoryAction; -import com.nukkitx.protocol.bedrock.data.ItemData; -import com.nukkitx.protocol.bedrock.packet.*; +import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; 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.block.BlockEntry; -import org.geysermc.connector.world.GlobalBlockPalette; -public class FurnaceInventoryTranslator extends InventoryTranslator { +public class FurnaceInventoryTranslator extends BlockInventoryTranslator { public FurnaceInventoryTranslator() { - super(3); - } - - @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - Vector3i position = session.getPlayerEntity().getPosition().toInt(); - position = position.add(Vector3i.UP); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(61 << 4)); //furnace - blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - session.getUpstream().sendPacket(blockPacket); - inventory.setHolderPosition(position); - - CompoundTag tag = CompoundTag.EMPTY.toBuilder() - .intTag("x", position.getX()) - .intTag("y", position.getY()) - .intTag("z", position.getZ()) - .stringTag("CustomName", inventory.getTitle()).buildRootTag(); - BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); - dataPacket.setData(tag); - dataPacket.setBlockPosition(position); - session.getUpstream().sendPacket(dataPacket); - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setWindowId((byte) inventory.getId()); - containerOpenPacket.setType((byte) ContainerType.FURNACE.id()); - containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); - containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); - session.getUpstream().sendPacket(containerOpenPacket); + super(3, 61 << 4, ContainerType.FURNACE); } @Override @@ -99,18 +58,6 @@ public class FurnaceInventoryTranslator extends InventoryTranslator { session.getUpstream().sendPacket(dataPacket); } - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - Vector3i holderPos = inventory.getHolderPosition(); - Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); - session.getUpstream().sendPacket(blockPacket); - } - @Override public boolean isOutputSlot(InventoryAction action) { return action.getSlot() == 2; 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 index 5a31a040..7181a345 100644 --- 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 @@ -25,15 +25,9 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.InventoryAction; -import com.nukkitx.protocol.bedrock.data.ItemData; -import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; -import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.TranslatorsInit; public abstract class InventoryTranslator { public final int size; @@ -46,51 +40,9 @@ public abstract class InventoryTranslator { public abstract void openInventory(GeyserSession session, Inventory inventory); public abstract void closeInventory(GeyserSession session, Inventory inventory); public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value); - - public void updateInventory(GeyserSession session, Inventory inventory) { - ItemData[] bedrockItems = new ItemData[this.size]; - for (int i = 0; i < bedrockItems.length; i++) { - bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); - } - InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); - contentPacket.setContents(bedrockItems); - session.getUpstream().sendPacket(contentPacket); - - Inventory playerInventory = session.getInventory(); - for (int i = 0; i < 36; i++) { - playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; - } - TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); - } - - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - if (slot >= this.size) { - Inventory playerInventory = session.getInventory(); - playerInventory.getItems()[(slot + 9) - this.size] = inventory.getItem(slot); - TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateSlot(session, playerInventory, (slot + 9) - this.size); - } else { - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(inventory.getId()); - slotPacket.setInventorySlot(slot); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot])); - session.getUpstream().sendPacket(slotPacket); - } - } - - public int bedrockSlotToJava(InventoryAction action) { - int slotnum = action.getSlot(); - if (action.getSource().getContainerId() == ContainerId.INVENTORY) { - //hotbar - if (slotnum >= 9) { - return slotnum + this.size - 9; - } else { - return slotnum + this.size + 27; - } - } else { - return slotnum; - } - } - + public abstract void updateInventory(GeyserSession session, Inventory inventory); + public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot); + public abstract int bedrockSlotToJava(InventoryAction action); + public abstract int javaSlotToBedrock(int slot); public abstract boolean isOutputSlot(InventoryAction action); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index 53244a9f..cfd92699 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -128,6 +128,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { return slotnum; } + @Override + public int javaSlotToBedrock(int slot) { + return slot; + } + @Override public boolean isOutputSlot(InventoryAction action) { return false; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index ef8f97cc..43ceb283 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -25,79 +25,22 @@ package org.geysermc.connector.network.translators.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.tag.CompoundTag; -import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.*; 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.block.BlockEntry; -import org.geysermc.connector.world.GlobalBlockPalette; -public class SingleChestInventoryTranslator extends InventoryTranslator { +public class SingleChestInventoryTranslator extends BlockInventoryTranslator { public SingleChestInventoryTranslator(int size) { - super(size); - } - - @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - Vector3i position = session.getPlayerEntity().getPosition().toInt(); - position = position.add(Vector3i.UP); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(54 << 4)); //chest - blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - session.getUpstream().sendPacket(blockPacket); - inventory.setHolderPosition(position); - - CompoundTag tag = CompoundTag.EMPTY.toBuilder() - .intTag("x", position.getX()) - .intTag("y", position.getY()) - .intTag("z", position.getZ()) - .stringTag("CustomName", inventory.getTitle()).buildRootTag(); - BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); - dataPacket.setData(tag); - dataPacket.setBlockPosition(position); - session.getUpstream().sendPacket(dataPacket); - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setWindowId((byte) inventory.getId()); - containerOpenPacket.setType((byte) ContainerType.CONTAINER.id()); - containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); - containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); - session.getUpstream().sendPacket(containerOpenPacket); - } - - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - Vector3i holderPos = inventory.getHolderPosition(); - Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); - session.getUpstream().sendPacket(blockPacket); - } - - @Override - public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + super(size, 54 << 4, ContainerType.CONTAINER); } @Override public void updateInventory(GeyserSession session, Inventory inventory) { //need to pad empty slots for 1x9 and 2x9 - final int paddedSize = 27; - ItemData[] bedrockItems = new ItemData[paddedSize]; + ItemData[] bedrockItems = new ItemData[27]; for (int i = 0; i < bedrockItems.length; i++) { if (i <= this.size) { bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); @@ -116,9 +59,4 @@ public class SingleChestInventoryTranslator extends InventoryTranslator { } TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); } - - @Override - public boolean isOutputSlot(InventoryAction action) { - return false; - } } From 2d36a8b43bf285374f03b4382431c67cf7631cfa Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 9 Nov 2019 17:20:47 -0900 Subject: [PATCH 13/32] Begin adding support for creative Still need to complete item mappings --- .../network/session/GeyserSession.java | 8 +++- .../network/translators/TranslatorsInit.java | 2 +- ...BedrockInventoryTransactionTranslator.java | 37 ++++++++++++++++++ .../CraftingTableInventoryTranslator.java | 33 ++++++++++++++++ .../org/geysermc/connector/utils/Toolbox.java | 38 ++++++++++++++++++- 5 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java 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 63b8a7e9..da98c62a 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 @@ -29,7 +29,6 @@ import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.packetlib.Client; import com.github.steveice10.packetlib.event.session.ConnectedEvent; import com.github.steveice10.packetlib.event.session.DisconnectedEvent; @@ -42,8 +41,10 @@ import com.nukkitx.math.vector.Vector2i; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.BedrockServerSession; +import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.GamePublishSetting; import com.nukkitx.protocol.bedrock.data.GameRule; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; @@ -311,5 +312,10 @@ public class GeyserSession implements Player { PlayStatusPacket playStatusPacket = new PlayStatusPacket(); playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); upstream.sendPacket(playStatusPacket); + + InventoryContentPacket creativePacket = new InventoryContentPacket(); + creativePacket.setContainerId(ContainerId.CREATIVE); + creativePacket.setContents(Toolbox.CREATIVE_ITEMS); + upstream.sendPacket(creativePacket); } } 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 3e5af466..7a07d4bc 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 @@ -172,6 +172,7 @@ public class TranslatorsInit { inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingStandInventoryTranslator()); inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator()); + inventoryTranslators.put(WindowType.CRAFTING, new CraftingTableInventoryTranslator()); //inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO InventoryTranslator furnace = new FurnaceInventoryTranslator(); @@ -182,7 +183,6 @@ public class TranslatorsInit { inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, 23 << 4, ContainerType.DISPENSER)); inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, 154 << 4, ContainerType.HOPPER)); inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(36, 205 << 4, ContainerType.CONTAINER)); - inventoryTranslators.put(WindowType.CRAFTING, new BlockInventoryTranslator(10, 58 << 4, ContainerType.WORKBENCH)); //inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, 138 << 4, ContainerType.BEACON)); //TODO } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index bf2dd7bc..d2f94164 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.data.game.window.*; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3f; @@ -69,6 +70,42 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator ITEMS; public static final ByteBuf CACHED_PALLETE; + public static final ItemData[] CREATIVE_ITEMS; public static final TIntObjectMap ITEM_ENTRIES; public static final TIntObjectMap BLOCK_ENTRIES; @@ -116,5 +120,37 @@ public class Toolbox { } BLOCK_ENTRIES = blockEntries; + + InputStream creativeItemStream = Toolbox.class.getClassLoader().getResourceAsStream("bedrock/creative_items.json"); + ObjectMapper creativeItemMapper = new ObjectMapper(); + List> creativeItemEntries = new ArrayList<>(); + + try { + creativeItemEntries = creativeItemMapper.readValue(creativeItemStream, ArrayList.class); + } catch (Exception e) { + e.printStackTrace(); + } + + List creativeItems = new ArrayList<>(); + for (Map map : creativeItemEntries) { + short damage = 0; + if (map.containsKey("damage")) { + damage = (short)(int) map.get("damage"); + } + if (map.containsKey("nbt_b64")) { + byte[] bytes = DatatypeConverter.parseBase64Binary((String) map.get("nbt_b64")); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + try { + com.nukkitx.nbt.tag.CompoundTag tag = (com.nukkitx.nbt.tag.CompoundTag) NbtUtils.createReaderLE(bais).readTag(); + creativeItems.add(ItemData.of((int) map.get("id"), damage, 1, tag)); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + creativeItems.add(ItemData.of((int) map.get("id"), damage, 1)); + } + } + + CREATIVE_ITEMS = creativeItems.toArray(new ItemData[0]); } } \ No newline at end of file From 489c39e900c9b5478325267c62c00ae5fdb45ff3 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 27 Nov 2019 18:55:58 -0900 Subject: [PATCH 14/32] Start adding support for crafting Expect bugs --- .../connector/inventory/Inventory.java | 7 +- .../connector/inventory/PlayerInventory.java | 2 +- .../network/session/GeyserSession.java | 4 +- .../network/translators/TranslatorsInit.java | 3 +- ...BedrockInventoryTransactionTranslator.java | 472 ++++++++++++------ .../inventory/AnvilInventoryTranslator.java | 4 +- .../ContainerInventoryTranslator.java | 10 +- .../CraftingTableInventoryTranslator.java | 22 + .../DoubleChestInventoryTranslator.java | 4 +- .../inventory/FurnaceInventoryTranslator.java | 4 +- .../inventory/InventoryTranslator.java | 2 +- .../inventory/PlayerInventoryTranslator.java | 14 +- .../SingleChestInventoryTranslator.java | 4 +- .../java/JavaDeclareRecipesTranslator.java | 149 ++++++ .../java/window/JavaSetSlotTranslator.java | 9 +- .../connector/utils/InventoryUtils.java | 13 +- 16 files changed, 541 insertions(+), 182 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 2147b070..24ec4a3c 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -52,7 +52,6 @@ public class Inventory { @Setter protected String title; - @Getter @Setter protected ItemStack[] items; @@ -82,4 +81,10 @@ public class Inventory { public ItemStack getItem(int slot) { return items[slot]; } + + public void setItem(int slot, ItemStack item) { + if (item != null && (item.getId() == 0 || item.getAmount() < 1)) + item = null; + items[slot] = item; + } } diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java index 4fd3bcd8..a11ce856 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -44,7 +44,7 @@ public class PlayerInventory extends Inventory { } public void setCursor(ItemStack stack) { - if (stack != null && stack.getId() == 0) + if (stack != null && (stack.getId() == 0 || stack.getAmount() < 1)) stack = null; cursor = stack; } 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 da8aaa20..1e410134 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 @@ -105,11 +105,9 @@ public class GeyserSession implements Player { @Setter private GameMode gameMode = GameMode.SURVIVAL; - @Getter @Setter - private int lastClickedSlot; + private int craftSlot = 0; - @Getter @Setter private int reopeningWindow = -1; 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 535faf5c..ba7e3a97 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 @@ -99,6 +99,7 @@ public class TranslatorsInit { Registry.registerJava(ServerRespawnPacket.class, new JavaRespawnTranslator()); Registry.registerJava(ServerSpawnPositionPacket.class, new JavaSpawnPositionTranslator()); Registry.registerJava(ServerDifficultyPacket.class, new JavaDifficultyTranslator()); + Registry.registerJava(ServerDeclareRecipesPacket.class, new JavaDeclareRecipesTranslator()); Registry.registerJava(ServerEntityAnimationPacket.class, new JavaEntityAnimationTranslator()); Registry.registerJava(ServerEntityPositionPacket.class, new JavaEntityPositionTranslator()); @@ -181,7 +182,7 @@ public class TranslatorsInit { inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, 23 << 4, ContainerType.DISPENSER)); inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, 154 << 4, ContainerType.HOPPER)); - inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(36, 205 << 4, ContainerType.CONTAINER)); + inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, 205 << 4, ContainerType.CONTAINER)); //inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, 138 << 4, ContainerType.BEACON)); //TODO } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index d2f94164..27dd19ca 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.data.game.window.*; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; @@ -49,27 +50,36 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.utils.InventoryUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; public class BedrockInventoryTransactionTranslator extends PacketTranslator { + private final ItemStack refreshItem = new ItemStack(1, 127, new CompoundTag("")); @Override public void translate(InventoryTransactionPacket packet, GeyserSession session) { switch (packet.getTransactionType()) { case NORMAL: + for (InventoryAction action : packet.getActions()) { + if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT || + action.getSource().getContainerId() == ContainerId.CRAFTING_RESULT) { + return; + } + } + Inventory inventory = session.getInventoryCache().getOpenInventory(); if (inventory == null) inventory = session.getInventory(); InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + int craftSlot = session.getCraftSlot(); + session.setCraftSlot(0); + if (session.getGameMode() == GameMode.CREATIVE && inventory.getId() == 0) { ItemStack javaItem; for (InventoryAction action : packet.getActions()) { @@ -87,17 +97,18 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator actions = packet.getActions(); if (inventory.getWindowType() == WindowType.ANVIL) { InventoryAction anvilResult = null; @@ -132,7 +142,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator(2); for (InventoryAction action : packet.getActions()) { //packet sent by client when grabbing anvil output needs useless actions stripped - if (!(action.getSource().getContainerId() == ContainerId.CONTAINER_INPUT || action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL)) { + if (!(action.getSource().getContainerId() == ContainerId.CONTAINER_INPUT || + action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL)) { actions.add(action); } } @@ -153,7 +164,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator 1 ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK); session.getDownstream().getSession().send(dropPacket); + ItemStack cursor = session.getInventory().getCursor(); + if (cursor != null) { + session.getInventory().setCursor(new ItemStack(cursor.getId(), dropAmount > 1 ? 0 : cursor.getAmount() - 1, cursor.getNbt())); + } return; } } @@ -199,43 +234,81 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator cursorAction.getFromItem().getCount()) { //fill stack - int javaSlot = session.getLastClickedSlot(); - ClientWindowActionPacket fillStackPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), - javaSlot, null, WindowAction.FILL_STACK, FillStackParam.FILL); - session.getDownstream().getSession().send(fillStackPacket); - translator.updateInventory(session, inventory); //bedrock fill stack can sometimes differ from java version, refresh and let server change slots - return; - } else { - //left/right click - int javaSlot = translator.bedrockSlotToJava(containerAction); - boolean rightClick; - if (cursorAction.getFromItem().getCount() == 0) { //picking up item - rightClick = containerAction.getToItem().getCount() != 0; - } else { //releasing item - rightClick = cursorAction.getToItem().getCount() != 0 && cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount() == 1; + //left/right click + List plan = new ArrayList<>(); + ItemStack translatedCursor = TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getFromItem()); + boolean refresh = !Objects.equals(session.getInventory().getCursor(), translatedCursor.getId() == 0 ? null : translatedCursor); //refresh slot if there is a cursor mismatch + int javaSlot = translator.bedrockSlotToJava(containerAction); + if (cursorAction.getFromItem().equals(containerAction.getToItem()) && + containerAction.getFromItem().equals(cursorAction.getToItem()) && + !canStack(cursorAction.getFromItem(), containerAction.getFromItem())) { //simple swap + Click.LEFT.onSlot(javaSlot, plan); + } else if (cursorAction.getFromItem().getCount() > cursorAction.getToItem().getCount()) { //release + if (cursorAction.getToItem().getCount() == 0) { + Click.LEFT.onSlot(javaSlot, plan); + } else { + int difference = cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); + for (int i = 0; i < difference; i++) { + Click.RIGHT.onSlot(javaSlot, plan); + } + } + } else { //pickup + if (cursorAction.getFromItem().getCount() == 0) { + if (containerAction.getToItem().getCount() == 0) { //pickup all + Click.LEFT.onSlot(javaSlot, plan); + } else { //pickup some + if (translator.isOutputSlot(javaSlot) || + containerAction.getToItem().getCount() == containerAction.getFromItem().getCount() / 2) { //right click + Click.RIGHT.onSlot(javaSlot, plan); + } else { + Click.LEFT.onSlot(javaSlot, plan); + int difference = containerAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); + for (int i = 0; i < difference; i++) { + Click.RIGHT.onSlot(javaSlot, plan); + } + } + } + } else { //pickup into non-empty cursor + if (translator.isOutputSlot(javaSlot)) { + if (containerAction.getToItem().getCount() == 0) { + Click.LEFT.onSlot(javaSlot, plan); + } else { + ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), + inventory.getTransactionId().getAndIncrement(), + javaSlot, refreshItem, WindowAction.SHIFT_CLICK_ITEM, + ShiftClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(shiftClickPacket); + translator.updateInventory(session, inventory); + return; + } + } else if ((inventory.getId() == 0 || inventory.getWindowType() == WindowType.CRAFTING) && javaSlot == 0) { //crafting output + Click.LEFT.onSlot(javaSlot, plan); + } else { + int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot)); + if (cursorSlot != -1) { + Click.LEFT.onSlot(cursorSlot, plan); + } else { + translator.updateInventory(session, inventory); + return; + } + Click.LEFT.onSlot(javaSlot, plan); + int difference = cursorAction.getToItem().getCount() - cursorAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + Click.RIGHT.onSlot(cursorSlot, plan); + } + Click.LEFT.onSlot(javaSlot, plan); + Click.LEFT.onSlot(cursorSlot, plan); + } } - ItemStack translatedCursor = TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getFromItem()); - boolean refresh = !Objects.equals(session.getInventory().getCursor(), translatedCursor.getId() == 0 ? null : translatedCursor); //refresh slot if there is a cursor mismatch - ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), javaSlot, - refresh ? new ItemStack(1, 127, new CompoundTag("")) : InventoryUtils.fixStack(TranslatorsInit.getItemTranslator().translateToJava(containerAction.getFromItem())), //send invalid item stack to refresh slot - WindowAction.CLICK_ITEM, rightClick ? ClickItemParam.RIGHT_CLICK : ClickItemParam.LEFT_CLICK); - session.getDownstream().getSession().send(clickPacket); - inventory.getItems()[javaSlot] = TranslatorsInit.getItemTranslator().translateToJava(containerAction.getToItem()); - translator.updateSlot(session, inventory, javaSlot); - session.getInventory().setCursor(TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getToItem())); - session.setLastClickedSlot(javaSlot); - return; } + executePlan(session, inventory, translator, plan, refresh); + return; } } else { - //either moving 1 item or swapping 2 slots (touchscreen or one slot shift click) + List plan = new ArrayList<>(); InventoryAction fromAction; InventoryAction toAction; - //find source slot - if (actions.get(0).getFromItem().getCount() > actions.get(0).getToItem().getCount()) { + if (actions.get(0).getFromItem().getCount() >= actions.get(0).getToItem().getCount()) { fromAction = actions.get(0); toAction = actions.get(1); } else { @@ -245,120 +318,93 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator 2) { - //shift click or fill stack? - ItemData firstItem; - if (actions.get(0).getFromItem().getId() != 0) { - firstItem = actions.get(0).getFromItem(); - } else { - firstItem = actions.get(0).getToItem(); - } - List sourceActions = new ArrayList<>(actions.size()); - List destActions = new ArrayList<>(actions.size()); - boolean sameItems = true; - for (InventoryAction action : actions) { - if (action.getFromItem().getCount() > action.getToItem().getCount()) { - if (!InventoryUtils.canCombine(action.getFromItem(), firstItem)) - sameItems = false; - sourceActions.add(action); - } else { - if (!InventoryUtils.canCombine(action.getToItem(), firstItem)) - sameItems = false; - destActions.add(action); - } - } - if (sameItems) { - if (sourceActions.size() == 1) { //shift click - InventoryAction sourceAction = sourceActions.get(0); - //in java edition, shift clicked item must move across hotbar and main inventory - if (sourceAction.getSource().getContainerId() == ContainerId.INVENTORY) { - for (InventoryAction action : actions) { - if (action != sourceAction && action.getSource().getContainerId() == ContainerId.INVENTORY) { - if ((sourceAction.getSlot() < 9 && action.getSlot() < 9) || (sourceAction.getSlot() >= 9 && action.getSlot() >= 9)) { - //shift click not compatible with java edition. refresh inventory and abort - translator.updateInventory(session, inventory); - return; - } + if ((inventory.getId() == 0 || inventory.getWindowType() == WindowType.CRAFTING) && fromSlot == 0) { + if ((craftSlot != 0 && craftSlot != -2) && (inventory.getItem(toSlot) == null || + canStack(session.getInventory().getCursor(), inventory.getItem(toSlot)))) { + boolean refresh = false; + if (fromAction.getToItem().getCount() == 0) { + refresh = true; + Click.LEFT.onSlot(toSlot, plan); + if (craftSlot != -1) { + Click.LEFT.onSlot(craftSlot, plan); } + } else { + int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + Click.RIGHT.onSlot(toSlot, plan); + } + session.setCraftSlot(craftSlot); } - } - int javaSlot = translator.bedrockSlotToJava(sourceAction); - ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), - javaSlot, InventoryUtils.fixStack(inventory.getItem(javaSlot)), WindowAction.SHIFT_CLICK_ITEM, ShiftClickItemParam.LEFT_CLICK); - session.getDownstream().getSession().send(shiftClickPacket); - return; - } else if (destActions.size() == 1) { //fill stack - InventoryAction destAction = destActions.get(0); - int javaSlot; - if (destAction != cursorAction) { //if touchscreen - javaSlot = translator.bedrockSlotToJava(destAction); - ClientWindowActionPacket leftClickPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), - javaSlot, InventoryUtils.fixStack(inventory.getItem(javaSlot)), WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK); - session.getDownstream().getSession().send(leftClickPacket); + executePlan(session, inventory, translator, plan, refresh); + return; } else { - javaSlot = session.getLastClickedSlot(); + session.setCraftSlot(-2); } - ClientWindowActionPacket fillStackPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), - javaSlot, null, WindowAction.FILL_STACK, FillStackParam.FILL); - session.getDownstream().getSession().send(fillStackPacket); - if (destAction != cursorAction) { //if touchscreen - ClientWindowActionPacket leftClickPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), - javaSlot, null, WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK); - session.getDownstream().getSession().send(leftClickPacket); - inventory.getItems()[javaSlot] = TranslatorsInit.getItemTranslator().translateToJava(destAction.getToItem()); - } - translator.updateInventory(session, inventory); - return; } + + int cursorSlot = -1; + if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot + cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot)); + if (cursorSlot != -1) { + Click.LEFT.onSlot(cursorSlot, plan); + } else { + translator.updateInventory(session, inventory); + return; + } + } + if ((fromAction.getFromItem().equals(toAction.getToItem()) && !canStack(fromAction.getFromItem(), toAction.getFromItem())) || fromAction.getToItem().getId() == 0) { //slot swap + Click.LEFT.onSlot(fromSlot, plan); + Click.LEFT.onSlot(toSlot, plan); + if (fromAction.getToItem().getId() != 0) { + Click.LEFT.onSlot(fromSlot, plan); + } + } else if (canStack(fromAction.getFromItem(), toAction.getToItem())) { //partial item move + if (translator.isOutputSlot(fromSlot)) { + ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), + inventory.getTransactionId().getAndIncrement(), + fromSlot, refreshItem, WindowAction.SHIFT_CLICK_ITEM, + ShiftClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(shiftClickPacket); + translator.updateInventory(session, inventory); + return; + } else if ((inventory.getId() == 0 || inventory.getWindowType() == WindowType.CRAFTING) && fromSlot == 0) { + session.setCraftSlot(cursorSlot); + Click.LEFT.onSlot(fromSlot, plan); + int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + Click.RIGHT.onSlot(toSlot, plan); + } + //client will send additional packets later to finish transferring crafting output + //translator will know how to handle this using the craftSlot variable + } else { + Click.LEFT.onSlot(fromSlot, plan); + int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + Click.RIGHT.onSlot(toSlot, plan); + } + Click.LEFT.onSlot(fromSlot, plan); + } + } + if (cursorSlot != -1) { + Click.LEFT.onSlot(cursorSlot, plan); + } + executePlan(session, inventory, translator, plan, false); + return; } } - - //refresh inventory, transaction was not translated translator.updateInventory(session, inventory); break; case INVENTORY_MISMATCH: InventorySlotPacket cursorPacket = new InventorySlotPacket(); cursorPacket.setContainerId(ContainerId.CURSOR); cursorPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(session.getInventory().getCursor())); - session.getUpstream().sendPacket(cursorPacket); + //session.getUpstream().sendPacket(cursorPacket); Inventory inv = session.getInventoryCache().getOpenInventory(); if (inv == null) inv = session.getInventory(); TranslatorsInit.getInventoryTranslators().get(inv.getWindowType()).updateInventory(session, inv); + break; case ITEM_USE: if (packet.getActionType() == 1) { ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); @@ -389,4 +435,134 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator slotBlacklist) { + /*try and find a slot that can temporarily store the given item + only look in the main inventory and hotbar + only slots that are empty or contain a different type of item are valid*/ + int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable slot (some servers disable it) + List itemBlacklist = new ArrayList<>(slotBlacklist.size() + 1); + itemBlacklist.add(item); + for (int slot : slotBlacklist) { + ItemStack blacklistItem = inventory.getItem(slot); + if (blacklistItem != null) + itemBlacklist.add(blacklistItem); + } + for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) { + ItemStack testItem = inventory.getItem(i); + boolean acceptable = true; + if (testItem != null) { + for (ItemStack blacklistItem : itemBlacklist) { + if (canStack(testItem, blacklistItem)) { + acceptable = false; + break; + } + } + } + if (acceptable && !slotBlacklist.contains(i)) + return i; + } + //could not find a viable temp slot + return -1; + } + + //NPE if compound tag is null + private ItemStack fixStack(ItemStack stack) { + if (stack == null || stack.getId() == 0) + return null; + return new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() == null ? new CompoundTag("") : stack.getNbt()); + } + + private boolean canStack(ItemStack item1, ItemStack item2) { + if (item1 == null || item2 == null) + return false; + return item1.getId() == item2.getId() && item1.getNbt() == item2.getNbt(); + } + + private boolean canStack(ItemData item1, ItemData item2) { + if (item1 == null || item2 == null) + return false; + return item1.equals(item2, false, true, true); + } + + private void executePlan(GeyserSession session, Inventory inventory, InventoryTranslator translator, List plan, boolean refresh) { + PlayerInventory playerInventory = session.getInventory(); + ListIterator planIter = plan.listIterator(); + while (planIter.hasNext()) { + ClickAction action = planIter.next(); + ItemStack cursorItem = playerInventory.getCursor(); + ItemStack clickedItem = inventory.getItem(action.slot); + short actionId = (short) inventory.getTransactionId().getAndIncrement(); + boolean craftingOutput = (inventory.getId() == 0 || inventory.getWindowType() == WindowType.CRAFTING) && action.slot == 0; + if (craftingOutput) + refresh = true; + ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(), + actionId, action.slot, !planIter.hasNext() && refresh ? refreshItem : fixStack(clickedItem), + WindowAction.CLICK_ITEM, action.click.actionParam); + if (craftingOutput) { //crafting output + if (cursorItem == null && clickedItem != null) { + playerInventory.setCursor(clickedItem); + } else if (canStack(cursorItem, clickedItem)) { + playerInventory.setCursor(new ItemStack(cursorItem.getId(), + cursorItem.getAmount() + clickedItem.getAmount(), cursorItem.getNbt())); + } + } else { + switch (action.click) { + case LEFT: + if (!canStack(cursorItem, clickedItem)) { + playerInventory.setCursor(clickedItem); + inventory.setItem(action.slot, cursorItem); + } else { + playerInventory.setCursor(null); + inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), + clickedItem.getAmount() + cursorItem.getAmount(), clickedItem.getNbt())); + } + break; + case RIGHT: + if (cursorItem == null && clickedItem != null) { + ItemStack halfItem = new ItemStack(clickedItem.getId(), + clickedItem.getAmount() / 2, clickedItem.getNbt()); + inventory.setItem(action.slot, halfItem); + playerInventory.setCursor(new ItemStack(clickedItem.getId(), + clickedItem.getAmount() - halfItem.getAmount(), clickedItem.getNbt())); + } else if (cursorItem != null && clickedItem == null) { + playerInventory.setCursor(new ItemStack(cursorItem.getId(), + cursorItem.getAmount() - 1, cursorItem.getNbt())); + inventory.setItem(action.slot, new ItemStack(cursorItem.getId(), + 1, cursorItem.getNbt())); + } else if (canStack(cursorItem, clickedItem)) { + playerInventory.setCursor(new ItemStack(cursorItem.getId(), + cursorItem.getAmount() - 1, cursorItem.getNbt())); + inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), + clickedItem.getAmount() + 1, clickedItem.getNbt())); + } + break; + } + } + session.getDownstream().getSession().send(clickPacket); + session.getDownstream().getSession().send(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true)); + } + } + + private enum Click { + LEFT(ClickItemParam.LEFT_CLICK), + RIGHT(ClickItemParam.RIGHT_CLICK); + + final WindowActionParam actionParam; + Click(WindowActionParam actionParam) { + this.actionParam = actionParam; + } + void onSlot(int slot, List plan) { + plan.add(new ClickAction(slot, this)); + } + } + + private static class ClickAction { + final int slot; + final Click click; + ClickAction(int slot, Click click) { + this.slot = slot; + this.click = click; + } + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java index 9c027dc2..53750130 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java @@ -54,7 +54,7 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { } @Override - public boolean isOutputSlot(InventoryAction action) { - return action.getSource().getContainerId() == ContainerId.ANVIL_RESULT; + public boolean isOutputSlot(int slot) { + return slot == 2; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java index 5c3ae3c8..22d73b9b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java @@ -43,7 +43,7 @@ public abstract class ContainerInventoryTranslator extends InventoryTranslator { public void updateInventory(GeyserSession session, Inventory inventory) { ItemData[] bedrockItems = new ItemData[this.size]; for (int i = 0; i < bedrockItems.length; i++) { - bedrockItems[javaSlotToBedrock(i)] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + bedrockItems[javaSlotToBedrock(i)] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getId()); @@ -52,7 +52,7 @@ public abstract class ContainerInventoryTranslator extends InventoryTranslator { Inventory playerInventory = session.getInventory(); for (int i = 0; i < 36; i++) { - playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; + playerInventory.setItem(i + 9, inventory.getItem(i + this.size)); } TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); } @@ -61,13 +61,13 @@ public abstract class ContainerInventoryTranslator extends InventoryTranslator { public void updateSlot(GeyserSession session, Inventory inventory, int slot) { if (slot >= this.size) { Inventory playerInventory = session.getInventory(); - playerInventory.getItems()[(slot + 9) - this.size] = inventory.getItem(slot); + playerInventory.setItem((slot + 9) - this.size, inventory.getItem(slot)); TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateSlot(session, playerInventory, (slot + 9) - this.size); } else { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); slotPacket.setInventorySlot(javaSlotToBedrock(slot)); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[slot])); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(slot))); session.getUpstream().sendPacket(slotPacket); } } @@ -97,7 +97,7 @@ public abstract class ContainerInventoryTranslator extends InventoryTranslator { } @Override - public boolean isOutputSlot(InventoryAction action) { + public boolean isOutputSlot(int slot) { return false; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java index e5f614f4..911fddc3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java @@ -1,7 +1,9 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryAction; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -30,4 +32,24 @@ public class CraftingTableInventoryTranslator extends ContainerInventoryTranslat public void closeInventory(GeyserSession session, Inventory inventory) { } + + @Override + public int bedrockSlotToJava(InventoryAction action) { + int slotnum = action.getSlot(); + if (action.getSource().getContainerId() == ContainerId.INVENTORY) { + //hotbar + if (slotnum >= 9) { + return slotnum + this.size - 9; + } else { + return slotnum + this.size + 27; + } + } else { + if (slotnum >= 32 && 42 >= slotnum) { + return slotnum - 31; + } else if (slotnum == 50) { + return 0; + } + return slotnum; + } + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index 4b90ba07..6c5057bb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -118,7 +118,7 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { ItemData[] bedrockItems = new ItemData[54]; for (int i = 0; i < bedrockItems.length; i++) { if (i <= this.size) { - bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } else { bedrockItems[i] = ItemData.AIR; } @@ -130,7 +130,7 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { Inventory playerInventory = session.getInventory(); for (int i = 0; i < 36; i++) { - playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; + playerInventory.setItem(i + 9, inventory.getItem(i + this.size)); } TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index c5296d37..9c274c87 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -59,7 +59,7 @@ public class FurnaceInventoryTranslator extends BlockInventoryTranslator { } @Override - public boolean isOutputSlot(InventoryAction action) { - return action.getSlot() == 2; + public boolean isOutputSlot(int slot) { + return slot == 2; } } 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 index 7181a345..edc7f495 100644 --- 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 @@ -44,5 +44,5 @@ public abstract class InventoryTranslator { public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot); public abstract int bedrockSlotToJava(InventoryAction action); public abstract int javaSlotToBedrock(int slot); - public abstract boolean isOutputSlot(InventoryAction action); + public abstract boolean isOutputSlot(int slot); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index cfd92699..2608fd6c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -45,12 +45,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator { ItemData[] contents = new ItemData[36]; // Inventory for (int i = 9; i < 36; i++) { - contents[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + contents[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } // Hotbar for (int i = 36; i < 45; i++) { - contents[i - 36] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + contents[i - 36] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } inventoryContentPacket.setContents(contents); @@ -61,7 +61,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { armorContentPacket.setContainerId(ContainerId.ARMOR); contents = new ItemData[4]; for (int i = 5; i < 9; i++) { - contents[i - 5] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + contents[i - 5] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } armorContentPacket.setContents(contents); session.getUpstream().sendPacket(armorContentPacket); @@ -124,6 +124,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator { case ContainerId.CRAFTING_ADD_INGREDIENT: case ContainerId.CRAFTING_REMOVE_INGREDIENT: return slotnum + 1; + case ContainerId.CURSOR: + if (slotnum >= 28 && 31 >= slotnum) { + return slotnum - 27; + } else if (slotnum == 50) { + return 0; + } } return slotnum; } @@ -134,7 +140,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public boolean isOutputSlot(InventoryAction action) { + public boolean isOutputSlot(int slot) { return false; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index 43ceb283..3b2c70d9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -43,7 +43,7 @@ public class SingleChestInventoryTranslator extends BlockInventoryTranslator { ItemData[] bedrockItems = new ItemData[27]; for (int i = 0; i < bedrockItems.length; i++) { if (i <= this.size) { - bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItems()[i]); + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } else { bedrockItems[i] = ItemData.AIR; } @@ -55,7 +55,7 @@ public class SingleChestInventoryTranslator extends BlockInventoryTranslator { Inventory playerInventory = session.getInventory(); for (int i = 0; i < 36; i++) { - playerInventory.getItems()[i + 9] = inventory.getItems()[i + this.size]; + playerInventory.setItem(i + 9, inventory.getItem(i + this.size)); } TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java new file mode 100644 index 00000000..afa4836c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -0,0 +1,149 @@ +/* + * 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.recipe.Ingredient; +import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerDeclareRecipesPacket; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.CraftingData; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.TranslatorsInit; + +import java.util.*; +import java.util.stream.Collectors; + +public class JavaDeclareRecipesTranslator extends PacketTranslator { + + @Override + public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) { + CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); + craftingDataPacket.setCleanRecipes(true); + for (Recipe recipe : packet.getRecipes()) { + switch (recipe.getType()) { + case CRAFTING_SHAPELESS: { + ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData(); + ItemData output = TranslatorsInit.getItemTranslator().translateToBedrock(shapelessRecipeData.getResult()); + List inputList = combinations(shapelessRecipeData.getIngredients()); + for (ItemData[] inputs : inputList) { + UUID uuid = UUID.randomUUID(); + craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(), + inputs, new ItemData[]{output}, uuid, "crafting_table", 0)); + } + break; + } + case CRAFTING_SHAPED: { + ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData(); + ItemData output = TranslatorsInit.getItemTranslator().translateToBedrock(shapedRecipeData.getResult()); + List inputList = combinations(shapedRecipeData.getIngredients()); + for (ItemData[] inputs : inputList) { + UUID uuid = UUID.randomUUID(); + craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(), + shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), inputs, + new ItemData[]{output}, uuid, "crafting_table", 0)); + } + break; + } + } + } + session.getUpstream().sendPacket(craftingDataPacket); + } + + private List combinations(Ingredient[] ingredients) { + ItemData[][] squashed = new ItemData[ingredients.length][]; + for (int i = 0; i < ingredients.length; i++) { + if (ingredients[i].getOptions().length == 0) { + squashed[i] = new ItemData[]{ItemData.AIR}; + continue; + } + Ingredient ingredient = ingredients[i]; + Map> groupedByIds = Arrays.stream(ingredient.getOptions()) + .map(item -> TranslatorsInit.getItemTranslator().translateToBedrock(item)) + .collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag()))); + squashed[i] = new ItemData[groupedByIds.size()]; + int index = 0; + for (Map.Entry> entry : groupedByIds.entrySet()) { + if (entry.getValue().size() > 1) { + GroupedItem groupedItem = entry.getKey(); + squashed[i][index++] = ItemData.of(groupedItem.id, (short) -1, groupedItem.count, groupedItem.tag); + } else { + ItemData item = entry.getValue().get(0); + squashed[i][index++] = item; + } + } + } + int[] sizeArray = new int[squashed.length]; + int[] counterArray = new int[squashed.length]; + int totalCombinationCount = 1; + for(int i = 0; i < squashed.length; i++) { + sizeArray[i] = squashed[i].length; + totalCombinationCount *= squashed[i].length; + } + if (totalCombinationCount > 10000) { + ItemData[] translatedItems = new ItemData[ingredients.length]; + for (int i = 0; i < ingredients.length; i++) { + if (ingredients[i].getOptions().length > 0) { + translatedItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(ingredients[i].getOptions()[0]); + } else { + translatedItems[i] = ItemData.AIR; + } + } + return Collections.singletonList(translatedItems); + } + List combinationList = new ArrayList<>(totalCombinationCount); + for (int countdown = totalCombinationCount; countdown > 0; --countdown) { + ItemData[] translatedItems = new ItemData[squashed.length]; + for(int i = 0; i < squashed.length; ++i) { + if (squashed[i].length > 0) + translatedItems[i] = squashed[i][counterArray[i]]; + } + combinationList.add(translatedItems); + for(int incIndex = squashed.length - 1; incIndex >= 0; --incIndex) { + if(counterArray[incIndex] + 1 < sizeArray[incIndex]) { + ++counterArray[incIndex]; + break; + } + counterArray[incIndex] = 0; + } + } + return combinationList; + } + + @EqualsAndHashCode + @AllArgsConstructor + private static class GroupedItem { + int id; + int count; + CompoundTag tag; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 562eb193..d658535f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -47,9 +47,12 @@ public class JavaSetSlotTranslator extends PacketTranslator if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor if (Objects.equals(session.getInventory().getCursor(), packet.getItem())) return; + if (session.getCraftSlot() != 0) + return; //bedrock client is bugged when changing the cursor. reopen inventory after changing it - if (packet.getItem() == null && session.getInventory().getCursor() != null) { + //TODO: fix this. too buggy rn + /*if (packet.getItem() == null && session.getInventory().getCursor() != null) { InventorySlotPacket cursorPacket = new InventorySlotPacket(); cursorPacket.setContainerId(ContainerId.CURSOR); cursorPacket.setSlot(ItemData.AIR); @@ -64,7 +67,7 @@ public class JavaSetSlotTranslator extends PacketTranslator ContainerClosePacket closePacket = new ContainerClosePacket(); closePacket.setWindowId((byte) inventory.getId()); Geyser.getGeneralThreadPool().schedule(() -> session.getUpstream().sendPacket(closePacket), 150, TimeUnit.MILLISECONDS); - } + }*/ session.getInventory().setCursor(packet.getItem()); return; @@ -76,7 +79,7 @@ public class JavaSetSlotTranslator extends PacketTranslator InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); if (translator != null) { - inventory.getItems()[packet.getSlot()] = packet.getItem(); + inventory.setItem(packet.getSlot(), packet.getItem()); translator.updateSlot(session, inventory, packet.getSlot()); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index 86c38fe9..77c69eed 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -44,14 +44,13 @@ public class InventoryUtils { session.getInventoryCache().uncacheInventory(windowId); session.getInventoryCache().setOpenInventory(null); } + } else { + Inventory inventory = session.getInventory(); + InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); + translator.updateInventory(session, inventory); } - } - - //currently, ItemStack.equals() does not check the item id - public static boolean canCombine(ItemData stack1, ItemData stack2) { - if (stack1 == null || stack2 == null) - return false; - return stack1.getId() == stack2.getId() && stack1.equals(stack2, false, true, true); + session.setCraftSlot(0); + session.getInventory().setCursor(null); } //NPE if nbt tag is null From 8a589129f0912d456b97f897d0b3e6a4d71460cd Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 29 Nov 2019 02:16:52 -0900 Subject: [PATCH 15/32] Update crafting recipe combinations calculation --- .../java/JavaDeclareRecipesTranslator.java | 78 +++++++++++-------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index afa4836c..cadafb01 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -39,6 +39,8 @@ import lombok.EqualsAndHashCode; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.TranslatorsInit; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.utils.Toolbox; import java.util.*; import java.util.stream.Collectors; @@ -54,8 +56,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator inputList = combinations(shapelessRecipeData.getIngredients()); - for (ItemData[] inputs : inputList) { + ItemData[][] inputCombinations = combinations(shapelessRecipeData.getIngredients()); + for (ItemData[] inputs : inputCombinations) { UUID uuid = UUID.randomUUID(); craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(), inputs, new ItemData[]{output}, uuid, "crafting_table", 0)); @@ -65,8 +67,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator inputList = combinations(shapedRecipeData.getIngredients()); - for (ItemData[] inputs : inputList) { + ItemData[][] inputCombinations = combinations(shapedRecipeData.getIngredients()); + for (ItemData[] inputs : inputCombinations) { UUID uuid = UUID.randomUUID(); craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(), shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), inputs, @@ -79,37 +81,45 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator combinations(Ingredient[] ingredients) { - ItemData[][] squashed = new ItemData[ingredients.length][]; + private ItemData[][] combinations(Ingredient[] ingredients) { + Map, Set> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length == 0) { - squashed[i] = new ItemData[]{ItemData.AIR}; + squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new HashSet<>()).add(i); continue; } Ingredient ingredient = ingredients[i]; Map> groupedByIds = Arrays.stream(ingredient.getOptions()) .map(item -> TranslatorsInit.getItemTranslator().translateToBedrock(item)) .collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag()))); - squashed[i] = new ItemData[groupedByIds.size()]; - int index = 0; + Set optionSet = new HashSet<>(groupedByIds.size()); for (Map.Entry> entry : groupedByIds.entrySet()) { if (entry.getValue().size() > 1) { GroupedItem groupedItem = entry.getKey(); - squashed[i][index++] = ItemData.of(groupedItem.id, (short) -1, groupedItem.count, groupedItem.tag); + int idCount = 0; + //not optimal + for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.valueCollection()) { + if (itemEntry.getBedrockId() == groupedItem.id) { + idCount++; + } + } + if (entry.getValue().size() < idCount) { + optionSet.addAll(entry.getValue()); + } else { + optionSet.add(ItemData.of(groupedItem.id, (short) -1, groupedItem.count, groupedItem.tag)); + } } else { ItemData item = entry.getValue().get(0); - squashed[i][index++] = item; + optionSet.add(item); } } + squashedOptions.computeIfAbsent(optionSet, k -> new HashSet<>()).add(i); } - int[] sizeArray = new int[squashed.length]; - int[] counterArray = new int[squashed.length]; - int totalCombinationCount = 1; - for(int i = 0; i < squashed.length; i++) { - sizeArray[i] = squashed[i].length; - totalCombinationCount *= squashed[i].length; + int totalCombinations = 1; + for (Set optionSet : squashedOptions.keySet()) { + totalCombinations *= optionSet.size(); } - if (totalCombinationCount > 10000) { + if (totalCombinations > 500) { ItemData[] translatedItems = new ItemData[ingredients.length]; for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length > 0) { @@ -118,25 +128,27 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator combinationList = new ArrayList<>(totalCombinationCount); - for (int countdown = totalCombinationCount; countdown > 0; --countdown) { - ItemData[] translatedItems = new ItemData[squashed.length]; - for(int i = 0; i < squashed.length; ++i) { - if (squashed[i].length > 0) - translatedItems[i] = squashed[i][counterArray[i]]; - } - combinationList.add(translatedItems); - for(int incIndex = squashed.length - 1; incIndex >= 0; --incIndex) { - if(counterArray[incIndex] + 1 < sizeArray[incIndex]) { - ++counterArray[incIndex]; - break; + List> sortedSets = new ArrayList<>(squashedOptions.keySet()); + sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder())); + ItemData[][] combinations = new ItemData[totalCombinations][ingredients.length]; + int x = 1; + for (Set set : sortedSets) { + Set slotSet = squashedOptions.get(set); + int i = 0; + for (ItemData item : set) { + for (int j = 0; j < totalCombinations / set.size(); j++) { + final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x); + for (int slot : slotSet) { + combinations[comboIndex][slot] = item; + } } - counterArray[incIndex] = 0; + i++; } + x *= set.size(); } - return combinationList; + return combinations; } @EqualsAndHashCode From 24e5d34ce92a740b000bd4f7f91a374dc928c375 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 29 Nov 2019 15:49:29 -0900 Subject: [PATCH 16/32] Cleanup --- .../network/session/GeyserSession.java | 3 --- .../BedrockContainerCloseTranslator.java | 11 -------- .../CraftingTableInventoryTranslator.java | 26 +++++++++++++++++- .../inventory/PlayerInventoryTranslator.java | 2 -- .../translators/item/ItemTranslator.java | 2 +- .../java/window/JavaSetSlotTranslator.java | 27 +------------------ .../window/JavaWindowPropertyTranslator.java | 26 +++++++++++++++++- .../connector/utils/InventoryUtils.java | 13 --------- 8 files changed, 52 insertions(+), 58 deletions(-) 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 1e410134..71108d89 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 @@ -108,9 +108,6 @@ public class GeyserSession implements Player { @Setter private int craftSlot = 0; - @Setter - private int reopeningWindow = -1; - public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { this.connector = connector; this.upstream = new UpstreamSession(bedrockServerSession); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index 71cc9f0d..01da6d5f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -47,17 +47,6 @@ public class BedrockContainerCloseTranslator extends PacketTranslator { @@ -49,26 +43,7 @@ public class JavaSetSlotTranslator extends PacketTranslator return; if (session.getCraftSlot() != 0) return; - - //bedrock client is bugged when changing the cursor. reopen inventory after changing it - //TODO: fix this. too buggy rn - /*if (packet.getItem() == null && session.getInventory().getCursor() != null) { - InventorySlotPacket cursorPacket = new InventorySlotPacket(); - cursorPacket.setContainerId(ContainerId.CURSOR); - cursorPacket.setSlot(ItemData.AIR); - session.getUpstream().sendPacket(cursorPacket); - - Inventory inventory = session.getInventoryCache().getOpenInventory(); - if (inventory != null) { - session.setReopeningWindow(inventory.getId()); - } else { - inventory = session.getInventory(); - } - ContainerClosePacket closePacket = new ContainerClosePacket(); - closePacket.setWindowId((byte) inventory.getId()); - Geyser.getGeneralThreadPool().schedule(() -> session.getUpstream().sendPacket(closePacket), 150, TimeUnit.MILLISECONDS); - }*/ - + //bedrock client is bugged when changing the cursor. do not send slot update packet session.getInventory().setCursor(packet.getItem()); return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java index 2127a94b..c8e04d37 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java @@ -1,9 +1,33 @@ +/* + * 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.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowPropertyPacket; 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.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index 77c69eed..c5823a40 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -1,10 +1,5 @@ package org.geysermc.connector.utils; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.api.Geyser; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -12,7 +7,6 @@ import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import java.util.Objects; import java.util.concurrent.TimeUnit; public class InventoryUtils { @@ -52,11 +46,4 @@ public class InventoryUtils { session.setCraftSlot(0); session.getInventory().setCursor(null); } - - //NPE if nbt tag is null - public static ItemStack fixStack(ItemStack stack) { - if (stack == null || stack.getId() == 0) - return null; - return new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() == null ? new CompoundTag("") : stack.getNbt()); - } } From 8c93ca65f5fdeea32f046469923e03e5f3fdd1f2 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 30 Nov 2019 15:24:01 -0900 Subject: [PATCH 17/32] Update JavaDeclareRecipesTranslator.java --- .../java/JavaDeclareRecipesTranslator.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index cadafb01..5cc98c3f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -34,6 +34,8 @@ import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.CraftingData; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import org.geysermc.connector.network.session.GeyserSession; @@ -82,10 +84,10 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator, Set> squashedOptions = new HashMap<>(); + Map, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length == 0) { - squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new HashSet<>()).add(i); + squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new IntOpenHashSet()).add(i); continue; } Ingredient ingredient = ingredients[i]; @@ -98,7 +100,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator new HashSet<>()).add(i); + squashedOptions.computeIfAbsent(optionSet, k -> new IntOpenHashSet()).add(i); } int totalCombinations = 1; for (Set optionSet : squashedOptions.keySet()) { @@ -135,7 +137,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator set : sortedSets) { - Set slotSet = squashedOptions.get(set); + IntSet slotSet = squashedOptions.get(set); int i = 0; for (ItemData item : set) { for (int j = 0; j < totalCombinations / set.size(); j++) { From ba0b898da99da96dd5d086e0502883efbc5d64a0 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 30 Nov 2019 17:22:14 -0900 Subject: [PATCH 18/32] Fix anvils --- ...BedrockInventoryTransactionTranslator.java | 21 +++++++++--------- .../inventory/AnvilInventoryTranslator.java | 22 +++++++++++++++---- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 27dd19ca..06343110 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -131,22 +131,18 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator(2); - for (InventoryAction action : packet.getActions()) { //packet sent by client when grabbing anvil output needs useless actions stripped - if (!(action.getSource().getContainerId() == ContainerId.CONTAINER_INPUT || - action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL)) { - actions.add(action); - } - } } else if (anvilInput != null) { itemName = anvilInput.getToItem(); } @@ -161,6 +157,11 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Sun, 1 Dec 2019 00:26:11 -0900 Subject: [PATCH 19/32] Cleanup and fixes --- ...BedrockInventoryTransactionTranslator.java | 38 +++++++++++------ .../inventory/AnvilInventoryTranslator.java | 42 ++++++------------- .../inventory/BlockInventoryTranslator.java | 4 +- .../BrewingStandInventoryTranslator.java | 34 ++++++--------- .../ContainerInventoryTranslator.java | 6 +-- .../CraftingTableInventoryTranslator.java | 20 ++++----- .../inventory/FurnaceInventoryTranslator.java | 7 ++-- .../inventory/InventoryTranslator.java | 2 +- .../inventory/PlayerInventoryTranslator.java | 10 ++--- .../translators/inventory/SlotType.java | 32 ++++++++++++++ 10 files changed, 108 insertions(+), 87 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 06343110..1fd0500c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -55,6 +55,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.inventory.SlotType; import java.util.*; @@ -237,8 +238,19 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator plan = new ArrayList<>(); - ItemStack translatedCursor = TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getFromItem()); - boolean refresh = !Objects.equals(session.getInventory().getCursor(), translatedCursor.getId() == 0 ? null : translatedCursor); //refresh slot if there is a cursor mismatch + ItemStack translatedCursor = cursorAction.getFromItem().isValid() ? + TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getFromItem()) : null; + ItemStack currentCursor = session.getInventory().getCursor(); + boolean refresh = false; + if (currentCursor != null) { + if (translatedCursor != null) { + refresh = !(currentCursor.getId() == translatedCursor.getId() && + currentCursor.getAmount() == translatedCursor.getAmount()); + } else { + refresh = true; + } + } + int javaSlot = translator.bedrockSlotToJava(containerAction); if (cursorAction.getFromItem().equals(containerAction.getToItem()) && containerAction.getFromItem().equals(cursorAction.getToItem()) && @@ -258,7 +270,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator= 9) { - return slotnum + this.size - 9; - } else { - return slotnum + this.size + 27; - } - } else { - if (action.getSource().getContainerId() == ContainerId.CURSOR) { - switch (slotnum) { - case 1: - return 0; - case 2: - return 1; - case 50: - return 2; - } + if (action.getSource().getContainerId() == ContainerId.CURSOR) { + switch (action.getSlot()) { + case 1: + return 0; + case 2: + return 1; + case 50: + return 2; } } - return slotnum; + return super.bedrockSlotToJava(action); } @Override - public boolean isOutputSlot(int slot) { - return slot == 2; + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 2) + return SlotType.OUTPUT; + return SlotType.NORMAL; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java index 065d63dc..0112dc9e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java @@ -38,8 +38,8 @@ import org.geysermc.connector.network.translators.block.BlockEntry; import org.geysermc.connector.world.GlobalBlockPalette; public class BlockInventoryTranslator extends ContainerInventoryTranslator { - protected final int blockId; - protected final ContainerType containerType; + final int blockId; + private final ContainerType containerType; public BlockInventoryTranslator(int size, int blockId, ContainerType containerType) { super(size); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java index 92eb4bc8..e6089cb8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.data.InventoryAction; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; @@ -58,27 +57,18 @@ public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { @Override public int bedrockSlotToJava(InventoryAction action) { - int slotnum = action.getSlot(); - if (action.getSource().getContainerId() == ContainerId.INVENTORY) { - //hotbar - if (slotnum >= 9) { - return slotnum + this.size - 9; - } else { - return slotnum + this.size + 27; - } - } else { - switch (slotnum) { - case 0: - return 3; - case 1: - return 0; - case 2: - return 1; - case 3: - return 2; - default: - return slotnum; - } + int slotnum = super.bedrockSlotToJava(action); + switch (slotnum) { + case 0: + return 3; + case 1: + return 0; + case 2: + return 1; + case 3: + return 2; + default: + return slotnum; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java index 22d73b9b..8f66675b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java @@ -35,7 +35,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.TranslatorsInit; public abstract class ContainerInventoryTranslator extends InventoryTranslator { - public ContainerInventoryTranslator(int size) { + ContainerInventoryTranslator(int size) { super(size); } @@ -97,7 +97,7 @@ public abstract class ContainerInventoryTranslator extends InventoryTranslator { } @Override - public boolean isOutputSlot(int slot) { - return false; + public SlotType getSlotType(int javaSlot) { + return SlotType.NORMAL; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java index 82b4f922..28ad0cb2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java @@ -59,21 +59,21 @@ public class CraftingTableInventoryTranslator extends ContainerInventoryTranslat @Override public int bedrockSlotToJava(InventoryAction action) { - int slotnum = action.getSlot(); - if (action.getSource().getContainerId() == ContainerId.INVENTORY) { - //hotbar - if (slotnum >= 9) { - return slotnum + this.size - 9; - } else { - return slotnum + this.size + 27; - } - } else { + if (action.getSource().getContainerId() == ContainerId.CURSOR) { + int slotnum = action.getSlot(); if (slotnum >= 32 && 42 >= slotnum) { return slotnum - 31; } else if (slotnum == 50) { return 0; } - return slotnum; } + return super.bedrockSlotToJava(action); + } + + @Override + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 0) + return SlotType.OUTPUT; + return SlotType.NORMAL; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index 9c274c87..95d78562 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -59,7 +58,9 @@ public class FurnaceInventoryTranslator extends BlockInventoryTranslator { } @Override - public boolean isOutputSlot(int slot) { - return slot == 2; + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 2) + return SlotType.FURNACE_OUTPUT; + return SlotType.NORMAL; } } 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 index edc7f495..0aa4df0a 100644 --- 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 @@ -44,5 +44,5 @@ public abstract class InventoryTranslator { public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot); public abstract int bedrockSlotToJava(InventoryAction action); public abstract int javaSlotToBedrock(int slot); - public abstract boolean isOutputSlot(int slot); + public abstract SlotType getSlotType(int javaSlot); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index 773c4dca..6ba25bc5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -119,15 +119,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { break; case ContainerId.OFFHAND: return 45; - case ContainerId.CRAFTING_ADD_INGREDIENT: - case ContainerId.CRAFTING_REMOVE_INGREDIENT: - return slotnum + 1; case ContainerId.CURSOR: if (slotnum >= 28 && 31 >= slotnum) { return slotnum - 27; } else if (slotnum == 50) { return 0; } + break; } return slotnum; } @@ -138,8 +136,10 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public boolean isOutputSlot(int slot) { - return false; + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 0) + return SlotType.OUTPUT; + return SlotType.NORMAL; } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java new file mode 100644 index 00000000..b5657af4 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java @@ -0,0 +1,32 @@ +/* + * 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; + +public enum SlotType { + NORMAL, + OUTPUT, + FURNACE_OUTPUT +} From 4eeadc6d21233baaffabd5194566b4522f181339 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 2 Dec 2019 00:48:27 -0900 Subject: [PATCH 20/32] Start working on translating enchantments and potions Translation is only (java -> bedrock) for now. Only regular potions will translate correctly. More work will be needed to translate custom potions. --- .../network/translators/item/Enchantment.java | 85 +++++++++++++++ .../translators/item/ItemTranslator.java | 40 ++++++- .../network/translators/item/Potion.java | 102 ++++++++++++++++++ 3 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java new file mode 100644 index 00000000..79b8514a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java @@ -0,0 +1,85 @@ +/* + * 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.Getter; + +import java.util.Locale; + +@Getter +enum Enchantment { + PROTECTION, + FIRE_PROTECTION, + FEATHER_FALLING, + BLAST_PROTECTION, + PROJECTILE_PROTECTION, + THORNS, + RESPIRATION, + DEPTH_STRIDER, + AQUA_AFFINITY, + SHARPNESS, + SMITE, + BANE_OF_ARTHROPODS, + KNOCKBACK, + FIRE_ASPECT, + LOOTING, + EFFICIENCY, + SILK_TOUCH, + UNBREAKING, + FORTUNE, + POWER, + PUNCH, + FLAME, + INFINITY, + LUCK_OF_THE_SEA, + LURE, + FROST_WALKER, + MENDING, + BINDING_CURSE, + VANISHING_CURSE, + IMPALING, + RIPTIDE, + LOYALTY, + CHANNELING, + MULTISHOT, + PIERCING, + QUICK_CHARGE; + + private final String javaIdentifier; + + Enchantment() { + this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH); + } + + public static Enchantment getByJavaIdentifier(String javaIdentifier) { + for (Enchantment enchantment : Enchantment.values()) { + if (enchantment.javaIdentifier.equals(javaIdentifier)) { + return enchantment; + } + } + return null; + } +} 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 index 472287b7..5478a278 100644 --- 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 @@ -41,6 +41,7 @@ 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 org.geysermc.api.Geyser; import org.geysermc.connector.console.GeyserLogger; import org.geysermc.connector.utils.MessageUtils; import org.geysermc.connector.utils.Toolbox; @@ -70,6 +71,15 @@ public class ItemTranslator { ItemEntry bedrockItem = getItem(stack); if (stack.getNbt() == null) { return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount()); + } else if (bedrockItem.getJavaIdentifier().endsWith("potion")) { + Tag potionTag = stack.getNbt().get("Potion"); + if (potionTag instanceof StringTag) { + Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); + if (potion != null) { + return ItemData.of(bedrockItem.getBedrockId(), potion.getBedrockId(), stack.getAmount(), translateToBedrockNBT(stack.getNbt())); + } + Geyser.getLogger().debug("Unknown java potion: " + potionTag.getValue()); + } } return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount(), translateToBedrockNBT(stack.getNbt())); } @@ -80,7 +90,7 @@ public class ItemTranslator { public ItemEntry getItem(ItemData data) { for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) { - if (itemEntry.getBedrockId() == data.getId() && itemEntry.getBedrockData() == data.getDamage()) { + if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) { return itemEntry; } } @@ -251,7 +261,33 @@ public class ItemTranslator { if (tag instanceof ListTag) { ListTag listTag = (ListTag) tag; - if (listTag.getName().equalsIgnoreCase("Lore")) { + if (listTag.getName().equalsIgnoreCase("Enchantments") || listTag.getName().equalsIgnoreCase("StoredEnchantments")) { + List tags = new ArrayList<>(); + for (Object value : listTag.getValue()) { + if (!(value instanceof CompoundTag)) + continue; + + Tag javaEnchLvl = ((CompoundTag) value).get("lvl"); + if (!(javaEnchLvl instanceof ShortTag)) + continue; + + Tag javaEnchId = ((CompoundTag) value).get("id"); + if (!(javaEnchId instanceof StringTag)) + continue; + + Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); + if (enchantment == null) { + Geyser.getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue()); + continue; + } + + com.nukkitx.nbt.CompoundTagBuilder builder = com.nukkitx.nbt.tag.CompoundTag.EMPTY.toBuilder(); + builder.shortTag("lvl", ((ShortTag) javaEnchLvl).getValue()); + builder.shortTag("id", (short) enchantment.ordinal()); + tags.add(builder.buildRootTag()); + } + return new com.nukkitx.nbt.tag.ListTag<>("ench", com.nukkitx.nbt.tag.CompoundTag.class, tags); + } else if (listTag.getName().equalsIgnoreCase("Lore")) { List tags = new ArrayList<>(); for (Object value : listTag.getValue()) { if (!(value instanceof Tag)) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java new file mode 100644 index 00000000..ca5cd5c0 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java @@ -0,0 +1,102 @@ +/* + * 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.Getter; + +import java.util.Locale; + +@Getter +enum Potion { + WATER(0), + MUNDANE(1), + THICK(3), + AWKWARD(4), + NIGHT_VISION(5), + LONG_NIGHT_VISION(6), + INVISIBILITY(7), + LONG_INVISIBILITY(8), + LEAPING(9), + STRONG_LEAPING(11), + LONG_LEAPING(10), + FIRE_RESISTANCE(12), + LONG_FIRE_RESISTANCE(13), + SWIFTNESS(14), + STRONG_SWIFTNESS(16), + LONG_SWIFTNESS(15), + SLOWNESS(17), + STRONG_SLOWNESS(18), //does not exist + LONG_SLOWNESS(18), + WATER_BREATHING(19), + LONG_WATER_BREATHING(20), + HEALING(21), + STRONG_HEALING(22), + HARMING(23), + STRONG_HARMING(24), + POISON(25), + STRONG_POISON(27), + LONG_POISON(26), + REGENERATION(28), + STRONG_REGENERATION(30), + LONG_REGENERATION(29), + STRENGTH(31), + STRONG_STRENGTH(33), + LONG_STRENGTH(32), + WEAKNESS(34), + LONG_WEAKNESS(35), + LUCK(2), //does not exist + TURTLE_MASTER(37), + STRONG_TURTLE_MASTER(39), + LONG_TURTLE_MASTER(38), + SLOW_FALLING(40), + LONG_SLOW_FALLING(41); + + private final String javaIdentifier; + private final short bedrockId; + + Potion(int bedrockId) { + this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH); + this.bedrockId = (short) bedrockId; + } + + public static Potion getByJavaIdentifier(String javaIdentifier) { + for (Potion potion : Potion.values()) { + if (potion.javaIdentifier.equals(javaIdentifier)) { + return potion; + } + } + return null; + } + + public static Potion getByBedrockId(short bedrockId) { + for (Potion potion : Potion.values()) { + if (potion.bedrockId == bedrockId) { + return potion; + } + } + return null; + } +} From 7a588408215e63171011a3c07b15974757d5694e Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 2 Dec 2019 14:22:13 -0900 Subject: [PATCH 21/32] Fix NoClassDefFoundError in Java 9+ --- .../src/main/java/org/geysermc/connector/utils/Toolbox.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 806f5e17..3b0d02a2 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -16,7 +16,6 @@ import org.geysermc.connector.network.translators.block.BlockEntry; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.world.GlobalBlockPalette; -import javax.xml.bind.DatatypeConverter; import java.io.*; import java.util.*; @@ -129,7 +128,7 @@ public class Toolbox { damage = (short)(int) map.get("damage"); } if (map.containsKey("nbt_b64")) { - byte[] bytes = DatatypeConverter.parseBase64Binary((String) map.get("nbt_b64")); + byte[] bytes = Base64.getDecoder().decode((String) map.get("nbt_b64")); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); try { com.nukkitx.nbt.tag.CompoundTag tag = (com.nukkitx.nbt.tag.CompoundTag) NbtUtils.createReaderLE(bais).readTag(); From 1b37a192808d501f429970fc824dafb779e291ec Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 2 Dec 2019 15:53:46 -0900 Subject: [PATCH 22/32] Translate bedrock enchantments to java --- .../network/translators/item/Enchantment.java | 7 ++++ .../translators/item/ItemTranslator.java | 38 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java index 79b8514a..596ef215 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java @@ -82,4 +82,11 @@ enum Enchantment { } return null; } + + public static Enchantment getByBedrockId(int bedrockId) { + if (bedrockId >= 0 && bedrockId < Enchantment.values().length) { + return Enchantment.values()[bedrockId]; + } + return null; + } } 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 index 5478a278..438b2061 100644 --- 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 @@ -58,6 +58,17 @@ public class ItemTranslator { if (data.getTag() == null) { return new ItemStack(javaItem.getJavaId(), data.getCount()); + } else if (javaItem.getJavaIdentifier().equals("minecraft:enchanted_book")) { + CompoundTag javaTag = translateToJavaNBT(data.getTag()); + Map javaValue = javaTag.getValue(); + Tag enchTag = javaValue.get("Enchantments"); + if (enchTag instanceof ListTag) { + enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue()); + javaValue.remove("Enchantments"); + javaValue.put("StoredEnchantments", enchTag); + javaTag.setValue(javaValue); + } + return new ItemStack(javaItem.getJavaId(), data.getCount(), javaTag); } return new ItemStack(javaItem.getJavaId(), data.getCount(), translateToJavaNBT(data.getTag())); } @@ -109,7 +120,7 @@ public class ItemTranslator { if (translatedTag == null) continue; - javaValue.put(str, translatedTag); + javaValue.put(translatedTag.getName(), translatedTag); } } @@ -172,6 +183,29 @@ public class ItemTranslator { com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag; List tags = new ArrayList<>(); + + if (tag.getName().equals("ench")) { + for (Object value : listTag.getValue()) { + if (!(value instanceof com.nukkitx.nbt.tag.CompoundTag)) + continue; + + com.nukkitx.nbt.tag.CompoundTag tagValue = (com.nukkitx.nbt.tag.CompoundTag) value; + int bedrockId = tagValue.getAsShort("id", (short) -1); + Enchantment enchantment = Enchantment.getByBedrockId(bedrockId); + if (enchantment != null) { + CompoundTag javaTag = new CompoundTag(""); + Map javaValue = javaTag.getValue(); + javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); + javaValue.put("lvl", new IntTag("lvl", tagValue.getAsShort("lvl"))); + javaTag.setValue(javaValue); + tags.add(javaTag); + } else { + Geyser.getLogger().debug("Unknown bedrock enchantment: " + bedrockId); + } + } + return new ListTag("Enchantments", tags); + } + for (Object value : listTag.getValue()) { if (!(value instanceof com.nukkitx.nbt.tag.Tag)) continue; @@ -200,7 +234,7 @@ public class ItemTranslator { if (translatedTag == null) continue; - javaValue.put(str, translatedTag); + javaValue.put(translatedTag.getName(), translatedTag); } } From 0720e18015f295cd4c652f992cee4c8f380767b2 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 2 Dec 2019 16:07:44 -0900 Subject: [PATCH 23/32] Default bedrock enchantment level to 1 --- .../connector/network/translators/item/ItemTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 438b2061..6b78f0d6 100644 --- 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 @@ -196,7 +196,7 @@ public class ItemTranslator { CompoundTag javaTag = new CompoundTag(""); Map javaValue = javaTag.getValue(); javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); - javaValue.put("lvl", new IntTag("lvl", tagValue.getAsShort("lvl"))); + javaValue.put("lvl", new IntTag("lvl", tagValue.getAsShort("lvl", (short) 1))); javaTag.setValue(javaValue); tags.add(javaTag); } else { From cdab1ce5ec32d69c29f5119cb1cc7703177ac21f Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 7 Dec 2019 14:56:00 -0900 Subject: [PATCH 24/32] Translate window properties Furnace and brewing stand --- .../BrewingStandInventoryTranslator.java | 17 +++++++++++++---- .../inventory/FurnaceInventoryTranslator.java | 13 ++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java index e6089cb8..91f9d327 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java @@ -36,22 +36,31 @@ public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { super(5, 117 << 4, ContainerType.BREWING_STAND); } + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + super.openInventory(session, inventory); + ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); + dataPacket.setWindowId((byte) inventory.getId()); + dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_TOTAL); + dataPacket.setValue(20); + session.getUpstream().sendPacket(dataPacket); + } + @Override public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - //bedrock protocol library is currently missing property mappings for windows. ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); dataPacket.setWindowId((byte) inventory.getId()); switch (key) { case 0: - dataPacket.setProperty(ContainerSetDataPacket.Property.BREWING_STAND_BREW_TIME); + dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_BREW_TIME); break; case 1: - dataPacket.setProperty(ContainerSetDataPacket.Property.BREWING_STAND_FUEL_AMOUNT); + dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_AMOUNT); break; default: return; } - dataPacket.setValue((short) value); + dataPacket.setValue(value); session.getUpstream().sendPacket(dataPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index 95d78562..12a634ff 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.connector.inventory.Inventory; @@ -37,23 +38,25 @@ public class FurnaceInventoryTranslator extends BlockInventoryTranslator { @Override public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - //bedrock protocol library is currently missing property mappings for windows. only the furnace arrow will update for now ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); dataPacket.setWindowId((byte) inventory.getId()); switch (key) { case 0: - dataPacket.setProperty(ContainerSetDataPacket.Property.FURNACE_LIT_TIME); + dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_TIME); break; case 1: - dataPacket.setProperty(ContainerSetDataPacket.Property.FURNACE_LIT_DURATION); + dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_DURATION); break; case 2: - dataPacket.setProperty(ContainerSetDataPacket.Property.FURNACE_TICK_COUNT); + dataPacket.setProperty(ContainerSetDataPacket.FURNACE_TICK_COUNT); + if (inventory.getWindowType() == WindowType.BLAST_FURNACE || inventory.getWindowType() == WindowType.SMOKER) { + value *= 2; + } break; default: return; } - dataPacket.setValue((short) value); + dataPacket.setValue(value); session.getUpstream().sendPacket(dataPacket); } From f524407c1d47ef160c737467e02a475aefbcc625 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 7 Dec 2019 15:06:56 -0900 Subject: [PATCH 25/32] Fix brewing --- .../translators/java/JavaDeclareRecipesTranslator.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 5cc98c3f..9015fc28 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -33,6 +33,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.ServerDeclareRecip import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.CraftingData; import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.data.PotionMixData; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -49,6 +50,8 @@ import java.util.stream.Collectors; public class JavaDeclareRecipesTranslator extends PacketTranslator { + private final int[] brewingIngredients = new int[]{372, 331, 348, 376, 289, 437, 353, 414, 382, 375, 462, 378, 396, 377, 370, 469, 470}; + @Override public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) { CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); @@ -80,6 +83,9 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator Date: Sat, 21 Dec 2019 01:32:49 -0900 Subject: [PATCH 26/32] Handle new creative_items.json format --- .../src/main/java/org/geysermc/connector/utils/Toolbox.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3b0d02a2..c47256da 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -116,7 +116,7 @@ public class Toolbox { List> creativeItemEntries = new ArrayList<>(); try { - creativeItemEntries = creativeItemMapper.readValue(creativeItemStream, ArrayList.class); + creativeItemEntries = (ArrayList>) creativeItemMapper.readValue(creativeItemStream, HashMap.class).get("items"); } catch (Exception e) { e.printStackTrace(); } From 20595a6e03c323450ce7200ceeca2d05aab60ad8 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 21 Dec 2019 01:35:34 -0900 Subject: [PATCH 27/32] Exclude Edu items from creative --- .../resources/bedrock/creative_items.json | 372 ------------------ 1 file changed, 372 deletions(-) diff --git a/connector/src/main/resources/bedrock/creative_items.json b/connector/src/main/resources/bedrock/creative_items.json index d55839ba..8045b219 100644 --- a/connector/src/main/resources/bedrock/creative_items.json +++ b/connector/src/main/resources/bedrock/creative_items.json @@ -3008,21 +3008,6 @@ { "id" : -198 }, - { - "id" : 238, - "damage" : 8 - }, - { - "id" : 238 - }, - { - "id" : 238, - "damage" : 12 - }, - { - "id" : 238, - "damage" : 4 - }, { "id" : 379 }, @@ -3419,363 +3404,6 @@ { "id" : 386 }, - { - "id" : 36 - }, - { - "id" : -12 - }, - { - "id" : -13 - }, - { - "id" : -14 - }, - { - "id" : -15 - }, - { - "id" : -16 - }, - { - "id" : -17 - }, - { - "id" : -18 - }, - { - "id" : -19 - }, - { - "id" : -20 - }, - { - "id" : -21 - }, - { - "id" : -22 - }, - { - "id" : -23 - }, - { - "id" : -24 - }, - { - "id" : -25 - }, - { - "id" : -26 - }, - { - "id" : -27 - }, - { - "id" : -28 - }, - { - "id" : -29 - }, - { - "id" : -30 - }, - { - "id" : -31 - }, - { - "id" : -32 - }, - { - "id" : -33 - }, - { - "id" : -34 - }, - { - "id" : -35 - }, - { - "id" : -36 - }, - { - "id" : -37 - }, - { - "id" : -38 - }, - { - "id" : -39 - }, - { - "id" : -40 - }, - { - "id" : -41 - }, - { - "id" : -42 - }, - { - "id" : -43 - }, - { - "id" : -44 - }, - { - "id" : -45 - }, - { - "id" : -46 - }, - { - "id" : -47 - }, - { - "id" : -48 - }, - { - "id" : -49 - }, - { - "id" : -50 - }, - { - "id" : -51 - }, - { - "id" : -52 - }, - { - "id" : -53 - }, - { - "id" : -54 - }, - { - "id" : -55 - }, - { - "id" : -56 - }, - { - "id" : -57 - }, - { - "id" : -58 - }, - { - "id" : -59 - }, - { - "id" : -60 - }, - { - "id" : -61 - }, - { - "id" : -62 - }, - { - "id" : -63 - }, - { - "id" : -64 - }, - { - "id" : -65 - }, - { - "id" : -66 - }, - { - "id" : -67 - }, - { - "id" : -68 - }, - { - "id" : -69 - }, - { - "id" : -70 - }, - { - "id" : -71 - }, - { - "id" : -72 - }, - { - "id" : -73 - }, - { - "id" : -74 - }, - { - "id" : -75 - }, - { - "id" : -76 - }, - { - "id" : -77 - }, - { - "id" : -78 - }, - { - "id" : -79 - }, - { - "id" : -80 - }, - { - "id" : -81 - }, - { - "id" : -82 - }, - { - "id" : -83 - }, - { - "id" : -84 - }, - { - "id" : -85 - }, - { - "id" : -86 - }, - { - "id" : -87 - }, - { - "id" : -88 - }, - { - "id" : -89 - }, - { - "id" : -90 - }, - { - "id" : -91 - }, - { - "id" : -92 - }, - { - "id" : -93 - }, - { - "id" : -94 - }, - { - "id" : -95 - }, - { - "id" : -96 - }, - { - "id" : -97 - }, - { - "id" : -98 - }, - { - "id" : -99 - }, - { - "id" : -100 - }, - { - "id" : -101 - }, - { - "id" : -102 - }, - { - "id" : -103 - }, - { - "id" : -104 - }, - { - "id" : -105 - }, - { - "id" : -106 - }, - { - "id" : -107 - }, - { - "id" : -108 - }, - { - "id" : -109 - }, - { - "id" : -110 - }, - { - "id" : -111 - }, - { - "id" : -112 - }, - { - "id" : -113 - }, - { - "id" : -114 - }, - { - "id" : -115 - }, - { - "id" : -116 - }, - { - "id" : -117 - }, - { - "id" : -118 - }, - { - "id" : -119 - }, - { - "id" : -120 - }, - { - "id" : -121 - }, - { - "id" : -122 - }, - { - "id" : -123 - }, - { - "id" : -124 - }, - { - "id" : -125 - }, - { - "id" : -126 - }, - { - "id" : -127 - }, - { - "id" : -128 - }, - { - "id" : -129 - }, { "id" : 403, "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAAAAAA=" From 46205600dd38e86ac579495f2ce11659fa3e5757 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 23 Dec 2019 17:00:31 -0900 Subject: [PATCH 28/32] Fix block ids --- .../network/translators/TranslatorsInit.java | 8 ++++---- .../inventory/AnvilInventoryTranslator.java | 2 +- .../inventory/BlockInventoryTranslator.java | 10 +++++----- .../inventory/BrewingStandInventoryTranslator.java | 2 +- .../inventory/DoubleChestInventoryTranslator.java | 11 +++++------ .../inventory/EnchantmentInventoryTranslator.java | 2 +- .../inventory/FurnaceInventoryTranslator.java | 2 +- .../inventory/SingleChestInventoryTranslator.java | 2 +- 8 files changed, 19 insertions(+), 20 deletions(-) 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 77a4fa12..31559d96 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 @@ -183,9 +183,9 @@ public class TranslatorsInit { inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace); inventoryTranslators.put(WindowType.SMOKER, furnace); - inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, 23 << 4, ContainerType.DISPENSER)); - inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, 154 << 4, ContainerType.HOPPER)); - inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, 205 << 4, ContainerType.CONTAINER)); - //inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, 138 << 4, ContainerType.BEACON)); //TODO + inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); + inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); + inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER)); + //inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java index 33815596..115a7dbd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.data.InventoryAction; public class AnvilInventoryTranslator extends BlockInventoryTranslator { public AnvilInventoryTranslator() { - super(3, 145 << 4, ContainerType.ANVIL); + super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java index 0112dc9e..54ab9bce 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java @@ -34,16 +34,16 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; 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.block.BlockEntry; -import org.geysermc.connector.world.GlobalBlockPalette; public class BlockInventoryTranslator extends ContainerInventoryTranslator { final int blockId; private final ContainerType containerType; - public BlockInventoryTranslator(int size, int blockId, ContainerType containerType) { + public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType) { super(size); - this.blockId = blockId; + this.blockId = TranslatorsInit.getBlockTranslator().getBlockEntry(javaBlockIdentifier).getBedrockRuntimeId(); this.containerType = containerType; } @@ -54,7 +54,7 @@ public class BlockInventoryTranslator extends ContainerInventoryTranslator { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(blockId)); + blockPacket.setRuntimeId(blockId); blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); inventory.setHolderPosition(position); @@ -88,7 +88,7 @@ public class BlockInventoryTranslator extends ContainerInventoryTranslator { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); session.getUpstream().sendPacket(blockPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java index 91f9d327..532928e6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java @@ -33,7 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession; public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { public BrewingStandInventoryTranslator() { - super(5, 117 << 4, ContainerType.BREWING_STAND); + super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index 6c5057bb..e0825ed8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -37,11 +37,10 @@ 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.block.BlockEntry; -import org.geysermc.connector.world.GlobalBlockPalette; public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { public DoubleChestInventoryTranslator(int size) { - super(size, 54 << 4, ContainerType.CONTAINER); + super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER); } @Override @@ -51,7 +50,7 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(blockId)); + blockPacket.setRuntimeId(blockId); blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); @@ -71,7 +70,7 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(blockId)); + blockPacket.setRuntimeId(blockId); blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); session.getUpstream().sendPacket(blockPacket); @@ -99,7 +98,7 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); session.getUpstream().sendPacket(blockPacket); holderPos = holderPos.add(Vector3i.UNIT_X); @@ -108,7 +107,7 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(GlobalBlockPalette.getOrCreateRuntimeId(realBlock.getBedrockId() << 4 | realBlock.getBedrockData())); + blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); session.getUpstream().sendPacket(blockPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java index 410bdc6a..0b4ed4ba 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java @@ -31,7 +31,7 @@ import org.geysermc.connector.network.session.GeyserSession; public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { public EnchantmentInventoryTranslator() { - super(2, 116 << 4, ContainerType.ENCHANTMENT); + super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index 12a634ff..a2eefac4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -33,7 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession; public class FurnaceInventoryTranslator extends BlockInventoryTranslator { public FurnaceInventoryTranslator() { - super(3, 61 << 4, ContainerType.FURNACE); + super(3, "minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index 3b2c70d9..16111708 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -34,7 +34,7 @@ import org.geysermc.connector.network.translators.TranslatorsInit; public class SingleChestInventoryTranslator extends BlockInventoryTranslator { public SingleChestInventoryTranslator(int size) { - super(size, 54 << 4, ContainerType.CONTAINER); + super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER); } @Override From 1a9aa4255f092a609c63a86b53b99f131113ac60 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 30 Jan 2020 16:05:57 -0900 Subject: [PATCH 29/32] Some refactoring and bug fixes Still much to do. Inventory desyncing when crafting will be fixed soon. --- .../network/translators/TranslatorsInit.java | 16 +- ...BedrockInventoryTransactionTranslator.java | 499 +----------------- .../inventory/AnvilInventoryTranslator.java | 63 ++- ...ator.java => BaseInventoryTranslator.java} | 63 +-- .../inventory/BlockInventoryTranslator.java | 71 +-- ...r.java => BrewingInventoryTranslator.java} | 22 +- ....java => CraftingInventoryTranslator.java} | 49 +- .../DoubleChestInventoryTranslator.java | 58 +- .../EnchantmentInventoryTranslator.java | 5 +- .../inventory/FurnaceInventoryTranslator.java | 5 +- .../inventory/InventoryTranslator.java | 9 +- .../inventory/PlayerInventoryTranslator.java | 77 ++- .../SingleChestInventoryTranslator.java | 31 +- .../translators/inventory/SlotType.java | 2 +- .../translators/inventory/action/Click.java | 38 ++ .../inventory/action/ClickPlan.java | 125 +++++ .../action/InventoryActionTranslator.java | 330 ++++++++++++ .../holder/BlockInventoryHolder.java | 90 ++++ .../inventory/holder/InventoryHolder.java | 36 ++ .../updater/ChestInventoryUpdater.java | 72 +++ .../updater/ContainerInventoryUpdater.java | 64 +++ .../updater/CursorInventoryUpdater.java | 64 +++ .../inventory/updater/InventoryUpdater.java | 61 +++ .../network/translators/item/Enchantment.java | 2 +- .../translators/item/ItemTranslator.java | 3 +- .../network/translators/item/Potion.java | 2 +- .../java/JavaDeclareRecipesTranslator.java | 15 +- .../JavaPlayerChangeHeldItemTranslator.java | 45 ++ .../window/JavaCloseWindowTranslator.java | 2 +- .../JavaConfirmTransactionTranslator.java | 2 +- .../java/window/JavaOpenWindowTranslator.java | 2 +- .../java/window/JavaSetSlotTranslator.java | 4 +- .../window/JavaWindowPropertyTranslator.java | 2 +- .../connector/utils/InventoryUtils.java | 34 ++ .../org/geysermc/connector/utils/Toolbox.java | 21 +- 35 files changed, 1282 insertions(+), 702 deletions(-) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{ContainerInventoryTranslator.java => BaseInventoryTranslator.java} (50%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{BrewingStandInventoryTranslator.java => BrewingInventoryTranslator.java} (86%) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/{CraftingTableInventoryTranslator.java => CraftingInventoryTranslator.java} (61%) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerChangeHeldItemTranslator.java 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 53850009..6b3adf15 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 @@ -46,6 +46,8 @@ import lombok.Getter; import org.geysermc.connector.network.translators.bedrock.*; import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.network.translators.inventory.*; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.java.*; import org.geysermc.connector.network.translators.java.entity.*; @@ -72,7 +74,7 @@ public class TranslatorsInit { private static BlockTranslator blockTranslator; @Getter - private static Map inventoryTranslators = new HashMap(); + private static Map inventoryTranslators = new HashMap<>(); private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag(); public static final byte[] EMPTY_LEVEL_CHUNK_DATA; @@ -127,6 +129,7 @@ public class TranslatorsInit { Registry.registerJava(ServerPlayerSetExperiencePacket.class, new JavaPlayerSetExperienceTranslator()); Registry.registerJava(ServerPlayerHealthPacket.class, new JavaPlayerHealthTranslator()); Registry.registerJava(ServerPlayerActionAckPacket.class, new JavaPlayerActionAckTranslator()); + Registry.registerJava(ServerPlayerChangeHeldItemPacket.class, new JavaPlayerChangeHeldItemTranslator()); // FIXME: This translator messes with allowing flight in creative mode. Will need to be addressed later // Registry.registerJava(ServerPlayerAbilitiesPacket.class, new JavaPlayerAbilitiesTranslator()); @@ -176,9 +179,9 @@ public class TranslatorsInit { inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); - inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingStandInventoryTranslator()); + inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator()); - inventoryTranslators.put(WindowType.CRAFTING, new CraftingTableInventoryTranslator()); + inventoryTranslators.put(WindowType.CRAFTING, new CraftingInventoryTranslator()); //inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO InventoryTranslator furnace = new FurnaceInventoryTranslator(); @@ -186,9 +189,10 @@ public class TranslatorsInit { inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace); inventoryTranslators.put(WindowType.SMOKER, furnace); - inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER)); - inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER)); - inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER)); + InventoryUpdater containerUpdater = new ContainerInventoryUpdater(); + inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater)); + inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater)); + inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater)); //inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index ca6729b9..ee12b5aa 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -25,13 +25,7 @@ package org.geysermc.connector.network.translators.bedrock; -import com.github.steveice10.mc.protocol.data.game.window.*; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3f; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; @@ -41,382 +35,31 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; -import com.nukkitx.protocol.bedrock.data.ContainerId; -import com.nukkitx.protocol.bedrock.data.InventoryAction; -import com.nukkitx.protocol.bedrock.data.InventorySource; -import com.nukkitx.protocol.bedrock.data.ItemData; -import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.TranslatorsInit; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.utils.InventoryUtils; import java.util.*; public class BedrockInventoryTransactionTranslator extends PacketTranslator { - private final ItemStack refreshItem = new ItemStack(1, 127, new CompoundTag("")); @Override public void translate(InventoryTransactionPacket packet, GeyserSession session) { switch (packet.getTransactionType()) { case NORMAL: - for (InventoryAction action : packet.getActions()) { - if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT || - action.getSource().getContainerId() == ContainerId.CRAFTING_RESULT) { - return; - } - } - Inventory inventory = session.getInventoryCache().getOpenInventory(); - if (inventory == null) - inventory = session.getInventory(); - InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); - - int craftSlot = session.getCraftSlot(); - session.setCraftSlot(0); - - if (session.getGameMode() == GameMode.CREATIVE && inventory.getId() == 0) { - ItemStack javaItem; - for (InventoryAction action : packet.getActions()) { - switch (action.getSource().getContainerId()) { - case ContainerId.INVENTORY: - case ContainerId.ARMOR: - case ContainerId.OFFHAND: - int javaSlot = translator.bedrockSlotToJava(action); - if (action.getToItem().getId() == 0) { - javaItem = new ItemStack(-1, 0, null); - } else { - javaItem = TranslatorsInit.getItemTranslator().translateToJava(action.getToItem()); - if (javaItem.getId() == 0) { //item missing mapping - translator.updateInventory(session, inventory); - break; - } - } - ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, fixStack(javaItem)); - session.getDownstream().getSession().send(creativePacket); - inventory.setItem(javaSlot, javaItem); - break; - case ContainerId.NONE: - if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION && - action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { - javaItem = TranslatorsInit.getItemTranslator().translateToJava(action.getToItem()); - if (javaItem.getId() == 0) { //item missing mapping - break; - } - ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, fixStack(javaItem)); - session.getDownstream().getSession().send(creativeDropPacket); - } - break; - } - } - return; - } - - InventoryAction worldAction = null; - InventoryAction cursorAction = null; - for (InventoryAction action : packet.getActions()) { - if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) { - worldAction = action; - } else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) { - cursorAction = action; - } - } - List actions = packet.getActions(); - if (inventory.getWindowType() == WindowType.ANVIL) { - InventoryAction anvilResult = null; - InventoryAction anvilInput = null; - for (InventoryAction action : packet.getActions()) { - if (action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL) { - //useless packet - return; - } else if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) { - anvilResult = action; - } else if (translator.bedrockSlotToJava(action) == 0) { - anvilInput = action; - } - } - ItemData itemName = null; - if (anvilResult != null) { - itemName = anvilResult.getFromItem(); - } else if (anvilInput != null) { - itemName = anvilInput.getToItem(); - } - if (itemName != null) { - String rename; - com.nukkitx.nbt.tag.CompoundTag tag = itemName.getTag(); - if (tag != null) { - rename = tag.getAsCompound("display").getAsString("Name"); - } else { - rename = ""; - } - ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename); - session.getDownstream().getSession().send(renameItemPacket); - } - if (anvilResult != null) { - //client will send another packet to grab anvil output - //this packet was only used to send rename packet - return; - } - } - - if (actions.size() == 2) { - if (worldAction != null) { - //find container action - InventoryAction containerAction = null; - for (InventoryAction action : actions) { - if (action != worldAction) { - containerAction = action; - break; - } - } - if (containerAction != null && worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { - //quick dropping from hotbar? - if (session.getInventoryCache().getOpenInventory() == null && containerAction.getSource().getContainerId() == ContainerId.INVENTORY) { - int heldSlot = session.getInventory().getHeldItemSlot(); - if (containerAction.getSlot() == heldSlot) { - ClientPlayerActionPacket actionPacket = new ClientPlayerActionPacket( - containerAction.getToItem().getCount() == 0 ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM, - new Position(0, 0, 0), BlockFace.DOWN); - session.getDownstream().getSession().send(actionPacket); - ItemStack item = session.getInventory().getItem(heldSlot); - if (item != null) { - session.getInventory().setItem(heldSlot, new ItemStack(item.getId(), item.getAmount() - 1, item.getNbt())); - } - return; - } - } - int dropAmount = containerAction.getFromItem().getCount() - containerAction.getToItem().getCount(); - if (containerAction != cursorAction) { //dropping directly from inventory - int javaSlot = translator.bedrockSlotToJava(containerAction); - if (dropAmount == containerAction.getFromItem().getCount()) { - ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - javaSlot, null, WindowAction.DROP_ITEM, - DropItemParam.DROP_SELECTED_STACK); - session.getDownstream().getSession().send(dropPacket); - } else { - for (int i = 0; i < dropAmount; i++) { - ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - javaSlot, null, WindowAction.DROP_ITEM, - DropItemParam.DROP_FROM_SELECTED); - session.getDownstream().getSession().send(dropPacket); - } - } - ItemStack item = session.getInventory().getItem(javaSlot); - if (item != null) { - session.getInventory().setItem(javaSlot, new ItemStack(item.getId(), item.getAmount() - dropAmount, item.getNbt())); - } - return; - } else { //clicking outside of inventory - ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), - -999, null, WindowAction.CLICK_ITEM, - dropAmount > 1 ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK); - session.getDownstream().getSession().send(dropPacket); - ItemStack cursor = session.getInventory().getCursor(); - if (cursor != null) { - session.getInventory().setCursor(new ItemStack(cursor.getId(), dropAmount > 1 ? 0 : cursor.getAmount() - 1, cursor.getNbt())); - } - return; - } - } - } else if (cursorAction != null) { - //find container action - InventoryAction containerAction = null; - for (InventoryAction action : actions) { - if (action != cursorAction) { - containerAction = action; - break; - } - } - if (containerAction != null) { - //left/right click - List plan = new ArrayList<>(); - ItemStack translatedCursor = cursorAction.getFromItem().isValid() ? - TranslatorsInit.getItemTranslator().translateToJava(cursorAction.getFromItem()) : null; - ItemStack currentCursor = session.getInventory().getCursor(); - boolean refresh = false; - if (currentCursor != null) { - if (translatedCursor != null) { - refresh = !(currentCursor.getId() == translatedCursor.getId() && - currentCursor.getAmount() == translatedCursor.getAmount()); - } else { - refresh = true; - } - } - - int javaSlot = translator.bedrockSlotToJava(containerAction); - if (cursorAction.getFromItem().equals(containerAction.getToItem()) && - containerAction.getFromItem().equals(cursorAction.getToItem()) && - !canStack(cursorAction.getFromItem(), containerAction.getFromItem())) { //simple swap - Click.LEFT.onSlot(javaSlot, plan); - } else if (cursorAction.getFromItem().getCount() > cursorAction.getToItem().getCount()) { //release - if (cursorAction.getToItem().getCount() == 0) { - Click.LEFT.onSlot(javaSlot, plan); - } else { - int difference = cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); - for (int i = 0; i < difference; i++) { - Click.RIGHT.onSlot(javaSlot, plan); - } - } - } else { //pickup - if (cursorAction.getFromItem().getCount() == 0) { - if (containerAction.getToItem().getCount() == 0) { //pickup all - Click.LEFT.onSlot(javaSlot, plan); - } else { //pickup some - if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT || - containerAction.getToItem().getCount() == containerAction.getFromItem().getCount() / 2) { //right click - Click.RIGHT.onSlot(javaSlot, plan); - } else { - Click.LEFT.onSlot(javaSlot, plan); - int difference = containerAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); - for (int i = 0; i < difference; i++) { - Click.RIGHT.onSlot(javaSlot, plan); - } - } - } - } else { //pickup into non-empty cursor - if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT) { - if (containerAction.getToItem().getCount() == 0) { - Click.LEFT.onSlot(javaSlot, plan); - } else { - ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - javaSlot, refreshItem, WindowAction.SHIFT_CLICK_ITEM, - ShiftClickItemParam.LEFT_CLICK); - session.getDownstream().getSession().send(shiftClickPacket); - translator.updateInventory(session, inventory); - return; - } - } else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) { - Click.LEFT.onSlot(javaSlot, plan); - } else { - int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot)); - if (cursorSlot != -1) { - Click.LEFT.onSlot(cursorSlot, plan); - } else { - translator.updateInventory(session, inventory); - return; - } - Click.LEFT.onSlot(javaSlot, plan); - int difference = cursorAction.getToItem().getCount() - cursorAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - Click.RIGHT.onSlot(cursorSlot, plan); - } - Click.LEFT.onSlot(javaSlot, plan); - Click.LEFT.onSlot(cursorSlot, plan); - } - } - } - executePlan(session, inventory, translator, plan, refresh); - return; - } - } else { - List plan = new ArrayList<>(); - InventoryAction fromAction; - InventoryAction toAction; - if (actions.get(0).getFromItem().getCount() >= actions.get(0).getToItem().getCount()) { - fromAction = actions.get(0); - toAction = actions.get(1); - } else { - fromAction = actions.get(1); - toAction = actions.get(0); - } - int fromSlot = translator.bedrockSlotToJava(fromAction); - int toSlot = translator.bedrockSlotToJava(toAction); - - if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) { - if ((craftSlot != 0 && craftSlot != -2) && (inventory.getItem(toSlot) == null || - canStack(session.getInventory().getCursor(), inventory.getItem(toSlot)))) { - boolean refresh = false; - if (fromAction.getToItem().getCount() == 0) { - refresh = true; - Click.LEFT.onSlot(toSlot, plan); - if (craftSlot != -1) { - Click.LEFT.onSlot(craftSlot, plan); - } - } else { - int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - Click.RIGHT.onSlot(toSlot, plan); - } - session.setCraftSlot(craftSlot); - } - executePlan(session, inventory, translator, plan, refresh); - return; - } else { - session.setCraftSlot(-2); - } - } - - int cursorSlot = -1; - if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot - cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot)); - if (cursorSlot != -1) { - Click.LEFT.onSlot(cursorSlot, plan); - } else { - translator.updateInventory(session, inventory); - return; - } - } - if ((fromAction.getFromItem().equals(toAction.getToItem()) && !canStack(fromAction.getFromItem(), toAction.getFromItem())) || fromAction.getToItem().getId() == 0) { //slot swap - Click.LEFT.onSlot(fromSlot, plan); - Click.LEFT.onSlot(toSlot, plan); - if (fromAction.getToItem().getId() != 0) { - Click.LEFT.onSlot(fromSlot, plan); - } - } else if (canStack(fromAction.getFromItem(), toAction.getToItem())) { //partial item move - if (translator.getSlotType(fromSlot) == SlotType.FURNACE_OUTPUT) { - ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - fromSlot, refreshItem, WindowAction.SHIFT_CLICK_ITEM, - ShiftClickItemParam.LEFT_CLICK); - session.getDownstream().getSession().send(shiftClickPacket); - translator.updateInventory(session, inventory); - return; - } else if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) { - session.setCraftSlot(cursorSlot); - Click.LEFT.onSlot(fromSlot, plan); - int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - Click.RIGHT.onSlot(toSlot, plan); - } - //client will send additional packets later to finish transferring crafting output - //translator will know how to handle this using the craftSlot variable - } else { - Click.LEFT.onSlot(fromSlot, plan); - int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); - for (int i = 0; i < difference; i++) { - Click.RIGHT.onSlot(toSlot, plan); - } - Click.LEFT.onSlot(fromSlot, plan); - } - } - if (cursorSlot != -1) { - Click.LEFT.onSlot(cursorSlot, plan); - } - executePlan(session, inventory, translator, plan, false); - return; - } - } - translator.updateInventory(session, inventory); + if (inventory == null) inventory = session.getInventory(); + TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions()); break; case INVENTORY_MISMATCH: - InventorySlotPacket cursorPacket = new InventorySlotPacket(); - cursorPacket.setContainerId(ContainerId.CURSOR); - cursorPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(session.getInventory().getCursor())); - //session.getUpstream().sendPacket(cursorPacket); - Inventory inv = session.getInventoryCache().getOpenInventory(); - if (inv == null) - inv = session.getInventory(); + if (inv == null) inv = session.getInventory(); TranslatorsInit.getInventoryTranslators().get(inv.getWindowType()).updateInventory(session, inv); + InventoryUtils.updateCursor(session); break; case ITEM_USE: if (packet.getActionType() == 1) { @@ -448,136 +91,4 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator slotBlacklist) { - /*try and find a slot that can temporarily store the given item - only look in the main inventory and hotbar - only slots that are empty or contain a different type of item are valid*/ - int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable slot (some servers disable it) - List itemBlacklist = new ArrayList<>(slotBlacklist.size() + 1); - itemBlacklist.add(item); - for (int slot : slotBlacklist) { - ItemStack blacklistItem = inventory.getItem(slot); - if (blacklistItem != null) - itemBlacklist.add(blacklistItem); - } - for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) { - ItemStack testItem = inventory.getItem(i); - boolean acceptable = true; - if (testItem != null) { - for (ItemStack blacklistItem : itemBlacklist) { - if (canStack(testItem, blacklistItem)) { - acceptable = false; - break; - } - } - } - if (acceptable && !slotBlacklist.contains(i)) - return i; - } - //could not find a viable temp slot - return -1; - } - - //NPE if compound tag is null - private ItemStack fixStack(ItemStack stack) { - if (stack == null || stack.getId() == 0) - return null; - return new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() == null ? new CompoundTag("") : stack.getNbt()); - } - - private boolean canStack(ItemStack item1, ItemStack item2) { - if (item1 == null || item2 == null) - return false; - return item1.getId() == item2.getId() && Objects.equals(item1.getNbt(), item2.getNbt()); - } - - private boolean canStack(ItemData item1, ItemData item2) { - if (item1 == null || item2 == null) - return false; - return item1.equals(item2, false, true, true); - } - - private void executePlan(GeyserSession session, Inventory inventory, InventoryTranslator translator, List plan, boolean refresh) { - PlayerInventory playerInventory = session.getInventory(); - ListIterator planIter = plan.listIterator(); - while (planIter.hasNext()) { - ClickAction action = planIter.next(); - ItemStack cursorItem = playerInventory.getCursor(); - ItemStack clickedItem = inventory.getItem(action.slot); - short actionId = (short) inventory.getTransactionId().getAndIncrement(); - boolean isOutput = translator.getSlotType(action.slot) == SlotType.OUTPUT; - - if (isOutput || translator.getSlotType(action.slot) == SlotType.FURNACE_OUTPUT) - refresh = true; - ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(), - actionId, action.slot, !planIter.hasNext() && refresh ? refreshItem : fixStack(clickedItem), - WindowAction.CLICK_ITEM, action.click.actionParam); - - if (isOutput) { - if (cursorItem == null && clickedItem != null) { - playerInventory.setCursor(clickedItem); - } else if (canStack(cursorItem, clickedItem)) { - playerInventory.setCursor(new ItemStack(cursorItem.getId(), - cursorItem.getAmount() + clickedItem.getAmount(), cursorItem.getNbt())); - } - } else { - switch (action.click) { - case LEFT: - if (!canStack(cursorItem, clickedItem)) { - playerInventory.setCursor(clickedItem); - inventory.setItem(action.slot, cursorItem); - } else { - playerInventory.setCursor(null); - inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), - clickedItem.getAmount() + cursorItem.getAmount(), clickedItem.getNbt())); - } - break; - case RIGHT: - if (cursorItem == null && clickedItem != null) { - ItemStack halfItem = new ItemStack(clickedItem.getId(), - clickedItem.getAmount() / 2, clickedItem.getNbt()); - inventory.setItem(action.slot, halfItem); - playerInventory.setCursor(new ItemStack(clickedItem.getId(), - clickedItem.getAmount() - halfItem.getAmount(), clickedItem.getNbt())); - } else if (cursorItem != null && clickedItem == null) { - playerInventory.setCursor(new ItemStack(cursorItem.getId(), - cursorItem.getAmount() - 1, cursorItem.getNbt())); - inventory.setItem(action.slot, new ItemStack(cursorItem.getId(), - 1, cursorItem.getNbt())); - } else if (canStack(cursorItem, clickedItem)) { - playerInventory.setCursor(new ItemStack(cursorItem.getId(), - cursorItem.getAmount() - 1, cursorItem.getNbt())); - inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), - clickedItem.getAmount() + 1, clickedItem.getNbt())); - } - break; - } - } - session.getDownstream().getSession().send(clickPacket); - session.getDownstream().getSession().send(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true)); - } - } - - private enum Click { - LEFT(ClickItemParam.LEFT_CLICK), - RIGHT(ClickItemParam.RIGHT_CLICK); - - final WindowActionParam actionParam; - Click(WindowActionParam actionParam) { - this.actionParam = actionParam; - } - void onSlot(int slot, List plan) { - plan.add(new ClickAction(slot, this)); - } - } - - private static class ClickAction { - final int slot; - final Click click; - ClickAction(int slot, Click click) { - this.slot = slot; - this.click = click; - } - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java index 115a7dbd..39575188 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,13 +25,20 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.ItemData; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; + +import java.util.List; public class AnvilInventoryTranslator extends BlockInventoryTranslator { public AnvilInventoryTranslator() { - super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL); + super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, new CursorInventoryUpdater()); } @Override @@ -49,10 +56,62 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { return super.bedrockSlotToJava(action); } + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 50; + } + return super.javaSlotToBedrock(slot); + } + @Override public SlotType getSlotType(int javaSlot) { if (javaSlot == 2) return SlotType.OUTPUT; return SlotType.NORMAL; } + + @Override + public void translateActions(GeyserSession session, Inventory inventory, List actions) { + InventoryAction anvilResult = null; + InventoryAction anvilInput = null; + for (InventoryAction action : actions) { + if (action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL) { + //useless packet + return; + } else if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) { + anvilResult = action; + } else if (bedrockSlotToJava(action) == 0) { + anvilInput = action; + } + } + ItemData itemName = null; + if (anvilResult != null) { + itemName = anvilResult.getFromItem(); + } else if (anvilInput != null) { + itemName = anvilInput.getToItem(); + } + if (itemName != null) { + String rename; + com.nukkitx.nbt.tag.CompoundTag tag = itemName.getTag(); + if (tag != null) { + rename = tag.getAsCompound("display").getAsString("Name"); + } else { + rename = ""; + } + ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename); + session.getDownstream().getSession().send(renameItemPacket); + } + if (anvilResult != null) { + //client will send another packet to grab anvil output + return; + } + + super.translateActions(session, inventory, actions); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java similarity index 50% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java index 8f66675b..d64c0e78 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ContainerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,53 +27,20 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.InventoryAction; -import com.nukkitx.protocol.bedrock.data.ItemData; -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.network.translators.inventory.action.InventoryActionTranslator; -public abstract class ContainerInventoryTranslator extends InventoryTranslator { - ContainerInventoryTranslator(int size) { +import java.util.List; + +public abstract class BaseInventoryTranslator extends InventoryTranslator{ + BaseInventoryTranslator(int size) { super(size); } - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - ItemData[] bedrockItems = new ItemData[this.size]; - for (int i = 0; i < bedrockItems.length; i++) { - bedrockItems[javaSlotToBedrock(i)] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); - } - InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); - contentPacket.setContents(bedrockItems); - session.getUpstream().sendPacket(contentPacket); - - Inventory playerInventory = session.getInventory(); - for (int i = 0; i < 36; i++) { - playerInventory.setItem(i + 9, inventory.getItem(i + this.size)); - } - TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); - } - - @Override - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - if (slot >= this.size) { - Inventory playerInventory = session.getInventory(); - playerInventory.setItem((slot + 9) - this.size, inventory.getItem(slot)); - TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateSlot(session, playerInventory, (slot + 9) - this.size); - } else { - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(inventory.getId()); - slotPacket.setInventorySlot(javaSlotToBedrock(slot)); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(slot))); - session.getUpstream().sendPacket(slotPacket); - } - } - @Override public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { + // } @Override @@ -86,13 +53,20 @@ public abstract class ContainerInventoryTranslator extends InventoryTranslator { } else { return slotnum + this.size + 27; } - } else { - return slotnum; } + return slotnum; } @Override public int javaSlotToBedrock(int slot) { + if (slot >= this.size) { + final int tmp = slot - this.size; + if (tmp < 27) { + return tmp + 9; + } else { + return tmp - 27; + } + } return slot; } @@ -100,4 +74,9 @@ public abstract class ContainerInventoryTranslator extends InventoryTranslator { public SlotType getSlotType(int javaSlot) { return SlotType.NORMAL; } + + @Override + public void translateActions(GeyserSession session, Inventory inventory, List actions) { + InventoryActionTranslator.translate(this, session, inventory, actions); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java index 54ab9bce..32dfc2a6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,70 +25,47 @@ package org.geysermc.connector.network.translators.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; -import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; 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.block.BlockEntry; +import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; +import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -public class BlockInventoryTranslator extends ContainerInventoryTranslator { - final int blockId; - private final ContainerType containerType; +public class BlockInventoryTranslator extends BaseInventoryTranslator { + private final InventoryHolder holder; + private final InventoryUpdater updater; - public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType) { + public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { super(size); - this.blockId = TranslatorsInit.getBlockTranslator().getBlockEntry(javaBlockIdentifier).getBedrockRuntimeId(); - this.containerType = containerType; + final int blockId = TranslatorsInit.getBlockTranslator().getBlockEntry(javaBlockIdentifier).getBedrockRuntimeId(); + this.holder = new BlockInventoryHolder(blockId, containerType); + this.updater = updater; } @Override public void prepareInventory(GeyserSession session, Inventory inventory) { - Vector3i position = session.getPlayerEntity().getPosition().toInt(); - position = position.add(Vector3i.UP); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(blockId); - blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - session.getUpstream().sendPacket(blockPacket); - inventory.setHolderPosition(position); - - CompoundTag tag = CompoundTag.EMPTY.toBuilder() - .intTag("x", position.getX()) - .intTag("y", position.getY()) - .intTag("z", position.getZ()) - .stringTag("CustomName", inventory.getTitle()).buildRootTag(); - BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); - dataPacket.setData(tag); - dataPacket.setBlockPosition(position); - session.getUpstream().sendPacket(dataPacket); + holder.prepareInventory(this, session, inventory); } @Override public void openInventory(GeyserSession session, Inventory inventory) { - ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setWindowId((byte) inventory.getId()); - containerOpenPacket.setType((byte) containerType.id()); - containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); - containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); - session.getUpstream().sendPacket(containerOpenPacket); + holder.openInventory(this, session, inventory); } @Override public void closeInventory(GeyserSession session, Inventory inventory) { - Vector3i holderPos = inventory.getHolderPosition(); - Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setDataLayer(0); - blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); - session.getUpstream().sendPacket(blockPacket); + holder.closeInventory(this, session, inventory); + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + updater.updateInventory(this, session, inventory); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + updater.updateSlot(this, session, inventory, slot); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java similarity index 86% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java index 532928e6..c5f67a03 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingStandInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,10 +30,11 @@ import com.nukkitx.protocol.bedrock.data.InventoryAction; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; -public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { - public BrewingStandInventoryTranslator() { - super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND); +public class BrewingInventoryTranslator extends BlockInventoryTranslator { + public BrewingInventoryTranslator() { + super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND, new ContainerInventoryUpdater()); } @Override @@ -66,8 +67,8 @@ public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { @Override public int bedrockSlotToJava(InventoryAction action) { - int slotnum = super.bedrockSlotToJava(action); - switch (slotnum) { + final int slot = super.bedrockSlotToJava(action); + switch (slot) { case 0: return 3; case 1: @@ -77,13 +78,13 @@ public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { case 3: return 2; default: - return slotnum; + return slot; } } @Override - public int javaSlotToBedrock(int slotnum) { - switch (slotnum) { + public int javaSlotToBedrock(int slot) { + switch (slot) { case 0: return 1; case 1: @@ -92,8 +93,7 @@ public class BrewingStandInventoryTranslator extends BlockInventoryTranslator { return 3; case 3: return 0; - default: - return slotnum; } + return super.javaSlotToBedrock(slot); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java similarity index 61% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java index 28ad0cb2..fe70609f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingTableInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,21 +25,33 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventorySource; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +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.network.translators.inventory.updater.CursorInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; +import org.geysermc.connector.utils.InventoryUtils; -public class CraftingTableInventoryTranslator extends ContainerInventoryTranslator { - public CraftingTableInventoryTranslator() { +import java.util.List; + +public class CraftingInventoryTranslator extends BaseInventoryTranslator { + private final InventoryUpdater updater; + + public CraftingInventoryTranslator() { super(10); + this.updater = new CursorInventoryUpdater(); } @Override public void prepareInventory(GeyserSession session, Inventory inventory) { - + // } @Override @@ -54,7 +66,17 @@ public class CraftingTableInventoryTranslator extends ContainerInventoryTranslat @Override public void closeInventory(GeyserSession session, Inventory inventory) { + // + } + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + updater.updateInventory(this, session, inventory); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + updater.updateSlot(this, session, inventory, slot); } @Override @@ -70,10 +92,29 @@ public class CraftingTableInventoryTranslator extends ContainerInventoryTranslat return super.bedrockSlotToJava(action); } + @Override + public int javaSlotToBedrock(int slot) { + return slot == 0 ? 50 : slot + 31; + } + @Override public SlotType getSlotType(int javaSlot) { if (javaSlot == 0) return SlotType.OUTPUT; return SlotType.NORMAL; } + + @Override + public void translateActions(GeyserSession session, Inventory inventory, List actions) { + if (session.getGameMode() == GameMode.CREATIVE) { + for (InventoryAction action : actions) { + if (action.getSource().getType() == InventorySource.Type.CREATIVE) { + updateInventory(session, inventory); + InventoryUtils.updateCursor(session); + return; + } + } + } + super.translateActions(session, inventory, actions); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index e0825ed8..07d3a414 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,32 +29,39 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; -import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; 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.block.BlockEntry; +import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; + +public class DoubleChestInventoryTranslator extends BaseInventoryTranslator { + private final int blockId; + private final InventoryUpdater updater; -public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { public DoubleChestInventoryTranslator(int size) { - super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER); + super(size); + this.blockId = TranslatorsInit.getBlockTranslator().getBlockEntry("minecraft:chest[facing=north,type=single,waterlogged=false]").getBedrockRuntimeId(); + this.updater = new ChestInventoryUpdater(54); } @Override public void prepareInventory(GeyserSession session, Inventory inventory) { Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); blockPacket.setRuntimeId(blockId); - blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.getUpstream().sendPacket(blockPacket); - CompoundTag tag = CompoundTag.EMPTY.toBuilder() + CompoundTag tag = CompoundTag.builder() .stringTag("id", "Chest") .intTag("x", position.getX()) .intTag("y", position.getY()) @@ -71,10 +78,10 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { blockPacket.setDataLayer(0); blockPacket.setBlockPosition(pairPosition); blockPacket.setRuntimeId(blockId); - blockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.getUpstream().sendPacket(blockPacket); - tag = CompoundTag.EMPTY.toBuilder() + tag = CompoundTag.builder() .stringTag("id", "Chest") .intTag("x", pairPosition.getX()) .intTag("y", pairPosition.getY()) @@ -90,6 +97,16 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { inventory.setHolderPosition(position); } + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.CONTAINER.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.getUpstream().sendPacket(containerOpenPacket); + } + @Override public void closeInventory(GeyserSession session, Inventory inventory) { Vector3i holderPos = inventory.getHolderPosition(); @@ -113,24 +130,11 @@ public class DoubleChestInventoryTranslator extends BlockInventoryTranslator { @Override public void updateInventory(GeyserSession session, Inventory inventory) { - //need to pad empty slots for 4x9 and 5x9 - ItemData[] bedrockItems = new ItemData[54]; - for (int i = 0; i < bedrockItems.length; i++) { - if (i <= this.size) { - bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); - } else { - bedrockItems[i] = ItemData.AIR; - } - } - InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); - contentPacket.setContents(bedrockItems); - session.getUpstream().sendPacket(contentPacket); + updater.updateInventory(this, session, inventory); + } - Inventory playerInventory = session.getInventory(); - for (int i = 0; i < 36; i++) { - playerInventory.setItem(i + 9, inventory.getItem(i + this.size)); - } - TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + updater.updateSlot(this, session, inventory, slot); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java index 0b4ed4ba..ba7f8cc7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,10 +28,11 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.protocol.bedrock.data.ContainerType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { public EnchantmentInventoryTranslator() { - super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT); + super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, new ContainerInventoryUpdater()); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index a2eefac4..9b45201e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,10 +30,11 @@ import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; public class FurnaceInventoryTranslator extends BlockInventoryTranslator { public FurnaceInventoryTranslator() { - super(3, "minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE); + super(3, "minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE, new ContainerInventoryUpdater()); } @Override 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 index 91562194..7baef61a 100644 --- 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 @@ -26,16 +26,16 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.protocol.bedrock.data.InventoryAction; +import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import java.util.List; + +@AllArgsConstructor public abstract class InventoryTranslator { public final int size; - InventoryTranslator(int size) { - this.size = size; - } - public abstract void prepareInventory(GeyserSession session, Inventory inventory); public abstract void openInventory(GeyserSession session, Inventory inventory); public abstract void closeInventory(GeyserSession session, Inventory inventory); @@ -45,4 +45,5 @@ public abstract class InventoryTranslator { public abstract int bedrockSlotToJava(InventoryAction action); public abstract int javaSlotToBedrock(int slot); public abstract SlotType getSlotType(int javaSlot); + public abstract void translateActions(GeyserSession session, Inventory inventory, List actions); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index 6ba25bc5..acad709f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,12 +25,19 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.nukkitx.protocol.bedrock.data.*; 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.network.translators.inventory.action.InventoryActionTranslator; +import org.geysermc.connector.utils.InventoryUtils; + +import java.util.List; public class PlayerInventoryTranslator extends InventoryTranslator { public PlayerInventoryTranslator() { @@ -39,20 +46,26 @@ public class PlayerInventoryTranslator extends InventoryTranslator { @Override public void updateInventory(GeyserSession session, Inventory inventory) { + // Crafting grid + for (int i = 1; i < 5; i++) { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.CURSOR); + slotPacket.setInventorySlot(i + 27); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i))); + session.getUpstream().sendPacket(slotPacket); + } + InventoryContentPacket inventoryContentPacket = new InventoryContentPacket(); inventoryContentPacket.setContainerId(ContainerId.INVENTORY); - ItemData[] contents = new ItemData[36]; // Inventory for (int i = 9; i < 36; i++) { contents[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } - // Hotbar for (int i = 36; i < 45; i++) { contents[i - 36] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); } - inventoryContentPacket.setContents(contents); session.getUpstream().sendPacket(inventoryContentPacket); @@ -75,7 +88,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { @Override public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - if (slot >= 5 && slot <= 44) { + if (slot >= 1 && slot <= 44) { InventorySlotPacket slotPacket = new InventorySlotPacket(); if (slot >= 9) { slotPacket.setContainerId(ContainerId.INVENTORY); @@ -84,9 +97,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } else { slotPacket.setInventorySlot(slot); } - } else { + } else if (slot >= 5) { slotPacket.setContainerId(ContainerId.ARMOR); slotPacket.setInventorySlot(slot - 5); + } else { + slotPacket.setContainerId(ContainerId.CURSOR); + slotPacket.setInventorySlot(slot + 27); } slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(slot))); session.getUpstream().sendPacket(slotPacket); @@ -142,6 +158,55 @@ public class PlayerInventoryTranslator extends InventoryTranslator { return SlotType.NORMAL; } + @Override + public void translateActions(GeyserSession session, Inventory inventory, List actions) { + if (session.getGameMode() == GameMode.CREATIVE) { + //crafting grid is not visible in creative mode in java edition + for (InventoryAction action : actions) { + if (action.getSource().getContainerId() == ContainerId.CURSOR && (action.getSlot() >= 28 && 31 >= action.getSlot())) { + updateInventory(session, inventory); + InventoryUtils.updateCursor(session); + return; + } + } + + ItemStack javaItem; + for (InventoryAction action : actions) { + switch (action.getSource().getContainerId()) { + case ContainerId.INVENTORY: + case ContainerId.ARMOR: + case ContainerId.OFFHAND: + int javaSlot = bedrockSlotToJava(action); + if (action.getToItem().getId() == 0) { + javaItem = new ItemStack(-1, 0, null); + } else { + javaItem = TranslatorsInit.getItemTranslator().translateToJava(action.getToItem()); + } + ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, InventoryUtils.fixStack(javaItem)); + session.getDownstream().getSession().send(creativePacket); + inventory.setItem(javaSlot, javaItem); + break; + case ContainerId.CURSOR: + if (action.getSlot() == 0) { + session.getInventory().setCursor(TranslatorsInit.getItemTranslator().translateToJava(action.getToItem())); + } + break; + case ContainerId.NONE: + if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION + && action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { + javaItem = TranslatorsInit.getItemTranslator().translateToJava(action.getToItem()); + ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, InventoryUtils.fixStack(javaItem)); + session.getDownstream().getSession().send(creativeDropPacket); + } + break; + } + } + return; + } + + InventoryActionTranslator.translate(this, session, inventory, actions); + } + @Override public void prepareInventory(GeyserSession session, Inventory inventory) { } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index 84426eaa..5c99b012 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -26,37 +26,10 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.ItemData; -import com.nukkitx.protocol.bedrock.packet.*; -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.updater.ChestInventoryUpdater; public class SingleChestInventoryTranslator extends BlockInventoryTranslator { public SingleChestInventoryTranslator(int size) { - super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER); - } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - //need to pad empty slots for 1x9 and 2x9 - ItemData[] bedrockItems = new ItemData[27]; - for (int i = 0; i < bedrockItems.length; i++) { - if (i <= this.size) { - bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); - } else { - bedrockItems[i] = ItemData.AIR; - } - } - InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); - contentPacket.setContents(bedrockItems); - session.getUpstream().sendPacket(contentPacket); - - Inventory playerInventory = session.getInventory(); - for (int i = 0; i < 36; i++) { - playerInventory.setItem(i + 9, inventory.getItem(i + this.size)); - } - TranslatorsInit.getInventoryTranslators().get(playerInventory.getWindowType()).updateInventory(session, playerInventory); + super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, new ChestInventoryUpdater(27)); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java index b5657af4..045adbd3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java new file mode 100644 index 00000000..1fdfa364 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.action; + +import com.github.steveice10.mc.protocol.data.game.window.ClickItemParam; +import com.github.steveice10.mc.protocol.data.game.window.WindowActionParam; +import lombok.AllArgsConstructor; + +@AllArgsConstructor +enum Click { + LEFT(ClickItemParam.LEFT_CLICK), + RIGHT(ClickItemParam.RIGHT_CLICK); + + public final WindowActionParam actionParam; +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java new file mode 100644 index 00000000..3abdd284 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.action; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.window.WindowAction; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.inventory.PlayerInventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.utils.InventoryUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +class ClickPlan { + private final List plan = new ArrayList<>(); + + public void add(Click click, int slot) { + plan.add(new ClickAction(click, slot)); + } + + public void execute(GeyserSession session, InventoryTranslator translator, Inventory inventory, boolean refresh) { + PlayerInventory playerInventory = session.getInventory(); + ListIterator planIter = plan.listIterator(); + while (planIter.hasNext()) { + final ClickAction action = planIter.next(); + final ItemStack cursorItem = playerInventory.getCursor(); + final ItemStack clickedItem = inventory.getItem(action.slot); + final short actionId = (short) inventory.getTransactionId().getAndIncrement(); + + //TODO: stop relying on refreshing the inventory for crafting to work properly + if (translator.getSlotType(action.slot) != SlotType.NORMAL) + refresh = true; + + ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(), + actionId, action.slot, !planIter.hasNext() && refresh ? InventoryUtils.REFRESH_ITEM : InventoryUtils.fixStack(clickedItem), + WindowAction.CLICK_ITEM, action.click.actionParam); + + if (translator.getSlotType(action.slot) == SlotType.OUTPUT) { + if (cursorItem == null && clickedItem != null) { + playerInventory.setCursor(clickedItem); + } else if (InventoryUtils.canStack(cursorItem, clickedItem)) { + playerInventory.setCursor(new ItemStack(cursorItem.getId(), + cursorItem.getAmount() + clickedItem.getAmount(), cursorItem.getNbt())); + } + } else { + switch (action.click) { + case LEFT: + if (!InventoryUtils.canStack(cursorItem, clickedItem)) { + playerInventory.setCursor(clickedItem); + inventory.setItem(action.slot, cursorItem); + } else { + playerInventory.setCursor(null); + inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), + clickedItem.getAmount() + cursorItem.getAmount(), clickedItem.getNbt())); + } + break; + case RIGHT: + if (cursorItem == null && clickedItem != null) { + ItemStack halfItem = new ItemStack(clickedItem.getId(), + clickedItem.getAmount() / 2, clickedItem.getNbt()); + inventory.setItem(action.slot, halfItem); + playerInventory.setCursor(new ItemStack(clickedItem.getId(), + clickedItem.getAmount() - halfItem.getAmount(), clickedItem.getNbt())); + } else if (cursorItem != null && clickedItem == null) { + playerInventory.setCursor(new ItemStack(cursorItem.getId(), + cursorItem.getAmount() - 1, cursorItem.getNbt())); + inventory.setItem(action.slot, new ItemStack(cursorItem.getId(), + 1, cursorItem.getNbt())); + } else if (InventoryUtils.canStack(cursorItem, clickedItem)) { + playerInventory.setCursor(new ItemStack(cursorItem.getId(), + cursorItem.getAmount() - 1, cursorItem.getNbt())); + inventory.setItem(action.slot, new ItemStack(clickedItem.getId(), + clickedItem.getAmount() + 1, clickedItem.getNbt())); + } + break; + } + } + session.getDownstream().getSession().send(clickPacket); + session.getDownstream().getSession().send(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true)); + } + + /*if (refresh) { + translator.updateInventory(session, inventory); + InventoryUtils.updateCursor(session); + }*/ + } + + private static class ClickAction { + final Click click; + final int slot; + ClickAction(Click click, int slot) { + this.click = click; + this.slot = slot; + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionTranslator.java new file mode 100644 index 00000000..586c2c02 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionTranslator.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.action; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; +import com.github.steveice10.mc.protocol.data.game.window.*; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; +import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventorySource; +import com.nukkitx.protocol.bedrock.data.ItemData; +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 org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.utils.InventoryUtils; + +import java.util.*; + +public class InventoryActionTranslator { + public static void translate(InventoryTranslator translator, GeyserSession session, Inventory inventory, List actions) { + if (actions.size() != 2) + return; + + InventoryAction worldAction = null; + InventoryAction cursorAction = null; + InventoryAction containerAction = null; + boolean refresh = false; + for (InventoryAction action : actions) { + if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT || action.getSource().getContainerId() == ContainerId.CRAFTING_RESULT) { + return; + } else if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) { + worldAction = action; + } else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) { + cursorAction = action; + ItemData translatedCursor = TranslatorsInit.getItemTranslator().translateToBedrock(session.getInventory().getCursor()); + if (!translatedCursor.equals(action.getFromItem())) { + refresh = true; + } + } else { + containerAction = action; + ItemData translatedItem = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(translator.bedrockSlotToJava(action))); + if (!translatedItem.equals(action.getFromItem())) { + refresh = true; + } + } + } + + final int craftSlot = session.getCraftSlot(); + session.setCraftSlot(0); + + if (worldAction != null) { + InventoryAction sourceAction; + if (cursorAction != null) { + sourceAction = cursorAction; + } else { + sourceAction = containerAction; + } + + if (sourceAction != null) { + if (worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { + //quick dropping from hotbar? + if (session.getInventoryCache().getOpenInventory() == null && sourceAction.getSource().getContainerId() == ContainerId.INVENTORY) { + int heldSlot = session.getInventory().getHeldItemSlot(); + if (sourceAction.getSlot() == heldSlot) { + ClientPlayerActionPacket actionPacket = new ClientPlayerActionPacket( + sourceAction.getToItem().getCount() == 0 ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM, + new Position(0, 0, 0), BlockFace.DOWN); + session.getDownstream().getSession().send(actionPacket); + ItemStack item = session.getInventory().getItem(heldSlot); + if (item != null) { + session.getInventory().setItem(heldSlot, new ItemStack(item.getId(), item.getAmount() - 1, item.getNbt())); + } + return; + } + } + int dropAmount = sourceAction.getFromItem().getCount() - sourceAction.getToItem().getCount(); + if (sourceAction != cursorAction) { //dropping directly from inventory + int javaSlot = translator.bedrockSlotToJava(sourceAction); + if (dropAmount == sourceAction.getFromItem().getCount()) { + ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), + inventory.getTransactionId().getAndIncrement(), + javaSlot, null, WindowAction.DROP_ITEM, + DropItemParam.DROP_SELECTED_STACK); + session.getDownstream().getSession().send(dropPacket); + } else { + for (int i = 0; i < dropAmount; i++) { + ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), + inventory.getTransactionId().getAndIncrement(), + javaSlot, null, WindowAction.DROP_ITEM, + DropItemParam.DROP_FROM_SELECTED); + session.getDownstream().getSession().send(dropPacket); + } + } + ItemStack item = session.getInventory().getItem(javaSlot); + if (item != null) { + session.getInventory().setItem(javaSlot, new ItemStack(item.getId(), item.getAmount() - dropAmount, item.getNbt())); + } + return; + } else { //clicking outside of inventory + ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(), + -999, null, WindowAction.CLICK_ITEM, + dropAmount > 1 ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK); + session.getDownstream().getSession().send(dropPacket); + ItemStack cursor = session.getInventory().getCursor(); + if (cursor != null) { + session.getInventory().setCursor(new ItemStack(cursor.getId(), dropAmount > 1 ? 0 : cursor.getAmount() - 1, cursor.getNbt())); + } + return; + } + } + } + } else if (cursorAction != null && containerAction != null) { + //left/right click + ClickPlan plan = new ClickPlan(); + int javaSlot = translator.bedrockSlotToJava(containerAction); + if (cursorAction.getFromItem().equals(containerAction.getToItem()) + && containerAction.getFromItem().equals(cursorAction.getToItem()) + && !InventoryUtils.canStack(cursorAction.getFromItem(), containerAction.getFromItem())) { //simple swap + plan.add(Click.LEFT, javaSlot); + } else if (cursorAction.getFromItem().getCount() > cursorAction.getToItem().getCount()) { //release + if (cursorAction.getToItem().getCount() == 0) { + plan.add(Click.LEFT, javaSlot); + } else { + int difference = cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); + for (int i = 0; i < difference; i++) { + plan.add(Click.RIGHT, javaSlot); + } + } + } else { //pickup + if (cursorAction.getFromItem().getCount() == 0) { + if (containerAction.getToItem().getCount() == 0) { //pickup all + plan.add(Click.LEFT, javaSlot); + } else { //pickup some + if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT + || containerAction.getToItem().getCount() == containerAction.getFromItem().getCount() / 2) { //right click + plan.add(Click.RIGHT, javaSlot); + } else { + plan.add(Click.LEFT, javaSlot); + int difference = containerAction.getFromItem().getCount() - cursorAction.getToItem().getCount(); + for (int i = 0; i < difference; i++) { + plan.add(Click.RIGHT, javaSlot); + } + } + } + } else { //pickup into non-empty cursor + if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT) { + if (containerAction.getToItem().getCount() == 0) { + plan.add(Click.LEFT, javaSlot); + } else { + ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), + inventory.getTransactionId().getAndIncrement(), + javaSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM, + ShiftClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(shiftClickPacket); + translator.updateInventory(session, inventory); + return; + } + } else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) { + plan.add(Click.LEFT, javaSlot); + } else { + int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot)); + if (cursorSlot != -1) { + plan.add(Click.LEFT, cursorSlot); + } else { + translator.updateInventory(session, inventory); + return; + } + plan.add(Click.LEFT, javaSlot); + int difference = cursorAction.getToItem().getCount() - cursorAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + plan.add(Click.RIGHT, cursorSlot); + } + plan.add(Click.LEFT, javaSlot); + plan.add(Click.LEFT, cursorSlot); + } + } + } + plan.execute(session, translator, inventory, refresh); + return; + } else { + ClickPlan plan = new ClickPlan(); + InventoryAction fromAction; + InventoryAction toAction; + if (actions.get(0).getFromItem().getCount() >= actions.get(0).getToItem().getCount()) { + fromAction = actions.get(0); + toAction = actions.get(1); + } else { + fromAction = actions.get(1); + toAction = actions.get(0); + } + int fromSlot = translator.bedrockSlotToJava(fromAction); + int toSlot = translator.bedrockSlotToJava(toAction); + + if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) { + if ((craftSlot != 0 && craftSlot != -2) && (inventory.getItem(toSlot) == null + || InventoryUtils.canStack(session.getInventory().getCursor(), inventory.getItem(toSlot)))) { + if (fromAction.getToItem().getCount() == 0) { + refresh = true; + plan.add(Click.LEFT, toSlot); + if (craftSlot != -1) { + plan.add(Click.LEFT, craftSlot); + } + } else { + int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + plan.add(Click.RIGHT, toSlot); + } + session.setCraftSlot(craftSlot); + } + plan.execute(session, translator, inventory, refresh); + return; + } else { + session.setCraftSlot(-2); + } + } + + int cursorSlot = -1; + if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot + cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot)); + if (cursorSlot != -1) { + plan.add(Click.LEFT, cursorSlot); + } else { + translator.updateInventory(session, inventory); + return; + } + } + if ((fromAction.getFromItem().equals(toAction.getToItem()) && !InventoryUtils.canStack(fromAction.getFromItem(), toAction.getFromItem())) + || fromAction.getToItem().getId() == 0) { //slot swap + plan.add(Click.LEFT, fromSlot); + plan.add(Click.LEFT, toSlot); + if (fromAction.getToItem().getId() != 0) { + plan.add(Click.LEFT, fromSlot); + } + } else if (InventoryUtils.canStack(fromAction.getFromItem(), toAction.getToItem())) { //partial item move + if (translator.getSlotType(fromSlot) == SlotType.FURNACE_OUTPUT) { + ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(), + inventory.getTransactionId().getAndIncrement(), + fromSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM, + ShiftClickItemParam.LEFT_CLICK); + session.getDownstream().getSession().send(shiftClickPacket); + translator.updateInventory(session, inventory); + return; + } else if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) { + session.setCraftSlot(cursorSlot); + plan.add(Click.LEFT, fromSlot); + int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + plan.add(Click.RIGHT, toSlot); + } + //client will send additional packets later to finish transferring crafting output + //translator will know how to handle this using the craftSlot variable + } else { + plan.add(Click.LEFT, fromSlot); + int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount(); + for (int i = 0; i < difference; i++) { + plan.add(Click.RIGHT, toSlot); + } + plan.add(Click.LEFT, fromSlot); + } + } + if (cursorSlot != -1) { + plan.add(Click.LEFT, cursorSlot); + } + plan.execute(session, translator, inventory, refresh); + return; + } + + translator.updateInventory(session, inventory); + InventoryUtils.updateCursor(session); + } + + private static int findTempSlot(Inventory inventory, ItemStack item, List slotBlacklist) { + /*try and find a slot that can temporarily store the given item + only look in the main inventory and hotbar + only slots that are empty or contain a different type of item are valid*/ + int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable slot (some servers disable it) + List itemBlacklist = new ArrayList<>(slotBlacklist.size() + 1); + itemBlacklist.add(item); + for (int slot : slotBlacklist) { + ItemStack blacklistItem = inventory.getItem(slot); + if (blacklistItem != null) + itemBlacklist.add(blacklistItem); + } + for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) { + ItemStack testItem = inventory.getItem(i); + boolean acceptable = true; + if (testItem != null) { + for (ItemStack blacklistItem : itemBlacklist) { + if (InventoryUtils.canStack(testItem, blacklistItem)) { + acceptable = false; + break; + } + } + } + if (acceptable && !slotBlacklist.contains(i)) + return i; + } + //could not find a viable temp slot + return -1; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java new file mode 100644 index 00000000..6c0db853 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.holder; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; +import lombok.AllArgsConstructor; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.block.BlockEntry; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +@AllArgsConstructor +public class BlockInventoryHolder extends InventoryHolder { + private final int blockId; + private final ContainerType containerType; + + @Override + public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + Vector3i position = session.getPlayerEntity().getPosition().toInt(); + position = position.add(Vector3i.UP); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(position); + blockPacket.setRuntimeId(blockId); + blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); + session.getUpstream().sendPacket(blockPacket); + inventory.setHolderPosition(position); + + CompoundTag tag = CompoundTag.builder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); + BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); + dataPacket.setData(tag); + dataPacket.setBlockPosition(position); + session.getUpstream().sendPacket(dataPacket); + } + + @Override + public void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) containerType.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.getUpstream().sendPacket(containerOpenPacket); + } + + @Override + public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + Vector3i holderPos = inventory.getHolderPosition(); + Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); + BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); + session.getUpstream().sendPacket(blockPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java new file mode 100644 index 00000000..5a9e736e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.holder; + +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; + +public abstract class InventoryHolder { + public abstract void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); + public abstract void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); + public abstract void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java new file mode 100644 index 00000000..4af1fba1 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.updater; + +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; +import lombok.AllArgsConstructor; +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; + +@AllArgsConstructor +public class ChestInventoryUpdater extends InventoryUpdater { + private final int paddedSize; + + @Override + public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + super.updateInventory(translator, session, inventory); + + ItemData[] bedrockItems = new ItemData[paddedSize]; + for (int i = 0; i < bedrockItems.length; i++) { + if (i <= translator.size) { + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); + } else { + bedrockItems[i] = ItemData.AIR; + } + } + + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(inventory.getId()); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + } + + @Override + public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) { + if (super.updateSlot(translator, session, inventory, javaSlot)) + return true; + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(inventory.getId()); + slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + session.getUpstream().sendPacket(slotPacket); + return true; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java new file mode 100644 index 00000000..7169311e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.updater; + +import com.nukkitx.protocol.bedrock.data.ItemData; +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.network.translators.inventory.InventoryTranslator; + +public class ContainerInventoryUpdater extends InventoryUpdater { + @Override + public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + super.updateInventory(translator, session, inventory); + + ItemData[] bedrockItems = new ItemData[translator.size]; + for (int i = 0; i < bedrockItems.length; i++) { + bedrockItems[translator.javaSlotToBedrock(i)] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i)); + } + + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(inventory.getId()); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + } + + @Override + public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) { + if (super.updateSlot(translator, session, inventory, javaSlot)) + return true; + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(inventory.getId()); + slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + session.getUpstream().sendPacket(slotPacket); + return true; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java new file mode 100644 index 00000000..3df8d766 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.updater; + +import com.nukkitx.protocol.bedrock.data.ContainerId; +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.network.translators.inventory.InventoryTranslator; + +public class CursorInventoryUpdater extends InventoryUpdater { + @Override + public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + super.updateInventory(translator, session, inventory); + + for (int i = 0; i < translator.size; i++) { + final int bedrockSlot = translator.javaSlotToBedrock(i); + if (bedrockSlot == 50) + continue; + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.CURSOR); + slotPacket.setInventorySlot(bedrockSlot); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i))); + session.getUpstream().sendPacket(slotPacket); + } + } + + @Override + public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) { + if (super.updateSlot(translator, session, inventory, javaSlot)) + return true; + + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.CURSOR); + slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + session.getUpstream().sendPacket(slotPacket); + return true; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java new file mode 100644 index 00000000..e5b6f4c5 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.inventory.updater; + +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ItemData; +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.network.translators.inventory.InventoryTranslator; + +public abstract class InventoryUpdater { + public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + ItemData[] bedrockItems = new ItemData[36]; + for (int i = 0; i < 36; i++) { + final int offset = i < 9 ? 27 : -9; + bedrockItems[i] = TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(translator.size + i + offset)); + } + InventoryContentPacket contentPacket = new InventoryContentPacket(); + contentPacket.setContainerId(ContainerId.INVENTORY); + contentPacket.setContents(bedrockItems); + session.getUpstream().sendPacket(contentPacket); + } + + public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) { + if (javaSlot >= translator.size) { + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.INVENTORY); + slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + session.getUpstream().sendPacket(slotPacket); + return true; + } + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java index 596ef215..c5c152a2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal 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 index ed61e491..aaf00169 100644 --- 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 @@ -74,9 +74,8 @@ public class ItemTranslator { } public ItemData translateToBedrock(ItemStack stack) { - // Most likely dirt if null if (stack == null) { - return ItemData.of(3, (short)0, 0); + return ItemData.AIR; } ItemEntry bedrockItem = getItem(stack); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java index ca5cd5c0..f711d3ea 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 9015fc28..9399d1dd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -49,8 +49,10 @@ import java.util.*; import java.util.stream.Collectors; public class JavaDeclareRecipesTranslator extends PacketTranslator { - - private final int[] brewingIngredients = new int[]{372, 331, 348, 376, 289, 437, 353, 414, 382, 375, 462, 378, 396, 377, 370, 469, 470}; + private static final Collection POTION_MIXES = + Arrays.stream(new int[]{372, 331, 348, 376, 289, 437, 353, 414, 382, 375, 462, 378, 396, 377, 370, 469, 470}) + .mapToObj(ingredient -> new PotionMixData(0, ingredient, 0)) + .collect(Collectors.toList()); @Override public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) { @@ -61,6 +63,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerChangeHeldItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerChangeHeldItemTranslator.java new file mode 100644 index 00000000..90042e32 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerChangeHeldItemTranslator.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.java.entity.player; + +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerChangeHeldItemPacket; +import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; + +public class JavaPlayerChangeHeldItemTranslator extends PacketTranslator { + + @Override + public void translate(ServerPlayerChangeHeldItemPacket packet, GeyserSession session) { + PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket(); + hotbarPacket.setContainerId(0); + hotbarPacket.setSelectedHotbarSlot(packet.getSlot()); + hotbarPacket.setSelectHotbarSlot(true); + session.getUpstream().sendPacket(hotbarPacket); + + session.getInventory().setHeldItemSlot(packet.getSlot()); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index dcb0c9fe..cb532e60 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java index 09718dbd..10c85de4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 43f3b6d1..4190ac5a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -80,7 +80,7 @@ public class JavaOpenWindowTranslator extends PacketTranslator InventoryUtils.openInventory(session, newInventory), 350, TimeUnit.MILLISECONDS); + Geyser.getGeneralThreadPool().schedule(() -> InventoryUtils.openInventory(session, newInventory), 500, TimeUnit.MILLISECONDS); return; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 9443f86b..21c7217a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -31,6 +31,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.utils.InventoryUtils; import java.util.Objects; @@ -43,8 +44,9 @@ public class JavaSetSlotTranslator extends PacketTranslator return; if (session.getCraftSlot() != 0) return; - //bedrock client is bugged when changing the cursor. do not send slot update packet + session.getInventory().setCursor(packet.getItem()); + InventoryUtils.updateCursor(session); return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java index c8e04d37..d7e2292e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index 60779f52..f55f28bb 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -25,6 +25,11 @@ package org.geysermc.connector.utils; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.api.Geyser; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -32,9 +37,11 @@ import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import java.util.Objects; import java.util.concurrent.TimeUnit; public class InventoryUtils { + public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag("")); //TODO: stop using this public static void openInventory(GeyserSession session, Inventory inventory) { InventoryTranslator translator = TranslatorsInit.getInventoryTranslators().get(inventory.getWindowType()); @@ -71,4 +78,31 @@ public class InventoryUtils { session.setCraftSlot(0); session.getInventory().setCursor(null); } + + public static void updateCursor(GeyserSession session) { + InventorySlotPacket cursorPacket = new InventorySlotPacket(); + cursorPacket.setContainerId(ContainerId.CURSOR); + cursorPacket.setInventorySlot(0); + cursorPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(session.getInventory().getCursor())); + session.getUpstream().sendPacket(cursorPacket); + } + + //NPE if compound tag is null + public static ItemStack fixStack(ItemStack stack) { + if (stack == null || stack.getId() == 0) + return null; + return new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() == null ? new CompoundTag("") : stack.getNbt()); + } + + public static boolean canStack(ItemStack item1, ItemStack item2) { + if (item1 == null || item2 == null) + return false; + return item1.getId() == item2.getId() && Objects.equals(item1.getNbt(), item2.getNbt()); + } + + public static boolean canStack(ItemData item1, ItemData item2) { + if (item1 == null || item2 == null) + return false; + return item1.equals(item2, false, true, true); + } } 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 cc2f03b5..00bc86c2 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -25,6 +25,7 @@ package org.geysermc.connector.utils; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.nbt.stream.NBTInputStream; @@ -150,31 +151,31 @@ public class Toolbox { InputStream creativeItemStream = Toolbox.class.getClassLoader().getResourceAsStream("bedrock/creative_items.json"); ObjectMapper creativeItemMapper = new ObjectMapper(); - List> creativeItemEntries = new ArrayList<>(); + JsonNode creativeItemEntries; try { - creativeItemEntries = (ArrayList>) creativeItemMapper.readValue(creativeItemStream, HashMap.class).get("items"); + creativeItemEntries = creativeItemMapper.readTree(creativeItemStream).get("items"); } catch (Exception e) { - e.printStackTrace(); + throw new AssertionError("Unable to load creative items", e); } List creativeItems = new ArrayList<>(); - for (Map map : creativeItemEntries) { + for (JsonNode itemNode : creativeItemEntries) { short damage = 0; - if (map.containsKey("damage")) { - damage = (short)(int) map.get("damage"); + if (itemNode.has("damage")) { + damage = itemNode.get("damage").numberValue().shortValue(); } - if (map.containsKey("nbt_b64")) { - byte[] bytes = Base64.getDecoder().decode((String) map.get("nbt_b64")); + if (itemNode.has("nbt_b64")) { + byte[] bytes = Base64.getDecoder().decode(itemNode.get("nbt_b64").asText()); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); try { com.nukkitx.nbt.tag.CompoundTag tag = (com.nukkitx.nbt.tag.CompoundTag) NbtUtils.createReaderLE(bais).readTag(); - creativeItems.add(ItemData.of((int) map.get("id"), damage, 1, tag)); + creativeItems.add(ItemData.of(itemNode.get("id").asInt(), damage, 1, tag)); } catch (IOException e) { e.printStackTrace(); } } else { - creativeItems.add(ItemData.of((int) map.get("id"), damage, 1)); + creativeItems.add(ItemData.of(itemNode.get("id").asInt(), damage, 1)); } } From 3d61b3ce280cf1ee3e207d2eeb5c05638bef2440 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 30 Jan 2020 23:15:18 -0900 Subject: [PATCH 30/32] Bump OpenNBT lib to 1.4-SNAPSHOT This fixes the NPE when sending an ItemStack with a null NBT tag. This also fixes some item movement bugs on pure vanilla servers. --- connector/pom.xml | 2 +- .../translators/inventory/PlayerInventoryTranslator.java | 4 ++-- .../network/translators/inventory/action/ClickPlan.java | 2 +- .../java/org/geysermc/connector/utils/InventoryUtils.java | 7 ------- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index 9de1e3e7..c6131159 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -79,7 +79,7 @@ com.github.steveice10 opennbt - 1.3-SNAPSHOT + 1.4-SNAPSHOT compile diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index acad709f..31d898c2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -182,7 +182,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } else { javaItem = TranslatorsInit.getItemTranslator().translateToJava(action.getToItem()); } - ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, InventoryUtils.fixStack(javaItem)); + ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem); session.getDownstream().getSession().send(creativePacket); inventory.setItem(javaSlot, javaItem); break; @@ -195,7 +195,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION && action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { javaItem = TranslatorsInit.getItemTranslator().translateToJava(action.getToItem()); - ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, InventoryUtils.fixStack(javaItem)); + ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem); session.getDownstream().getSession().send(creativeDropPacket); } break; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java index 3abdd284..cdc42f96 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java @@ -61,7 +61,7 @@ class ClickPlan { refresh = true; ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(), - actionId, action.slot, !planIter.hasNext() && refresh ? InventoryUtils.REFRESH_ITEM : InventoryUtils.fixStack(clickedItem), + actionId, action.slot, !planIter.hasNext() && refresh ? InventoryUtils.REFRESH_ITEM : clickedItem, WindowAction.CLICK_ITEM, action.click.actionParam); if (translator.getSlotType(action.slot) == SlotType.OUTPUT) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index f55f28bb..0fb9e0fc 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -87,13 +87,6 @@ public class InventoryUtils { session.getUpstream().sendPacket(cursorPacket); } - //NPE if compound tag is null - public static ItemStack fixStack(ItemStack stack) { - if (stack == null || stack.getId() == 0) - return null; - return new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() == null ? new CompoundTag("") : stack.getNbt()); - } - public static boolean canStack(ItemStack item1, ItemStack item2) { if (item1 == null || item2 == null) return false; From bf1835e69101d1e49587f0ebb7ef6c65164fe688 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 12 Feb 2020 22:29:44 -0900 Subject: [PATCH 31/32] Fix Block IDs Quick fix. Might have a different method for getting block IDs in the future --- .../network/translators/block/BlockTranslator.java | 12 ++++++++++-- .../inventory/BlockInventoryTranslator.java | 6 ++++-- .../inventory/DoubleChestInventoryTranslator.java | 13 +++++++------ .../inventory/holder/BlockInventoryHolder.java | 7 ++++--- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/block/BlockTranslator.java index f4753b8d..970808b6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/block/BlockTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/block/BlockTranslator.java @@ -48,6 +48,7 @@ public class BlockTranslator { private static final Int2IntMap JAVA_TO_BEDROCK_BLOCK_MAP = new Int2IntOpenHashMap(); private static final Int2ObjectMap BEDROCK_TO_JAVA_BLOCK_MAP = new Int2ObjectOpenHashMap<>(); + private static final Map JAVA_ID_BLOCK_MAP = new HashMap<>(); private static final IntSet WATERLOGGED = new IntOpenHashSet(); private static final int BLOCK_STATE_VERSION = 17760256; @@ -89,18 +90,21 @@ public class BlockTranslator { javaRuntimeId++; Map.Entry entry = blocksIterator.next(); String javaId = entry.getKey(); + BlockState javaBlockState = new BlockState(javaRuntimeId); CompoundTag blockTag = buildBedrockState(entry.getValue()); + JAVA_ID_BLOCK_MAP.put(javaId, javaBlockState); + if ("minecraft:water[level=0]".equals(javaId)) { waterRuntimeId = bedrockRuntimeId; } boolean waterlogged = entry.getValue().has("waterlogged") && entry.getValue().get("waterlogged").booleanValue(); if (waterlogged) { - BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, new BlockState(javaRuntimeId)); + BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, javaBlockState); WATERLOGGED.add(javaRuntimeId); } else { - BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, new BlockState(javaRuntimeId)); + BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaBlockState); } CompoundTag runtimeTag = blockStateMap.remove(blockTag); @@ -175,6 +179,10 @@ public class BlockTranslator { return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId); } + public static BlockState getJavaBlockState(String javaId) { + return JAVA_ID_BLOCK_MAP.get(javaId); + } + public static boolean isWaterlogged(BlockState state) { return WATERLOGGED.contains(state.getId()); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java index 32dfc2a6..5f6274f0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java @@ -25,10 +25,11 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.protocol.bedrock.data.ContainerType; 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.block.BlockTranslator; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; @@ -39,7 +40,8 @@ public class BlockInventoryTranslator extends BaseInventoryTranslator { public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { super(size); - final int blockId = TranslatorsInit.getBlockTranslator().getBlockEntry(javaBlockIdentifier).getBedrockRuntimeId(); + BlockState javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + int blockId = BlockTranslator.getBedrockBlockId(javaBlockState); this.holder = new BlockInventoryHolder(blockId, containerType); this.updater = updater; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index 07d3a414..c70a8995 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; @@ -34,8 +35,7 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; 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.block.BlockEntry; +import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; @@ -45,7 +45,8 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator { public DoubleChestInventoryTranslator(int size) { super(size); - this.blockId = TranslatorsInit.getBlockTranslator().getBlockEntry("minecraft:chest[facing=north,type=single,waterlogged=false]").getBedrockRuntimeId(); + BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); + this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState); this.updater = new ChestInventoryUpdater(54); } @@ -111,11 +112,11 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator { public void closeInventory(GeyserSession session, Inventory inventory) { Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + BlockState realBlock = session.getChunkCache().getBlockAt(pos); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); + blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock)); session.getUpstream().sendPacket(blockPacket); holderPos = holderPos.add(Vector3i.UNIT_X); @@ -124,7 +125,7 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); + blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock)); session.getUpstream().sendPacket(blockPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 6c0db853..a9b0d4ad 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.inventory.holder; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ContainerType; @@ -35,7 +36,7 @@ import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.block.BlockEntry; +import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; @AllArgsConstructor @@ -80,11 +81,11 @@ public class BlockInventoryHolder extends InventoryHolder { public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - BlockEntry realBlock = session.getChunkCache().getBlockAt(pos); + BlockState realBlock = session.getChunkCache().getBlockAt(pos); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(realBlock.getBedrockRuntimeId()); + blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock)); session.getUpstream().sendPacket(blockPacket); } } From bfca25bbe3534f1c58bc05465cf27d42b1002251 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 25 Feb 2020 22:31:55 -0900 Subject: [PATCH 32/32] Fix compile errors --- .../inventory/AnvilInventoryTranslator.java | 14 +++++----- .../inventory/BaseInventoryTranslator.java | 10 +++---- .../inventory/BrewingInventoryTranslator.java | 4 +-- .../CraftingInventoryTranslator.java | 10 +++---- .../inventory/InventoryTranslator.java | 6 ++--- .../inventory/PlayerInventoryTranslator.java | 26 +++++++++---------- ...ava => InventoryActionDataTranslator.java} | 20 +++++++------- .../updater/ChestInventoryUpdater.java | 4 +-- .../updater/ContainerInventoryUpdater.java | 4 +-- .../updater/CursorInventoryUpdater.java | 8 +++--- .../inventory/updater/InventoryUpdater.java | 4 +-- .../translators/item/ItemTranslator.java | 4 +-- .../connector/utils/InventoryUtils.java | 4 +-- .../connector/world/chunk/ChunkPosition.java | 17 ------------ 14 files changed, 58 insertions(+), 77 deletions(-) rename connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/{InventoryActionTranslator.java => InventoryActionDataTranslator.java} (97%) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java index 39575188..60700ba2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java @@ -28,7 +28,7 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -42,7 +42,7 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { } @Override - public int bedrockSlotToJava(InventoryAction action) { + public int bedrockSlotToJava(InventoryActionData action) { if (action.getSource().getContainerId() == ContainerId.CURSOR) { switch (action.getSlot()) { case 1: @@ -77,10 +77,10 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - InventoryAction anvilResult = null; - InventoryAction anvilInput = null; - for (InventoryAction action : actions) { + public void translateActions(GeyserSession session, Inventory inventory, List actions) { + InventoryActionData anvilResult = null; + InventoryActionData anvilInput = null; + for (InventoryActionData action : actions) { if (action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL) { //useless packet return; @@ -100,7 +100,7 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { String rename; com.nukkitx.nbt.tag.CompoundTag tag = itemName.getTag(); if (tag != null) { - rename = tag.getAsCompound("display").getAsString("Name"); + rename = tag.getCompound("display").getString("Name"); } else { rename = ""; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java index d64c0e78..5deb0370 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java @@ -26,10 +26,10 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.protocol.bedrock.data.ContainerId; -import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.action.InventoryActionTranslator; +import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator; import java.util.List; @@ -44,7 +44,7 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{ } @Override - public int bedrockSlotToJava(InventoryAction action) { + public int bedrockSlotToJava(InventoryActionData action) { int slotnum = action.getSlot(); if (action.getSource().getContainerId() == ContainerId.INVENTORY) { //hotbar @@ -76,7 +76,7 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{ } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - InventoryActionTranslator.translate(this, session, inventory, actions); + public void translateActions(GeyserSession session, Inventory inventory, List actions) { + InventoryActionDataTranslator.translate(this, session, inventory, actions); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java index c5f67a03..bd143698 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java @@ -26,7 +26,7 @@ package org.geysermc.connector.network.translators.inventory; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -66,7 +66,7 @@ public class BrewingInventoryTranslator extends BlockInventoryTranslator { } @Override - public int bedrockSlotToJava(InventoryAction action) { + public int bedrockSlotToJava(InventoryActionData action) { final int slot = super.bedrockSlotToJava(action); switch (slot) { case 0: diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java index fe70609f..92a1d90e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java @@ -28,13 +28,11 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ContainerType; -import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import com.nukkitx.protocol.bedrock.data.InventorySource; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -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.network.translators.inventory.updater.CursorInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; import org.geysermc.connector.utils.InventoryUtils; @@ -80,7 +78,7 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator { } @Override - public int bedrockSlotToJava(InventoryAction action) { + public int bedrockSlotToJava(InventoryActionData action) { if (action.getSource().getContainerId() == ContainerId.CURSOR) { int slotnum = action.getSlot(); if (slotnum >= 32 && 42 >= slotnum) { @@ -105,9 +103,9 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator { } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { + public void translateActions(GeyserSession session, Inventory inventory, List actions) { if (session.getGameMode() == GameMode.CREATIVE) { - for (InventoryAction action : actions) { + for (InventoryActionData action : actions) { if (action.getSource().getType() == InventorySource.Type.CREATIVE) { updateInventory(session, inventory); InventoryUtils.updateCursor(session); 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 index 7baef61a..2a5afb8c 100644 --- 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 @@ -25,7 +25,7 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -42,8 +42,8 @@ public abstract class InventoryTranslator { public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value); public abstract void updateInventory(GeyserSession session, Inventory inventory); public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot); - public abstract int bedrockSlotToJava(InventoryAction action); + public abstract int bedrockSlotToJava(InventoryActionData action); public abstract int javaSlotToBedrock(int slot); public abstract SlotType getSlotType(int javaSlot); - public abstract void translateActions(GeyserSession session, Inventory inventory, List actions); + public abstract void translateActions(GeyserSession session, Inventory inventory, List actions); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index 31d898c2..555e80a0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -34,7 +34,7 @@ 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.network.translators.inventory.action.InventoryActionTranslator; +import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator; import org.geysermc.connector.utils.InventoryUtils; import java.util.List; @@ -50,8 +50,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { for (int i = 1; i < 5; i++) { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.CURSOR); - slotPacket.setInventorySlot(i + 27); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i))); + slotPacket.setSlot(i + 27); + slotPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i))); session.getUpstream().sendPacket(slotPacket); } @@ -93,18 +93,18 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (slot >= 9) { slotPacket.setContainerId(ContainerId.INVENTORY); if (slot >= 36) { - slotPacket.setInventorySlot(slot - 36); + slotPacket.setSlot(slot - 36); } else { - slotPacket.setInventorySlot(slot); + slotPacket.setSlot(slot); } } else if (slot >= 5) { slotPacket.setContainerId(ContainerId.ARMOR); - slotPacket.setInventorySlot(slot - 5); + slotPacket.setSlot(slot - 5); } else { slotPacket.setContainerId(ContainerId.CURSOR); - slotPacket.setInventorySlot(slot + 27); + slotPacket.setSlot(slot + 27); } - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(slot))); + slotPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(slot))); session.getUpstream().sendPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); @@ -115,7 +115,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public int bedrockSlotToJava(InventoryAction action) { + public int bedrockSlotToJava(InventoryActionData action) { int slotnum = action.getSlot(); switch (action.getSource().getContainerId()) { case ContainerId.INVENTORY: @@ -159,10 +159,10 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { + public void translateActions(GeyserSession session, Inventory inventory, List actions) { if (session.getGameMode() == GameMode.CREATIVE) { //crafting grid is not visible in creative mode in java edition - for (InventoryAction action : actions) { + for (InventoryActionData action : actions) { if (action.getSource().getContainerId() == ContainerId.CURSOR && (action.getSlot() >= 28 && 31 >= action.getSlot())) { updateInventory(session, inventory); InventoryUtils.updateCursor(session); @@ -171,7 +171,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } ItemStack javaItem; - for (InventoryAction action : actions) { + for (InventoryActionData action : actions) { switch (action.getSource().getContainerId()) { case ContainerId.INVENTORY: case ContainerId.ARMOR: @@ -204,7 +204,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { return; } - InventoryActionTranslator.translate(this, session, inventory, actions); + InventoryActionDataTranslator.translate(this, session, inventory, actions); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java similarity index 97% rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java index 586c2c02..a94b6242 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java @@ -33,7 +33,7 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; import com.nukkitx.protocol.bedrock.data.ContainerId; -import com.nukkitx.protocol.bedrock.data.InventoryAction; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import com.nukkitx.protocol.bedrock.data.InventorySource; import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.inventory.Inventory; @@ -45,16 +45,16 @@ import org.geysermc.connector.utils.InventoryUtils; import java.util.*; -public class InventoryActionTranslator { - public static void translate(InventoryTranslator translator, GeyserSession session, Inventory inventory, List actions) { +public class InventoryActionDataTranslator { + public static void translate(InventoryTranslator translator, GeyserSession session, Inventory inventory, List actions) { if (actions.size() != 2) return; - InventoryAction worldAction = null; - InventoryAction cursorAction = null; - InventoryAction containerAction = null; + InventoryActionData worldAction = null; + InventoryActionData cursorAction = null; + InventoryActionData containerAction = null; boolean refresh = false; - for (InventoryAction action : actions) { + for (InventoryActionData action : actions) { if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT || action.getSource().getContainerId() == ContainerId.CRAFTING_RESULT) { return; } else if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) { @@ -78,7 +78,7 @@ public class InventoryActionTranslator { session.setCraftSlot(0); if (worldAction != null) { - InventoryAction sourceAction; + InventoryActionData sourceAction; if (cursorAction != null) { sourceAction = cursorAction; } else { @@ -208,8 +208,8 @@ public class InventoryActionTranslator { return; } else { ClickPlan plan = new ClickPlan(); - InventoryAction fromAction; - InventoryAction toAction; + InventoryActionData fromAction; + InventoryActionData toAction; if (actions.get(0).getFromItem().getCount() >= actions.get(0).getToItem().getCount()) { fromAction = actions.get(0); toAction = actions.get(1); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java index 4af1fba1..ab45cdc4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java @@ -64,8 +64,8 @@ public class ChestInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); - slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java index 7169311e..3efe1cee 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java @@ -56,8 +56,8 @@ public class ContainerInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); - slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java index 3df8d766..13b8554b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java @@ -43,8 +43,8 @@ public class CursorInventoryUpdater extends InventoryUpdater { continue; InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.CURSOR); - slotPacket.setInventorySlot(bedrockSlot); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i))); + slotPacket.setSlot(bedrockSlot); + slotPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(i))); session.getUpstream().sendPacket(slotPacket); } } @@ -56,8 +56,8 @@ public class CursorInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.CURSOR); - slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java index e5b6f4c5..888b14b1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java @@ -51,8 +51,8 @@ public abstract class InventoryUpdater { if (javaSlot >= translator.size) { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.INVENTORY); - slotPacket.setInventorySlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); + slotPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } 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 index aaf00169..446b25db 100644 --- 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 @@ -189,13 +189,13 @@ public class ItemTranslator { continue; com.nukkitx.nbt.tag.CompoundTag tagValue = (com.nukkitx.nbt.tag.CompoundTag) value; - int bedrockId = tagValue.getAsShort("id", (short) -1); + int bedrockId = tagValue.getShort("id", (short) -1); Enchantment enchantment = Enchantment.getByBedrockId(bedrockId); if (enchantment != null) { CompoundTag javaTag = new CompoundTag(""); Map javaValue = javaTag.getValue(); javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); - javaValue.put("lvl", new IntTag("lvl", tagValue.getAsShort("lvl", (short) 1))); + javaValue.put("lvl", new IntTag("lvl", tagValue.getShort("lvl", (short) 1))); javaTag.setValue(javaValue); tags.add(javaTag); } else { diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index 0fb9e0fc..8eb407d0 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -82,8 +82,8 @@ public class InventoryUtils { public static void updateCursor(GeyserSession session) { InventorySlotPacket cursorPacket = new InventorySlotPacket(); cursorPacket.setContainerId(ContainerId.CURSOR); - cursorPacket.setInventorySlot(0); - cursorPacket.setSlot(TranslatorsInit.getItemTranslator().translateToBedrock(session.getInventory().getCursor())); + cursorPacket.setSlot(0); + cursorPacket.setItem(TranslatorsInit.getItemTranslator().translateToBedrock(session.getInventory().getCursor())); session.getUpstream().sendPacket(cursorPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java b/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java index a59b2031..26748dff 100644 --- a/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java +++ b/connector/src/main/java/org/geysermc/connector/world/chunk/ChunkPosition.java @@ -53,21 +53,4 @@ public class ChunkPosition { return new Position(chunkX, chunkY, chunkZ); } - - @Override - public boolean equals(Object obj) { - if (obj == this) - return true; - if (obj == null) - return false; - if (!(obj instanceof ChunkPosition)) - return false; - ChunkPosition other = (ChunkPosition)obj; - return x == other.x && z == other.z; - } - - @Override - public int hashCode() { - return Objects.hash(x, z); - } }