diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java index a5cfb46ca..6c6cf9110 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -42,7 +42,6 @@ public class GeyserItemStack { private int amount; private CompoundTag nbt; private int netId; - private boolean netIdWasUpdated; public GeyserItemStack(int javaId) { this(javaId, 1); @@ -61,7 +60,6 @@ public class GeyserItemStack { this.amount = amount; this.nbt = nbt; this.netId = netId; - this.netIdWasUpdated = !this.isEmpty(); } public int getJavaId() { @@ -78,7 +76,6 @@ public class GeyserItemStack { public void setNetId(int netId) { this.netId = netId; - this.netIdWasUpdated = true; } public int getNetId() { 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 f2b626897..7048ce808 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -79,6 +79,11 @@ public class Inventory { public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { GeyserItemStack oldItem = items[slot]; + updateItemNetId(oldItem, newItem, session); + items[slot] = newItem; + } + + protected static void updateItemNetId(GeyserItemStack oldItem, GeyserItemStack newItem, GeyserSession session) { if (!newItem.isEmpty()) { if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) { newItem.setNetId(oldItem.getNetId()); @@ -86,7 +91,6 @@ public class Inventory { newItem.setNetId(session.getNextItemNetId()); } } - items[slot] = newItem; } public short getNextTransactionId() { 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 2e4e3a615..9d03c69ab 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -28,6 +28,7 @@ package org.geysermc.connector.inventory; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.geysermc.connector.network.session.GeyserSession; public class PlayerInventory extends Inventory { @@ -40,7 +41,6 @@ public class PlayerInventory extends Inventory { private int heldItemSlot; @Getter - @Setter @NonNull private GeyserItemStack cursor = GeyserItemStack.EMPTY; @@ -49,6 +49,11 @@ public class PlayerInventory extends Inventory { heldItemSlot = 0; } + public void setCursor(@NonNull GeyserItemStack newCursor, GeyserSession session) { + updateItemNetId(cursor, newCursor, session); + cursor = newCursor; + } + public GeyserItemStack getItemInHand() { return items[36 + heldItemSlot]; } 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 bfead50fb..ffc8d02fa 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 @@ -223,7 +223,7 @@ public abstract class InventoryTranslator { } else { // Cursor will be emptied destItem.setAmount(itemsLeftOver); - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( destSlot, @@ -250,13 +250,13 @@ public abstract class InventoryTranslator { if (sourceItem.isEmpty()) { // Item is basically deleted if (sourceIsCursor) { - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } else { inventory.setItem(sourceSlot, GeyserItemStack.EMPTY, session); } } if (destIsCursor) { - session.getPlayerInventory().setCursor(newItem); + session.getPlayerInventory().setCursor(newItem, session); } else { inventory.setItem(destSlot, newItem, session); } @@ -340,7 +340,7 @@ public abstract class InventoryTranslator { //try to transfer items with least clicks possible int halfSource = sourceAmount - (sourceAmount / 2); //larger half int holding; - if (transferAction.getCount() <= halfSource) { //faster to take only half + if (plan.getCursor().isEmpty() && transferAction.getCount() <= halfSource) { //faster to take only half. CURSOR MUST BE EMPTY plan.add(Click.RIGHT, sourceSlot); holding = halfSource; } else { //need all @@ -376,7 +376,7 @@ public abstract class InventoryTranslator { GeyserItemStack oldDestinationItem = inventory.getItem(destSlot); if (isCursor(swapAction.getSource())) { oldSourceItem = session.getPlayerInventory().getCursor(); - session.getPlayerInventory().setCursor(oldDestinationItem); + session.getPlayerInventory().setCursor(oldDestinationItem, session); } else { int sourceSlot = bedrockSlotToJava(swapAction.getSource()); oldSourceItem = inventory.getItem(sourceSlot); @@ -389,7 +389,7 @@ public abstract class InventoryTranslator { inventory.setItem(sourceSlot, oldDestinationItem, session); } if (isCursor(swapAction.getDestination())) { - session.getPlayerInventory().setCursor(oldSourceItem); + session.getPlayerInventory().setCursor(oldSourceItem, session); } else { ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket( destSlot, @@ -445,7 +445,7 @@ public abstract class InventoryTranslator { cursorItem.setAmount(cursorItem.getAmount() - dropAction.getCount()); if (cursorItem.isEmpty()) { // Cursor item no longer exists - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } droppingItem.setAmount(dropAction.getCount()); ClientCreativeInventoryActionPacket packet = new ClientCreativeInventoryActionPacket( @@ -503,7 +503,7 @@ public abstract class InventoryTranslator { 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.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); } break; } @@ -715,7 +715,7 @@ public abstract class InventoryTranslator { ItemStack javaCreativeItem = ItemTranslator.translateToJava(creativeItem); if (isCursor(transferAction.getDestination())) { - session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId())); + session.getPlayerInventory().setCursor(GeyserItemStack.from(javaCreativeItem, session.getNextItemNetId()), session); return acceptRequest(request, Collections.singletonList( new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(makeItemEntry(0, session.getPlayerInventory().getCursor()))))); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java index e2d554e2f..830a9ce0b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java @@ -63,6 +63,11 @@ public class ClickPlan { this.simulating = true; } + private void resetSimulation() { + this.simulatedItems.clear(); + this.simulatedCursor = session.getPlayerInventory().getCursor().copy(); + } + public void add(Click click, int slot) { if (!simulating) throw new UnsupportedOperationException("ClickPlan already executed"); @@ -77,7 +82,8 @@ public class ClickPlan { } public void execute(boolean refresh) { - simulating = false; + //update geyser inventory after simulation to avoid net id desync + resetSimulation(); ListIterator planIter = plan.listIterator(); while (planIter.hasNext()) { ClickAction action = planIter.next(); @@ -92,7 +98,7 @@ public class ClickPlan { } else if (action.click.windowAction == WindowAction.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) { clickedItemStack = null; } else { - clickedItemStack = inventory.getItem(action.slot).getItemStack(); + clickedItemStack = getItem(action.slot).getItemStack(); } short actionId = inventory.getNextTransactionId(); @@ -113,6 +119,12 @@ public class ClickPlan { } System.out.println(clickPacket); } + + session.getPlayerInventory().setCursor(simulatedCursor, session); + for (Int2ObjectMap.Entry simulatedSlot : simulatedItems.int2ObjectEntrySet()) { + inventory.setItem(simulatedSlot.getIntKey(), simulatedSlot.getValue(), session); + } + simulating = false; } public GeyserItemStack getItem(int slot) { @@ -135,7 +147,7 @@ public class ClickPlan { if (simulating) { simulatedCursor = item; } else { - session.getPlayerInventory().setCursor(item); + session.getPlayerInventory().setCursor(item, session); } } 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 3b55733bf..05347fd06 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 @@ -41,6 +41,7 @@ public class JavaConfirmTransactionTranslator extends PacketTranslator session.addInventoryTask(() -> { if (packet.getWindowId() == 255) { //cursor GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); - GeyserItemStack oldItem = session.getPlayerInventory().getCursor(); - if (newItem.getItemData(session).equals(oldItem.getItemData(session))) { - newItem.setNetId(oldItem.getNetId()); - } else { - newItem.setNetId(session.getNextItemNetId()); - } - session.getPlayerInventory().setCursor(newItem); + session.getPlayerInventory().setCursor(newItem, session); InventoryUtils.updateCursor(session); return; } 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 23f8f103d..81f59cf3f 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -79,7 +79,7 @@ public class InventoryUtils { } public static void closeInventory(GeyserSession session, int windowId) { - session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY); + session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); updateCursor(session); Inventory inventory = getInventory(session, windowId);