From 234c6542bbabf5a1314e883208af1e595c9e2e42 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 14 Jan 2021 19:45:59 -0900 Subject: [PATCH] Refactor creative request translator and fix bugs --- .../inventory/InventoryTranslator.java | 237 +--------------- .../PlayerInventoryTranslator.java | 255 ++++++++++++++++++ 2 files changed, 265 insertions(+), 227 deletions(-) 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 64f73ac54..b6f22dc61 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 @@ -217,79 +217,6 @@ public abstract class InventoryTranslator { if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? return rejectRequest(request); - } else if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { // TODO: does the Java server use this stuff all the time in creative? - // Creative acts a little differently because it just edits slots - boolean sourceIsCursor = isCursor(transferAction.getSource()); - boolean destIsCursor = isCursor(transferAction.getDestination()); - - GeyserItemStack sourceItem = sourceIsCursor ? session.getPlayerInventory().getCursor() : - inventory.getItem(sourceSlot); - GeyserItemStack newItem = sourceItem.copy(); - if (sourceIsCursor) { - GeyserItemStack destItem = inventory.getItem(destSlot); - if (destItem.getJavaId() == sourceItem.getJavaId()) { - // Combining items - int itemsLeftOver = destItem.getAmount() + transferAction.getCount(); - if (itemsLeftOver > MAX_ITEM_STACK_SIZE) { - // Items will remain in cursor because destination slot gets set to 64 - destItem.setAmount(MAX_ITEM_STACK_SIZE); - sourceItem.setAmount(itemsLeftOver - MAX_ITEM_STACK_SIZE); - } else { - // Cursor will be emptied - destItem.setAmount(itemsLeftOver); - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - destSlot, - destItem.getItemStack() - ); - session.sendDownstreamPacket(creativeActionPacket); - affectedSlots.add(destSlot); - break; - } - } else { - // Delete the source since we're moving it - inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - sourceSlot, - new ItemStack(0) - ); - session.sendDownstreamPacket(creativeActionPacket); - affectedSlots.add(sourceSlot); - } - // Update the item count with however much the client took - newItem.setAmount(transferAction.getCount()); - // Remove that amount from the existing item - sourceItem.setAmount(sourceItem.getAmount() - transferAction.getCount()); - if (sourceItem.isEmpty()) { - // Item is basically deleted - if (sourceIsCursor) { - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } else { - inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); - } - } - if (destIsCursor) { - session.getPlayerInventory().setCursor(newItem, session); - } else { - inventory.setItem(destSlot, newItem, session); - } - GeyserItemStack itemToUpdate = destIsCursor ? sourceItem : newItem; - // The Java server doesn't care about what's in the mouse in creative mode, so we just need to track - // which inventory slot the client modified - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - destIsCursor ? sourceSlot : destSlot, - itemToUpdate.isEmpty() ? new ItemStack(0) : itemToUpdate.getItemStack() - ); - session.sendDownstreamPacket(creativeActionPacket); - - if (!sourceIsCursor) { // Cursor is always added for us as an affected slot - affectedSlots.add(sourceSlot); - } - if (!destIsCursor) { - affectedSlots.add(destSlot); - } - } else if (isCursor(transferAction.getSource())) { //releasing cursor int sourceAmount = cursor.getAmount(); if (transferAction.getCount() == sourceAmount) { //release all @@ -359,35 +286,7 @@ public abstract class InventoryTranslator { if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) return rejectRequest(request); - if (session.getGameMode().equals(GameMode.CREATIVE) && inventory instanceof PlayerInventory) { - int destSlot = bedrockSlotToJava(swapAction.getDestination()); - GeyserItemStack oldSourceItem; - GeyserItemStack oldDestinationItem = inventory.getItem(destSlot); - if (isCursor(swapAction.getSource())) { - oldSourceItem = session.getPlayerInventory().getCursor(); - session.getPlayerInventory().setCursor(oldDestinationItem, session); - } else { - int sourceSlot = bedrockSlotToJava(swapAction.getSource()); - oldSourceItem = inventory.getItem(sourceSlot); - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - sourceSlot, - oldDestinationItem.isEmpty() ? new ItemStack(0) : oldDestinationItem.getItemStack() // isEmpty check... just in case - ); - session.sendDownstreamPacket(creativeActionPacket); - inventory.setItem(sourceSlot, oldDestinationItem, session); - } - if (isCursor(swapAction.getDestination())) { - session.getPlayerInventory().setCursor(oldSourceItem, session); - } else { - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - destSlot, - oldSourceItem.isEmpty() ? new ItemStack(0) : oldSourceItem.getItemStack() - ); - session.sendDownstreamPacket(creativeActionPacket); - inventory.setItem(destSlot, oldSourceItem, session); - } - - } else if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? + if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //??? return rejectRequest(request); } else if (isCursor(swapAction.getSource())) { //swap cursor int destSlot = bedrockSlotToJava(swapAction.getDestination()); @@ -425,29 +324,12 @@ public abstract class InventoryTranslator { return rejectRequest(request); if (isCursor(dropAction.getSource())) { //clicking outside of window - if (session.getGameMode() == GameMode.CREATIVE && inventory instanceof PlayerInventory) { - GeyserItemStack cursorItem = session.getPlayerInventory().getCursor(); - GeyserItemStack droppingItem = cursorItem.copy(); - // Subtract the cursor item by however much is being dropped - cursorItem.setAmount(cursorItem.getAmount() - dropAction.getCount()); - if (cursorItem.isEmpty()) { - // Cursor item no longer exists - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } - droppingItem.setAmount(dropAction.getCount()); - ClientCreativeInventoryActionPacket packet = new ClientCreativeInventoryActionPacket( - Click.OUTSIDE_SLOT, - droppingItem.getItemStack() - ); - session.sendDownstreamPacket(packet); - } else { - int sourceAmount = plan.getCursor().getAmount(); - if (dropAction.getCount() == sourceAmount) { //drop all - plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT); - } else { //drop some - for (int i = 0; i < dropAction.getCount(); i++) { - plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met - } + int sourceAmount = plan.getCursor().getAmount(); + if (dropAction.getCount() == sourceAmount) { //drop all + plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT); + } else { //drop some + for (int i = 0; i < dropAction.getCount(); i++) { + plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met } } } else { //dropping from inventory @@ -463,39 +345,6 @@ public abstract class InventoryTranslator { } break; } - case DESTROY: { - // Only called when a creative client wants to destroy an item... I think - Camotoy - DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; - if (!session.getGameMode().equals(GameMode.CREATIVE)) { - // If this happens, let's throw an error and figure out why. - return rejectRequest(request); - } - if (!isCursor(destroyAction.getSource())) { - // Item exists; let's remove it from the inventory - int javaSlot = bedrockSlotToJava(destroyAction.getSource()); - GeyserItemStack existingItem = inventory.getItem(javaSlot); - existingItem.setAmount(existingItem.getAmount() - destroyAction.getCount()); - ClientCreativeInventoryActionPacket destroyItemPacket; - if (existingItem.isEmpty()) { - destroyItemPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - new ItemStack(0) - ); - inventory.setItem(javaSlot, GeyserItemStack.EMPTY, session); - } else { - destroyItemPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - existingItem.getItemStack() - ); - } - session.sendDownstreamPacket(destroyItemPacket); - affectedSlots.add(javaSlot); - } else { - // Just sync up the item on our end, since the server doesn't care what's in our cursor - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); - } - break; - } // The following three tend to be called for UI inventories case CONSUME: { if (inventory instanceof CartographyContainer) { @@ -838,73 +687,7 @@ public abstract class InventoryTranslator { } public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { - int creativeId = 0; - CraftState craftState = CraftState.START; - for (StackRequestActionData action : request.getActions()) { - switch (action.getType()) { - case CRAFT_CREATIVE: { - CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; - if (craftState != CraftState.START) { - return rejectRequest(request); - } - craftState = CraftState.RECIPE_ID; - - creativeId = creativeAction.getCreativeItemNetworkId(); - break; - } - case CRAFT_RESULTS_DEPRECATED: { - CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; - if (craftState != CraftState.RECIPE_ID) { - return rejectRequest(request); - } - craftState = CraftState.DEPRECATED; - break; - } - case TAKE: - case PLACE: { - TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; - if (craftState != CraftState.DEPRECATED) { - return rejectRequest(request); - } - craftState = CraftState.TRANSFER; - - if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { - return rejectRequest(request); - } - // Reference the creative items list we send to the client to know what it's asking of us - ItemData creativeItem = ItemRegistry.CREATIVE_ITEMS[creativeId - 1]; - // Get the correct count - creativeItem = ItemData.of(creativeItem.getId(), creativeItem.getDamage(), transferAction.getCount(), creativeItem.getTag()); - ItemStack javaCreativeItem = ItemTranslator.translateToJava(creativeItem); - - if (isCursor(transferAction.getDestination())) { - session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem), session); - return acceptRequest(request, Collections.singletonList( - new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, - Collections.singletonList(makeItemEntry(0, session.getPlayerInventory().getCursor()))))); - } else { - int javaSlot = bedrockSlotToJava(transferAction.getDestination()); - GeyserItemStack existingItem = inventory.getItem(javaSlot); - if (existingItem.getJavaId() == javaCreativeItem.getId()) { - // Adding more to an existing item - existingItem.setAmount(existingItem.getAmount() + transferAction.getCount()); - javaCreativeItem = existingItem.getItemStack(); - } else { - inventory.setItem(javaSlot, GeyserItemStack.from(javaCreativeItem), session); - } - ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( - javaSlot, - javaCreativeItem - ); - session.sendDownstreamPacket(creativeActionPacket); - Set affectedSlots = Collections.singleton(javaSlot); - return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); - } - } - default: - return rejectRequest(request); - } - } + // Handled in PlayerInventoryTranslator return rejectRequest(request); } @@ -1040,11 +823,11 @@ public abstract class InventoryTranslator { return itemEntry; } - private static boolean isCursor(StackRequestSlotInfoData slotInfoData) { + protected static boolean isCursor(StackRequestSlotInfoData slotInfoData) { return slotInfoData.getContainer() == ContainerSlotType.CURSOR; } - private enum CraftState { + protected enum CraftState { START, RECIPE_ID, DEPRECATED, diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java index 51ff0f5d2..c5a2db1c8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java @@ -25,18 +25,26 @@ package org.geysermc.connector.network.translators.inventory.translators; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket; import com.nukkitx.protocol.bedrock.data.inventory.*; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import org.geysermc.connector.inventory.GeyserItemStack; 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.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; import org.geysermc.connector.utils.LanguageUtils; @@ -207,6 +215,253 @@ public class PlayerInventoryTranslator extends InventoryTranslator { super.translateRequests(session, inventory, requests); } + @Override + public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + if (session.getGameMode() != GameMode.CREATIVE) { + return super.translateRequest(session, inventory, request); + } + + PlayerInventory playerInv = session.getPlayerInventory(); + IntSet affectedSlots = new IntOpenHashSet(); + for (StackRequestActionData action : request.getActions()) { + switch (action.getType()) { + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) { + return rejectRequest(request); + } + if (isCraftingGrid(transferAction.getSource()) || isCraftingGrid(transferAction.getDestination())) { + return rejectRequest(request, false); + } + + int transferAmount = transferAction.getCount(); + if (isCursor(transferAction.getDestination())) { + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + if (playerInv.getCursor().isEmpty()) { + playerInv.setCursor(sourceItem.copy(0), session); + } + + playerInv.getCursor().add(transferAmount); + sourceItem.sub(transferAmount); + + affectedSlots.add(sourceSlot); + } else if (isCursor(transferAction.getSource())) { + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + GeyserItemStack sourceItem = playerInv.getCursor(); + if (inventory.getItem(destSlot).isEmpty()) { + inventory.setItem(destSlot, sourceItem.copy(0), session); + } + + inventory.getItem(destSlot).add(transferAmount); + sourceItem.sub(transferAmount); + + affectedSlots.add(destSlot); + } else { + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + if (inventory.getItem(destSlot).isEmpty()) { + inventory.setItem(destSlot, sourceItem.copy(0), session); + } + + inventory.getItem(destSlot).add(transferAmount); + sourceItem.sub(transferAmount); + + affectedSlots.add(sourceSlot); + affectedSlots.add(destSlot); + } + break; + } + case SWAP: { + SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action; + if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) { + return rejectRequest(request); + } + if (isCraftingGrid(swapAction.getSource()) || isCraftingGrid(swapAction.getDestination())) { + return rejectRequest(request, false); + } + + if (isCursor(swapAction.getDestination())) { + int sourceSlot = bedrockSlotToJava(swapAction.getSource()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + GeyserItemStack destItem = playerInv.getCursor(); + + playerInv.setCursor(sourceItem, session); + inventory.setItem(sourceSlot, destItem, session); + + affectedSlots.add(sourceSlot); + } else if (isCursor(swapAction.getSource())) { + int destSlot = bedrockSlotToJava(swapAction.getDestination()); + GeyserItemStack sourceItem = playerInv.getCursor(); + GeyserItemStack destItem = inventory.getItem(destSlot); + + inventory.setItem(destSlot, sourceItem, session); + playerInv.setCursor(destItem, session); + + affectedSlots.add(destSlot); + } else { + int sourceSlot = bedrockSlotToJava(swapAction.getSource()); + int destSlot = bedrockSlotToJava(swapAction.getDestination()); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + GeyserItemStack destItem = inventory.getItem(destSlot); + + inventory.setItem(destSlot, sourceItem, session); + inventory.setItem(sourceSlot, destItem, session); + + affectedSlots.add(sourceSlot); + affectedSlots.add(destSlot); + } + break; + } + case DROP: { + DropStackRequestActionData dropAction = (DropStackRequestActionData) action; + if (!checkNetId(session, inventory, dropAction.getSource())) { + return rejectRequest(request); + } + if (isCraftingGrid(dropAction.getSource())) { + return rejectRequest(request, false); + } + + GeyserItemStack sourceItem; + if (isCursor(dropAction.getSource())) { + sourceItem = playerInv.getCursor(); + } else { + int sourceSlot = bedrockSlotToJava(dropAction.getSource()); + sourceItem = inventory.getItem(sourceSlot); + affectedSlots.add(sourceSlot); + } + + if (sourceItem.isEmpty()) { + return rejectRequest(request); + } + + ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, sourceItem.getItemStack(dropAction.getCount())); + session.sendDownstreamPacket(creativeDropPacket); + + sourceItem.sub(dropAction.getCount()); + break; + } + case DESTROY: { + // Only called when a creative client wants to destroy an item... I think - Camotoy + DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action; + if (!checkNetId(session, inventory, destroyAction.getSource())) { + return rejectRequest(request); + } + if (isCraftingGrid(destroyAction.getSource())) { + return rejectRequest(request, false); + } + + if (!isCursor(destroyAction.getSource())) { + // Item exists; let's remove it from the inventory + int javaSlot = bedrockSlotToJava(destroyAction.getSource()); + GeyserItemStack existingItem = inventory.getItem(javaSlot); + existingItem.sub(destroyAction.getCount()); + affectedSlots.add(javaSlot); + } else { + // Just sync up the item on our end, since the server doesn't care what's in our cursor + playerInv.getCursor().sub(destroyAction.getCount()); + } + break; + } + default: + return rejectRequest(request); + } + } + for (int slot : affectedSlots) { + sendCreativeAction(session, inventory, slot); + } + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + } + + @Override + public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) { + ItemStack javaCreativeItem = null; + IntSet affectedSlots = new IntOpenHashSet(); + CraftState craftState = CraftState.START; + for (StackRequestActionData action : request.getActions()) { + switch (action.getType()) { + case CRAFT_CREATIVE: { + CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action; + if (craftState != CraftState.START) { + return rejectRequest(request); + } + craftState = CraftState.RECIPE_ID; + + int creativeId = creativeAction.getCreativeItemNetworkId() - 1; + if (creativeId < 0 || creativeId >= ItemRegistry.CREATIVE_ITEMS.length) { + return rejectRequest(request); + } + // Reference the creative items list we send to the client to know what it's asking of us + ItemData creativeItem = ItemRegistry.CREATIVE_ITEMS[creativeId]; + javaCreativeItem = ItemTranslator.translateToJava(creativeItem); + break; + } + case CRAFT_RESULTS_DEPRECATED: { + CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; + if (craftState != CraftState.RECIPE_ID) { + return rejectRequest(request); + } + craftState = CraftState.DEPRECATED; + break; + } + case TAKE: + case PLACE: { + TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; + if (!(craftState == CraftState.DEPRECATED || craftState == CraftState.TRANSFER)) { + return rejectRequest(request); + } + craftState = CraftState.TRANSFER; + + if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) { + return rejectRequest(request); + } + + if (isCursor(transferAction.getDestination())) { + if (session.getPlayerInventory().getCursor().isEmpty()) { + GeyserItemStack newItemStack = GeyserItemStack.from(javaCreativeItem); + newItemStack.setAmount(transferAction.getCount()); + session.getPlayerInventory().setCursor(newItemStack, session); + } else { + session.getPlayerInventory().getCursor().add(transferAction.getCount()); + } + //cursor is always included in response + } else { + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + if (inventory.getItem(destSlot).isEmpty()) { + GeyserItemStack newItemStack = GeyserItemStack.from(javaCreativeItem); + newItemStack.setAmount(transferAction.getCount()); + inventory.setItem(destSlot, newItemStack, session); + } else { + inventory.getItem(destSlot).add(transferAction.getCount()); + } + affectedSlots.add(destSlot); + } + break; + } + default: + return rejectRequest(request); + } + } + for (int slot : affectedSlots) { + sendCreativeAction(session, inventory, slot); + } + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + } + + private static void sendCreativeAction(GeyserSession session, Inventory inventory, int slot) { + GeyserItemStack item = inventory.getItem(slot); + ItemStack itemStack = item.isEmpty() ? new ItemStack(-1, 0, null) : item.getItemStack(); + + ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(slot, itemStack); + session.sendDownstreamPacket(creativePacket); + } + + private static boolean isCraftingGrid(StackRequestSlotInfoData slotInfoData) { + return slotInfoData.getContainer() == ContainerSlotType.CRAFTING_INPUT; + } + @Override public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) { throw new UnsupportedOperationException();