1
0
forked from xjboss/KCauldronX
KCauldronX/patches/net/minecraft/inventory/Container.java.patch
Prototik f3a73d8d68 Reduce calls to heavy nbt comparsion
Spigot patch: 0157-Use-FastMatches-for-ItemStack-Dirty-Check.patch
2015-05-14 22:23:44 +07:00

215 lines
9.4 KiB
Diff

--- ../src-base/minecraft/net/minecraft/inventory/Container.java
+++ ../src-work/minecraft/net/minecraft/inventory/Container.java
@@ -13,6 +13,17 @@
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
+// CraftBukkit start
+import java.util.HashMap;
+import java.util.Map;
+import net.minecraft.entity.player.EntityPlayerMP;
+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.inventory.InventoryView;
+// CraftBukkit end
+
public abstract class Container
{
public List inventoryItemStacks = new ArrayList();
@@ -21,12 +32,52 @@
@SideOnly(Side.CLIENT)
private short transactionID;
private int field_94535_f = -1;
- private int field_94536_g;
+ public int field_94536_g; // CraftBukkit - private -> public
private final Set field_94537_h = new HashSet();
+ public InventoryView bukkitView = null; // Cauldron
+ private int tickCount = 0; // Spigot
protected List crafters = new ArrayList();
private Set playerList = new HashSet();
private static final String __OBFID = "CL_00001730";
+ // CraftBukkit start
+ public boolean checkReachable = true;
+ public InventoryView getBukkitView() { return bukkitView; } // Cauldron
+ public void transferTo(Container other, org.bukkit.craftbukkit.entity.CraftHumanEntity player)
+ {
+ InventoryView source = this.getBukkitView(), destination = other.getBukkitView();
+ // Cauldron start - add null checks to skip modded inventories with no Bukkit wrappers, and
+ // catch AbstractMethodErrors for modded IInventory's with no onClose()
+ if (source != null) {
+ try {
+ ((CraftInventory) source.getTopInventory()).getInventory().onClose(player);
+ } catch (AbstractMethodError ex) {
+ // modded
+ }
+
+ try {
+ ((CraftInventory) source.getBottomInventory()).getInventory().onClose(player);
+ } catch (AbstractMethodError ex) {
+ // modded
+ }
+ }
+ if (destination != null) {
+ try {
+ ((CraftInventory) destination.getTopInventory()).getInventory().onOpen(player);
+ } catch (AbstractMethodError ex) {
+ // modded
+ }
+
+ try {
+ ((CraftInventory) destination.getBottomInventory()).getInventory().onOpen(player);
+ } catch (AbstractMethodError ex) {
+ // modded
+ }
+ }
+ // Cauldron end
+ }
+ // CraftBukkit end
+
protected Slot addSlotToContainer(Slot p_75146_1_)
{
p_75146_1_.slotNumber = this.inventorySlots.size();
@@ -39,7 +90,11 @@
{
if (this.crafters.contains(p_75132_1_))
{
- throw new IllegalArgumentException("Listener already listening");
+ // Cauldron start - As we do not create a new player object on respawn, we need to update the client with changes if listener already exists
+ //throw new IllegalArgumentException("Listener already listening");
+ p_75132_1_.sendContainerAndContentsToPlayer(this, this.getInventory());
+ this.detectAndSendChanges();
+ // Cauldron end
}
else
{
@@ -74,7 +129,7 @@
ItemStack itemstack = ((Slot)this.inventorySlots.get(i)).getStack();
ItemStack itemstack1 = (ItemStack)this.inventoryItemStacks.get(i);
- if (!ItemStack.areItemStacksEqual(itemstack1, itemstack))
+ if (!areItemStacksEqual(itemstack1, itemstack))
{
itemstack1 = itemstack == null ? null : itemstack.copy();
this.inventoryItemStacks.set(i, itemstack1);
@@ -85,6 +140,7 @@
}
}
}
+ tickCount++;
}
public boolean enchantItem(EntityPlayer p_75140_1_, int p_75140_2_)
@@ -109,6 +165,10 @@
public Slot getSlot(int p_75139_1_)
{
+ // Cauldron start - vanilla compatibility. fixes NPE with ProjectRed's Item Stock Keeper
+ if (p_75139_1_ < 0 || p_75139_1_ >= this.inventorySlots.size())
+ return null;
+ // Cauldron end
return (Slot)this.inventorySlots.get(p_75139_1_);
}
@@ -168,6 +228,7 @@
itemstack3 = inventoryplayer.getItemStack().copy();
i1 = inventoryplayer.getItemStack().stackSize;
Iterator iterator = this.field_94537_h.iterator();
+ Map<Integer, ItemStack> draggedSlots = new HashMap<Integer, ItemStack>(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack)
while (iterator.hasNext())
{
@@ -190,18 +251,55 @@
}
i1 -= itemstack1.stackSize - j1;
- slot1.putStack(itemstack1);
+ draggedSlots.put(slot1.slotNumber, itemstack1); // CraftBukkit - Put in map instead of setting
}
}
- itemstack3.stackSize = i1;
+ // CraftBukkit start - InventoryDragEvent
+ InventoryView view = getBukkitView();
+ org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack3);
+ newcursor.setAmount(i1);
+ Map<Integer, org.bukkit.inventory.ItemStack> eventmap = new HashMap<Integer, org.bukkit.inventory.ItemStack>();
- if (itemstack3.stackSize <= 0)
+ for (Map.Entry<Integer, ItemStack> ditem : draggedSlots.entrySet())
{
- itemstack3 = null;
+ eventmap.put(ditem.getKey(), CraftItemStack.asBukkitCopy(ditem.getValue()));
}
- inventoryplayer.setItemStack(itemstack3);
+ // 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 = inventoryplayer.getItemStack();
+ inventoryplayer.setItemStack(CraftItemStack.asNMSCopy(newcursor));
+ InventoryDragEvent event = new InventoryDragEvent(view, (newcursor.getType() != org.bukkit.Material.AIR ? newcursor : null), CraftItemStack.asBukkitCopy(oldCursor), this.field_94535_f == i1, eventmap); // Should be dragButton
+ p_75144_4_.worldObj.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<Integer, ItemStack> 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 (inventoryplayer.getItemStack() != null)
+ {
+ inventoryplayer.setItemStack(CraftItemStack.asNMSCopy(event.getCursor()));
+ needsUpdate = true;
+ }
+ }
+ else
+ {
+ inventoryplayer.setItemStack(oldCursor);
+ }
+
+ if (needsUpdate && p_75144_4_ instanceof EntityPlayerMP)
+ {
+ ((EntityPlayerMP) p_75144_4_).sendContainerToPlayer(this);
+ }
+
+ // CraftBukkit end
}
this.func_94533_d();
@@ -235,10 +333,17 @@
if (p_75144_2_ == 1)
{
- p_75144_4_.dropPlayerItemWithRandomChoice(inventoryplayer.getItemStack().splitStack(1), true);
+ // CraftBukkit start - Store a reference
+ ItemStack itemstack4 = inventoryplayer.getItemStack();
if (inventoryplayer.getItemStack().stackSize == 0)
{
+ p_75144_4_.dropPlayerItemWithRandomChoice(inventoryplayer.getItemStack().splitStack(1), true);
+ }
+
+ if (itemstack4.stackSize == 0)
+ {
+ // CraftBukkit end
inventoryplayer.setItemStack((ItemStack)null);
}
}
@@ -730,4 +835,10 @@
return MathHelper.floor_float(f * 14.0F) + (i > 0 ? 1 : 0);
}
}
+
+ // Spigot start
+ public boolean areItemStacksEqual(ItemStack is1, ItemStack is2) {
+ return tickCount % 20 == 0 ? ItemStack.areItemStacksEqual(is1, is2) : ItemStack.fastMatches(is1, is2);
+ }
+ // Spigot
}