--- a/net/minecraft/server/Container.java +++ b/net/minecraft/server/Container.java @@ -7,6 +7,17 @@ import java.util.List; import java.util.Set; +// CraftBukkit start +import java.util.HashMap; +import java.util.Map; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.event.Event.Result; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryView; +// CraftBukkit end + public abstract class Container { public List b = Lists.newArrayList(); @@ -18,12 +29,24 @@ protected List listeners = Lists.newArrayList(); private Set i = Sets.newHashSet(); + // CraftBukkit start + public boolean checkReachable = true; + public abstract InventoryView getBukkitView(); + public void transferTo(Container other, org.bukkit.craftbukkit.entity.CraftHumanEntity player) { + InventoryView source = this.getBukkitView(), destination = other.getBukkitView(); + ((CraftInventory) source.getTopInventory()).getInventory().onClose(player); + ((CraftInventory) source.getBottomInventory()).getInventory().onClose(player); + ((CraftInventory) destination.getTopInventory()).getInventory().onOpen(player); + ((CraftInventory) destination.getBottomInventory()).getInventory().onOpen(player); + } + // CraftBukkit end + public Container() {} protected Slot a(Slot slot) { slot.rawSlotIndex = this.c.size(); this.c.add(slot); - this.b.add((Object) null); + this.b.add(null); // CraftBukkit - fix decompile error return slot; } @@ -124,6 +147,7 @@ l = playerinventory.getCarried().count; Iterator iterator = this.h.iterator(); + Map draggedSlots = new HashMap(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack) while (iterator.hasNext()) { Slot slot1 = (Slot) iterator.next(); @@ -141,16 +165,48 @@ } l -= itemstack2.count - j1; - slot1.set(itemstack2); + // slot1.set(itemstack2); + draggedSlots.put(slot1.rawSlotIndex, itemstack2); // CraftBukkit - Put in map instead of setting } } - itemstack1.count = l; - if (itemstack1.count <= 0) { - itemstack1 = null; + // CraftBukkit start - InventoryDragEvent + InventoryView view = getBukkitView(); + org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack1); + newcursor.setAmount(l); + Map eventmap = new HashMap(); + for (Map.Entry ditem : draggedSlots.entrySet()) { + eventmap.put(ditem.getKey(), CraftItemStack.asBukkitCopy(ditem.getValue())); + } + + // It's essential that we set the cursor to the new value here to prevent item duplication if a plugin closes the inventory. + ItemStack oldCursor = playerinventory.getCarried(); + playerinventory.setCarried(CraftItemStack.asNMSCopy(newcursor)); + + InventoryDragEvent event = new InventoryDragEvent(view, (newcursor.getType() != org.bukkit.Material.AIR ? newcursor : null), CraftItemStack.asBukkitCopy(oldCursor), this.dragType == 1, eventmap); + entityhuman.world.getServer().getPluginManager().callEvent(event); + + // Whether or not a change was made to the inventory that requires an update. + boolean needsUpdate = event.getResult() != Result.DEFAULT; + + if (event.getResult() != Result.DENY) { + for (Map.Entry dslot : draggedSlots.entrySet()) { + view.setItem(dslot.getKey(), CraftItemStack.asBukkitCopy(dslot.getValue())); + } + // The only time the carried item will be set to null is if the inventory is closed by the server. + // If the inventory is closed by the server, then the cursor items are dropped. This is why we change the cursor early. + if (playerinventory.getCarried() != null) { + playerinventory.setCarried(CraftItemStack.asNMSCopy(event.getCursor())); + needsUpdate = true; + } + } else { + playerinventory.setCarried(oldCursor); } - playerinventory.setCarried(itemstack1); + if (needsUpdate && entityhuman instanceof EntityPlayer) { + ((EntityPlayer) entityhuman).updateInventory(this); + } + // CraftBukkit end } this.d(); @@ -173,8 +229,14 @@ } if (j == 1) { - entityhuman.drop(playerinventory.getCarried().cloneAndSubtract(1), true); - if (playerinventory.getCarried().count == 0) { + // CraftBukkit start - Store a reference + ItemStack itemstack4 = playerinventory.getCarried(); + if (itemstack4.count > 0) { + entityhuman.drop(itemstack4.cloneAndSubtract(1), true); + } + + if (itemstack4.count == 0) { + // CraftBukkit end playerinventory.setCarried((ItemStack) null); } } @@ -223,7 +285,11 @@ if (itemstack4.count == 0) { playerinventory.setCarried((ItemStack) null); + // CraftBukkit start - Update client cursor if we didn't empty it + } else if (entityhuman instanceof EntityPlayer) { + ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, entityhuman.inventory.getCarried())); } + // CraftBukkit end } } else if (slot2.isAllowed(entityhuman)) { if (itemstack4 == null) { @@ -249,7 +315,11 @@ itemstack4.cloneAndSubtract(k1); if (itemstack4.count == 0) { playerinventory.setCarried((ItemStack) null); + // CraftBukkit start - Update client cursor if we didn't empty it + } else if (entityhuman instanceof EntityPlayer) { + ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, entityhuman.inventory.getCarried())); } + // CraftBukkit end itemstack1.count += k1; } else if (itemstack4.count <= slot2.getMaxStackSize(itemstack4)) { @@ -258,7 +328,9 @@ } } else if (itemstack1.getItem() == itemstack4.getItem() && itemstack4.getMaxStackSize() > 1 && (!itemstack1.usesData() || itemstack1.getData() == itemstack4.getData()) && ItemStack.equals(itemstack1, itemstack4)) { k1 = itemstack1.count; - if (k1 > 0 && k1 + itemstack4.count <= itemstack4.getMaxStackSize()) { + // CraftBukkit start - itemstack4.getMaxStackSize() -> maxStack + int maxStack = Math.min(itemstack4.getMaxStackSize(), slot2.getMaxStackSize()); + if (k1 > 0 && k1 + itemstack4.count <= maxStack) { itemstack4.count += k1; itemstack1 = slot2.a(k1); if (itemstack1.count == 0) { @@ -266,11 +338,24 @@ } slot2.a(entityhuman, playerinventory.getCarried()); + // CraftBukkit start - Update client cursor if we didn't empty it + } else if (entityhuman instanceof EntityPlayer) { + ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, entityhuman.inventory.getCarried())); } + // CraftBukkit end } } slot2.f(); + // CraftBukkit start - Make sure the client has the right slot contents + if (entityhuman instanceof EntityPlayer && slot2.getMaxStackSize() != 64) { + ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(this.windowId, slot2.rawSlotIndex, slot2.getItem())); + // Updating a crafting inventory makes the client reset the result slot, have to send it again + if (this.getBukkitView().getType() == InventoryType.WORKBENCH || this.getBukkitView().getType() == InventoryType.CRAFTING) { + ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(this.windowId, 0, this.getSlot(0).getItem())); + } + } + // CraftBukkit end } } } else if (k == 2 && j >= 0 && j < 9) { @@ -411,17 +496,20 @@ if (itemstack1 != null && itemstack1.getItem() == itemstack.getItem() && (!itemstack.usesData() || itemstack.getData() == itemstack1.getData()) && ItemStack.equals(itemstack, itemstack1)) { int l = itemstack1.count + itemstack.count; - if (l <= itemstack.getMaxStackSize()) { + // CraftBukkit start - itemstack.getMaxStackSize() -> maxStack + int maxStack = Math.min(itemstack.getMaxStackSize(), slot.getMaxStackSize()); + if (l <= maxStack) { itemstack.count = 0; itemstack1.count = l; slot.f(); flag1 = true; - } else if (itemstack1.count < itemstack.getMaxStackSize()) { - itemstack.count -= itemstack.getMaxStackSize() - itemstack1.count; - itemstack1.count = itemstack.getMaxStackSize(); + } else if (itemstack1.count < maxStack) { + itemstack.count -= maxStack - itemstack1.count; + itemstack1.count = maxStack; slot.f(); flag1 = true; } + // CraftBukkit end } if (flag) {