From 0842bab48b1c24f113c61606a294f5bcdf2e1315 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Wed, 29 Feb 2012 13:56:35 -0500 Subject: [PATCH] [Bleeding] Implementation of inventory framework. Addresses BUKKIT-856 See the corresponding Bukkit commit for details. Implementation details: - Any packets that include an itemstack will send air stacks as null; maybe this will even eliminate the client crash that occurs if the client receives an air stack - Better handling of null itemstacks in general (ie less converting them to air stacks) - Inventory.setContents() can now take an array smaller than the inventory without error - Player.updateInventory() should now correctly update the result slot in a crafting inventory Some small credit goes to Afforess (initial implementation of openInventory() methods) and Drakia (initial implementation of InventoryOpenEvent and InventoryCloseEvent). --- .../java/net/minecraft/server/Container.java | 19 +- .../server/ContainerBrewingStand.java | 22 ++ .../net/minecraft/server/ContainerChest.java | 36 ++- .../minecraft/server/ContainerDispenser.java | 27 ++- .../server/ContainerEnchantTable.java | 29 ++- .../ContainerEnchantTableInventory.java | 4 +- .../ContainerEnchantTableSubcontainer.java | 32 ++- .../minecraft/server/ContainerFurnace.java | 24 +- .../net/minecraft/server/ContainerPlayer.java | 29 ++- .../minecraft/server/ContainerWorkbench.java | 32 ++- .../net/minecraft/server/CraftingManager.java | 26 +- .../net/minecraft/server/EntityHuman.java | 10 +- .../net/minecraft/server/EntityMinecart.java | 25 +- .../net/minecraft/server/EntityPlayer.java | 53 +++- .../java/net/minecraft/server/IInventory.java | 20 +- .../server/InventoryCraftResult.java | 19 ++ .../minecraft/server/InventoryCrafting.java | 34 +++ .../minecraft/server/InventoryLargeChest.java | 35 ++- .../minecraft/server/NetServerHandler.java | 121 ++++++++-- .../java/net/minecraft/server/Packet.java | 2 +- .../net/minecraft/server/PlayerInventory.java | 27 +++ .../java/net/minecraft/server/TileEntity.java | 13 + .../server/TileEntityBrewingStand.java | 30 +++ .../net/minecraft/server/TileEntityChest.java | 22 ++ .../minecraft/server/TileEntityDispenser.java | 22 ++ .../minecraft/server/TileEntityFurnace.java | 20 ++ .../org/bukkit/craftbukkit/CraftServer.java | 20 ++ .../craftbukkit/block/CraftBrewingStand.java | 8 +- .../bukkit/craftbukkit/block/CraftChest.java | 24 +- .../craftbukkit/block/CraftFurnace.java | 8 +- .../craftbukkit/entity/CraftHumanEntity.java | 140 +++++++++++ .../craftbukkit/entity/CraftPlayer.java | 25 ++ .../craftbukkit/event/CraftEventFactory.java | 39 +++ .../craftbukkit/inventory/CraftContainer.java | 228 ++++++++++++++++++ .../craftbukkit/inventory/CraftInventory.java | 65 ++++- .../inventory/CraftInventoryBrewer.java | 26 ++ .../inventory/CraftInventoryCrafting.java | 139 +++++++++++ .../inventory/CraftInventoryCustom.java | 122 ++++++++++ .../inventory/CraftInventoryDoubleChest.java | 53 ++++ .../inventory/CraftInventoryEnchanting.java | 25 ++ .../inventory/CraftInventoryFurnace.java | 42 ++++ .../inventory/CraftInventoryPlayer.java | 8 + .../inventory/CraftInventoryView.java | 117 +++++++++ .../craftbukkit/inventory/CraftItemStack.java | 5 + .../inventory/CraftShapelessRecipe.java | 2 +- .../craftbukkit/inventory/CraftSlot.java | 25 -- .../inventory/InventoryIterator.java | 56 +++++ 47 files changed, 1821 insertions(+), 89 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryBrewer.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java delete mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/InventoryIterator.java diff --git a/src/main/java/net/minecraft/server/Container.java b/src/main/java/net/minecraft/server/Container.java index 1b4c3427e8..248ae3a258 100644 --- a/src/main/java/net/minecraft/server/Container.java +++ b/src/main/java/net/minecraft/server/Container.java @@ -5,8 +5,13 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public abstract class Container { +// CraftBukkit start +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.inventory.InventoryView; +// CraftBukkit end +public abstract class Container { public List d = new ArrayList(); public List e = new ArrayList(); public int windowId = 0; @@ -14,6 +19,18 @@ public abstract class Container { protected List listeners = new ArrayList(); private Set b = new HashSet(); + // CraftBukkit start + public boolean checkReachable = true; + public abstract InventoryView getBukkitView(); + public void transferTo(Container other, 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 void a(Slot slot) { diff --git a/src/main/java/net/minecraft/server/ContainerBrewingStand.java b/src/main/java/net/minecraft/server/ContainerBrewingStand.java index a0a7d950ef..25655e5812 100644 --- a/src/main/java/net/minecraft/server/ContainerBrewingStand.java +++ b/src/main/java/net/minecraft/server/ContainerBrewingStand.java @@ -1,11 +1,21 @@ package net.minecraft.server; +// CraftBukkit start +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +// CraftBukkit end + public class ContainerBrewingStand extends Container { private TileEntityBrewingStand a; private int b = 0; + // CraftBukkit start + private CraftInventoryView bukkitEntity = null; + private PlayerInventory player; + // CraftBukkit end public ContainerBrewingStand(PlayerInventory playerinventory, TileEntityBrewingStand tileentitybrewingstand) { + player = playerinventory; // CraftBukkit this.a = tileentitybrewingstand; this.a(new SlotPotionBottle(this, playerinventory.d, tileentitybrewingstand, 0, 56, 46)); this.a(new SlotPotionBottle(this, playerinventory.d, tileentitybrewingstand, 1, 79, 53)); @@ -45,6 +55,7 @@ public class ContainerBrewingStand extends Container { } public boolean b(EntityHuman entityhuman) { + if (!this.checkReachable) return true; // CraftBukkit return this.a.a(entityhuman); } @@ -87,4 +98,15 @@ public class ContainerBrewingStand extends Container { return itemstack; } + + // CraftBukkit start + public CraftInventoryView getBukkitView() { + if (bukkitEntity != null) { + return bukkitEntity; + } + CraftInventory inventory = new CraftInventory(this.a); + bukkitEntity = new CraftInventoryView(this.player.d.getBukkitEntity(), inventory, this); + return bukkitEntity; + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/ContainerChest.java b/src/main/java/net/minecraft/server/ContainerChest.java index 5da010fdc7..c1aa3f5fed 100644 --- a/src/main/java/net/minecraft/server/ContainerChest.java +++ b/src/main/java/net/minecraft/server/ContainerChest.java @@ -1,15 +1,30 @@ package net.minecraft.server; +// CraftBukkit start +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest; +import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +// CraftBukkit end + public class ContainerChest extends Container { - private IInventory a; + public IInventory a; // CraftBukkit - private->public private int b; + // CraftBukkit start + private CraftInventoryView bukkitEntity = null; + private PlayerInventory player; + // CraftBukkit end public ContainerChest(IInventory iinventory, IInventory iinventory1) { this.a = iinventory1; this.b = iinventory1.getSize() / 9; iinventory1.f(); int i = (this.b - 4) * 18; + // CraftBukkit start - save player + // TODO: Should we check to make sure it really is an InventoryPlayer? + this.player = (PlayerInventory)iinventory; + // CraftBukkit end int j; int k; @@ -32,6 +47,7 @@ public class ContainerChest extends Container { } public boolean b(EntityHuman entityhuman) { + if (!this.checkReachable) return true; // CraftBukkit return this.a.a(entityhuman); } @@ -61,6 +77,24 @@ public class ContainerChest extends Container { return itemstack; } + // CraftBukkit start + public CraftInventoryView getBukkitView() { + if (bukkitEntity != null) { + return bukkitEntity; + } + CraftInventory inventory; + if (a instanceof PlayerInventory) { + inventory = new CraftInventoryPlayer((PlayerInventory)a); + } else if (a instanceof InventoryLargeChest) { + inventory = new CraftInventoryDoubleChest((InventoryLargeChest)a); + } else { + inventory = new CraftInventory(this.a); + } + bukkitEntity = new CraftInventoryView(this.player.d.getBukkitEntity(), inventory, this); + return bukkitEntity; + } + // CraftBukkit end + public void a(EntityHuman entityhuman) { super.a(entityhuman); this.a.g(); diff --git a/src/main/java/net/minecraft/server/ContainerDispenser.java b/src/main/java/net/minecraft/server/ContainerDispenser.java index 463a83ae5b..276f436299 100644 --- a/src/main/java/net/minecraft/server/ContainerDispenser.java +++ b/src/main/java/net/minecraft/server/ContainerDispenser.java @@ -1,11 +1,24 @@ package net.minecraft.server; +// CraftBukkit start +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +// CraftBukkit end + public class ContainerDispenser extends Container { - private TileEntityDispenser a; + public TileEntityDispenser a; // CraftBukkit - Private -> Public + // CraftBukkit start + private CraftInventoryView bukkitEntity = null; + private PlayerInventory player; + // CraftBukkit end public ContainerDispenser(IInventory iinventory, TileEntityDispenser tileentitydispenser) { this.a = tileentitydispenser; + // CraftBukkit start - save player + // TODO: Should we check to make sure it really is an InventoryPlayer? + this.player = (PlayerInventory)iinventory; + // CraftBukkit end int i; int j; @@ -28,6 +41,7 @@ public class ContainerDispenser extends Container { } public boolean b(EntityHuman entityhuman) { + if (!this.checkReachable) return true; // CraftBukkit return this.a.a(entityhuman); } @@ -62,4 +76,15 @@ public class ContainerDispenser extends Container { return itemstack; } + + // CraftBukkit start + public CraftInventoryView getBukkitView() { + if (bukkitEntity != null) { + return bukkitEntity; + } + CraftInventory inventory = new CraftInventory(this.a); + bukkitEntity = new CraftInventoryView(this.player.d.getBukkitEntity(), inventory, this); + return bukkitEntity; + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/ContainerEnchantTable.java b/src/main/java/net/minecraft/server/ContainerEnchantTable.java index cce9a7f623..3acf50653d 100644 --- a/src/main/java/net/minecraft/server/ContainerEnchantTable.java +++ b/src/main/java/net/minecraft/server/ContainerEnchantTable.java @@ -8,6 +8,8 @@ import java.util.Random; import java.util.Map; import java.util.HashMap; +import org.bukkit.craftbukkit.inventory.CraftInventoryEnchanting; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.event.enchantment.EnchantItemEvent; import org.bukkit.event.enchantment.PrepareItemEnchantEvent; @@ -16,7 +18,9 @@ import org.bukkit.entity.Player; public class ContainerEnchantTable extends Container { - public IInventory a = new ContainerEnchantTableInventory(this, "Enchant", 1); + // CraftBukkit start - make type specific (changed from IInventory) + public ContainerEnchantTableInventory a = new ContainerEnchantTableInventory(this, "Enchant", 1); + // CraftBukkit end private World h; private int i; private int j; @@ -24,7 +28,10 @@ public class ContainerEnchantTable extends Container { private Random l = new Random(); public long b; public int[] c = new int[3]; - private Player player; // CraftBukkit + // CraftBukkit start + private CraftInventoryView bukkitEntity = null; + private Player player; + // CraftBukkit end public ContainerEnchantTable(PlayerInventory playerinventory, World world, int i, int j, int k) { this.h = world; @@ -44,7 +51,7 @@ public class ContainerEnchantTable extends Container { for (l = 0; l < 9; ++l) { this.a(new Slot(playerinventory, l, 8 + l * 18, 142)); } - player = (Player) playerinventory.d.bukkitEntity; // CraftBukkit + player = (Player) playerinventory.d.getBukkitEntity(); // CraftBukkit } public void a(ICrafting icrafting) { @@ -116,7 +123,7 @@ public class ContainerEnchantTable extends Container { // CraftBukkit start CraftItemStack item = new CraftItemStack(itemstack); - PrepareItemEnchantEvent event = new PrepareItemEnchantEvent(player, h.getWorld().getBlockAt(this.i, this.j, this.k), item, this.c, i); + PrepareItemEnchantEvent event = new PrepareItemEnchantEvent(player, this.getBukkitView(), h.getWorld().getBlockAt(this.i, this.j, this.k), item, this.c, i); h.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { for (i = 0; i < 3; ++i) { @@ -149,7 +156,7 @@ public class ContainerEnchantTable extends Container { enchants.put(org.bukkit.enchantments.Enchantment.getById(e.a.id), e.b); } CraftItemStack item = new CraftItemStack(itemstack); - EnchantItemEvent event = new EnchantItemEvent((Player) entityhuman.bukkitEntity, h.getWorld().getBlockAt(this.i, this.j, this.k), item, this.c[i], enchants); + EnchantItemEvent event = new EnchantItemEvent((Player) entityhuman.bukkitEntity, this.getBukkitView(), h.getWorld().getBlockAt(this.i, this.j, this.k), item, this.c[i], enchants, i); h.getServer().getPluginManager().callEvent(event); int level = event.getExpLevelCost(); @@ -189,6 +196,7 @@ public class ContainerEnchantTable extends Container { } public boolean b(EntityHuman entityhuman) { + if (!this.checkReachable) return true; // CraftBukkit return this.h.getTypeId(this.i, this.j, this.k) != Block.ENCHANTMENT_TABLE.id ? false : entityhuman.e((double) this.i + 0.5D, (double) this.j + 0.5D, (double) this.k + 0.5D) <= 64.0D; } @@ -223,4 +231,15 @@ public class ContainerEnchantTable extends Container { return itemstack; } + + // CraftBukkit start + public CraftInventoryView getBukkitView() { + if (bukkitEntity != null) { + return bukkitEntity; + } + CraftInventoryEnchanting inventory = new CraftInventoryEnchanting(this.a); + bukkitEntity = new CraftInventoryView(this.player, inventory, this); + return bukkitEntity; + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/ContainerEnchantTableInventory.java b/src/main/java/net/minecraft/server/ContainerEnchantTableInventory.java index 7b7bab9308..c697ae15dd 100644 --- a/src/main/java/net/minecraft/server/ContainerEnchantTableInventory.java +++ b/src/main/java/net/minecraft/server/ContainerEnchantTableInventory.java @@ -1,8 +1,8 @@ package net.minecraft.server; -class ContainerEnchantTableInventory extends ContainerEnchantTableSubcontainer { +public class ContainerEnchantTableInventory extends ContainerEnchantTableSubcontainer { // CraftBukkit -> public - final ContainerEnchantTable a; + public final ContainerEnchantTable a; // CraftBukkit -> public ContainerEnchantTableInventory(ContainerEnchantTable containerenchanttable, String s, int i) { super(s, i); diff --git a/src/main/java/net/minecraft/server/ContainerEnchantTableSubcontainer.java b/src/main/java/net/minecraft/server/ContainerEnchantTableSubcontainer.java index 14f943ad68..17903b2c49 100644 --- a/src/main/java/net/minecraft/server/ContainerEnchantTableSubcontainer.java +++ b/src/main/java/net/minecraft/server/ContainerEnchantTableSubcontainer.java @@ -1,14 +1,44 @@ package net.minecraft.server; +import java.util.ArrayList; import java.util.List; -public class ContainerEnchantTableSubcontainer implements IInventory { +// CraftBukkit start +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end +public class ContainerEnchantTableSubcontainer implements IInventory { private String a; private int b; private ItemStack[] c; private List d; + // CraftBukkit start + public List transaction = new ArrayList(); + + public ItemStack[] getContents() { + return this.c; + } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } + + public InventoryHolder getOwner() { + return null; // TODO: Enchanting tables don't really have an owner? Maybe they should? + } + // CraftBukkit end + public ContainerEnchantTableSubcontainer(String s, int i) { this.a = s; this.b = i; diff --git a/src/main/java/net/minecraft/server/ContainerFurnace.java b/src/main/java/net/minecraft/server/ContainerFurnace.java index cc14e532e5..e2ca557c28 100644 --- a/src/main/java/net/minecraft/server/ContainerFurnace.java +++ b/src/main/java/net/minecraft/server/ContainerFurnace.java @@ -1,17 +1,27 @@ package net.minecraft.server; +// CraftBukkit start +import org.bukkit.craftbukkit.inventory.CraftInventoryFurnace; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +// CraftBukkit end + public class ContainerFurnace extends Container { - private TileEntityFurnace a; + public TileEntityFurnace a; // CraftBukkit - Private -> Public private int b = 0; private int c = 0; private int h = 0; + // CraftBukkit start + private CraftInventoryView bukkitEntity = null; + private PlayerInventory player; + // CraftBukkit end public ContainerFurnace(PlayerInventory playerinventory, TileEntityFurnace tileentityfurnace) { this.a = tileentityfurnace; this.a(new Slot(tileentityfurnace, 0, 56, 17)); this.a(new Slot(tileentityfurnace, 1, 56, 53)); this.a(new SlotResult2(playerinventory.d, tileentityfurnace, 2, 116, 35)); + this.player = playerinventory; // CraftBukkit - save player int i; @@ -58,6 +68,7 @@ public class ContainerFurnace extends Container { } public boolean b(EntityHuman entityhuman) { + if (!this.checkReachable) return true; // CraftBukkit return this.a.a(entityhuman); } @@ -100,4 +111,15 @@ public class ContainerFurnace extends Container { return itemstack; } + + // CraftBukkit start + public CraftInventoryView getBukkitView() { + if (bukkitEntity != null) { + return bukkitEntity; + } + CraftInventoryFurnace inventory = new CraftInventoryFurnace(this.a); + bukkitEntity = new CraftInventoryView(this.player.d.getBukkitEntity(), inventory, this); + return bukkitEntity; + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/ContainerPlayer.java b/src/main/java/net/minecraft/server/ContainerPlayer.java index f5d995e026..fd8bb49519 100644 --- a/src/main/java/net/minecraft/server/ContainerPlayer.java +++ b/src/main/java/net/minecraft/server/ContainerPlayer.java @@ -1,18 +1,29 @@ package net.minecraft.server; +// CraftBukkit start +import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +// CraftBukkit end + public class ContainerPlayer extends Container { public InventoryCrafting craftInventory; public IInventory resultInventory; public boolean c; + // CraftBukkit start + private CraftInventoryView bukkitEntity = null; + private PlayerInventory player; + // CraftBukkit end public ContainerPlayer(PlayerInventory playerinventory) { this(playerinventory, true); } public ContainerPlayer(PlayerInventory playerinventory, boolean flag) { + this.resultInventory = new InventoryCraftResult(); // CraftBukkit - moved to before InventoryCrafting construction this.craftInventory = new InventoryCrafting(this, 2, 2); - this.resultInventory = new InventoryCraftResult(); + this.craftInventory.resultInventory = this.resultInventory; // CraftBukkit - let InventoryCrafting know about its result slot + this.player = playerinventory; // CraftBukkit - save player this.c = false; this.c = flag; this.a((Slot) (new SlotResult(playerinventory.d, this.craftInventory, this.resultInventory, 0, 144, 36))); @@ -40,11 +51,12 @@ public class ContainerPlayer extends Container { this.a(new Slot(playerinventory, i, 8 + i * 18, 142)); } - this.a((IInventory) this.craftInventory); + // this.a((IInventory) this.craftInventory); // CraftBukkit - unneeded since it just sets result slot to empty } public void a(IInventory iinventory) { - // CraftBukkit start + // CraftBukkit start (Note: the following line would cause an error if called during construction) + CraftingManager.getInstance().lastCraftView = getBukkitView(); ItemStack craftResult = CraftingManager.getInstance().craft(this.craftInventory); this.resultInventory.setItem(0, craftResult); if (super.listeners.size() < 1) { @@ -112,4 +124,15 @@ public class ContainerPlayer extends Container { return itemstack; } + + // CraftBukkit start + public CraftInventoryView getBukkitView() { + if (bukkitEntity != null) { + return bukkitEntity; + } + CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftInventory, this.resultInventory); + bukkitEntity = new CraftInventoryView(this.player.d.getBukkitEntity(), inventory, this); + return bukkitEntity; + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/ContainerWorkbench.java b/src/main/java/net/minecraft/server/ContainerWorkbench.java index 46c5c0741b..b007690e9b 100644 --- a/src/main/java/net/minecraft/server/ContainerWorkbench.java +++ b/src/main/java/net/minecraft/server/ContainerWorkbench.java @@ -1,15 +1,30 @@ package net.minecraft.server; +// CraftBukkit start +import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +// CraftBukkit end + public class ContainerWorkbench extends Container { - public InventoryCrafting craftInventory = new InventoryCrafting(this, 3, 3); - public IInventory resultInventory = new InventoryCraftResult(); + public InventoryCrafting craftInventory; // CraftBukkit - move initialization into constructor + public IInventory resultInventory; // CraftBukkit - move initialization into constructor private World c; private int h; private int i; private int j; + // CraftBukkit start + private CraftInventoryView bukkitEntity = null; + private PlayerInventory player; + // CraftBukkit end public ContainerWorkbench(PlayerInventory playerinventory, World world, int i, int j, int k) { + // CraftBukkit start - switched order of IInventory construction and stored player + this.resultInventory = new InventoryCraftResult(); + this.craftInventory = new InventoryCrafting(this, 3, 3); + this.craftInventory.resultInventory = this.resultInventory; + this.player = playerinventory; + // CraftBukkit end this.c = world; this.h = i; this.i = j; @@ -40,6 +55,7 @@ public class ContainerWorkbench extends Container { public void a(IInventory iinventory) { // CraftBukkit start + CraftingManager.getInstance().lastCraftView = getBukkitView(); ItemStack craftResult = CraftingManager.getInstance().craft(this.craftInventory); this.resultInventory.setItem(0, craftResult); if (super.listeners.size() < 1) { @@ -65,6 +81,7 @@ public class ContainerWorkbench extends Container { } public boolean b(EntityHuman entityhuman) { + if (!this.checkReachable) return true; // CraftBukkit return this.c.getTypeId(this.h, this.i, this.j) != Block.WORKBENCH.id ? false : entityhuman.e((double) this.h + 0.5D, (double) this.i + 0.5D, (double) this.j + 0.5D) <= 64.0D; } @@ -107,4 +124,15 @@ public class ContainerWorkbench extends Container { return itemstack; } + + // CraftBukkit start + public CraftInventoryView getBukkitView() { + if (bukkitEntity != null) { + return bukkitEntity; + } + CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftInventory, this.resultInventory); + bukkitEntity = new CraftInventoryView(this.player.d.getBukkitEntity(), inventory, this); + return bukkitEntity; + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/CraftingManager.java b/src/main/java/net/minecraft/server/CraftingManager.java index c785425b16..aff11b01ae 100644 --- a/src/main/java/net/minecraft/server/CraftingManager.java +++ b/src/main/java/net/minecraft/server/CraftingManager.java @@ -4,11 +4,19 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; +// CraftBukkit start +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.inventory.InventoryView; +// CraftBukkit end public class CraftingManager { private static final CraftingManager a = new CraftingManager(); public List b = new ArrayList(); // CraftBukkit - private -> public + // CraftBukkit start + public CraftingRecipe lastRecipe; + public InventoryView lastCraftView; + // CraftBukkit end public static final CraftingManager getInstance() { return a; @@ -218,13 +226,27 @@ public class CraftingManager { j1 = 0; } - return new ItemStack(itemstack.id, 1, j1); + // CraftBukkit start - construct a dummy repair recipe + ItemStack result = new ItemStack(itemstack.id, 1, j1); + List ingredients = new ArrayList(); + ingredients.add(itemstack.cloneItemStack()); + ingredients.add(itemstack1.cloneItemStack()); + ShapelessRecipes recipe = new ShapelessRecipes(result.cloneItemStack(), ingredients); + inventorycrafting.currentRecipe = recipe; + result = CraftEventFactory.callPreCraftEvent(inventorycrafting, result, lastCraftView, true); + return result; + // CraftBukkit end } else { for (j = 0; j < this.b.size(); ++j) { CraftingRecipe craftingrecipe = (CraftingRecipe) this.b.get(j); if (craftingrecipe.a(inventorycrafting)) { - return craftingrecipe.b(inventorycrafting); + // CraftBukkit start - INVENTORY_PRE_CRAFT event + inventorycrafting.currentRecipe = craftingrecipe; + ItemStack result = craftingrecipe.b(inventorycrafting); + result = CraftEventFactory.callPreCraftEvent(inventorycrafting, result, lastCraftView, false); + return result; + // CraftBukkit end } } diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java index 00e32df1c2..6bd0228011 100644 --- a/src/main/java/net/minecraft/server/EntityHuman.java +++ b/src/main/java/net/minecraft/server/EntityHuman.java @@ -7,6 +7,7 @@ import java.util.List; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.entity.CraftItem; import org.bukkit.craftbukkit.TrigMath; +import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.event.entity.EntityCombustByEntityEvent; @@ -261,7 +262,8 @@ public abstract class EntityHuman extends EntityLiving { return this.getHealth() <= 0 || this.isSleeping(); } - protected void closeInventory() { + // CraftBukkit - protected -> public + public void closeInventory() { this.activeContainer = this.defaultContainer; } @@ -1283,4 +1285,10 @@ public abstract class EntityHuman extends EntityLiving { this.exp = entityhuman.exp; this.q = entityhuman.q; } + + // CraftBukkit start + public HumanEntity getBukkitEntity() { + return (HumanEntity) super.getBukkitEntity(); + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/EntityMinecart.java b/src/main/java/net/minecraft/server/EntityMinecart.java index 49e1bf0388..0422308484 100644 --- a/src/main/java/net/minecraft/server/EntityMinecart.java +++ b/src/main/java/net/minecraft/server/EntityMinecart.java @@ -1,9 +1,11 @@ package net.minecraft.server; +// CraftBukkit start +import java.util.ArrayList; import java.util.List; -// CraftBukkit start import org.bukkit.Location; +import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Vehicle; import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.event.vehicle.VehicleDamageEvent; @@ -13,6 +15,8 @@ import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; import org.bukkit.event.vehicle.VehicleMoveEvent; import org.bukkit.event.vehicle.VehicleUpdateEvent; import org.bukkit.util.Vector; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; // CraftBukkit end public class EntityMinecart extends Entity implements IInventory { @@ -40,10 +44,29 @@ public class EntityMinecart extends Entity implements IInventory { private double flyingY = 0.95; private double flyingZ = 0.95; public double maxSpeed = 0.4D; + public List transaction = new ArrayList(); // CraftBukkit public ItemStack[] getContents() { return this.items; } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } + + public InventoryHolder getOwner() { + org.bukkit.entity.Entity cart = getBukkitEntity(); + if(cart instanceof InventoryHolder) return (InventoryHolder) cart; + return null; + } // CraftBukkit end public EntityMinecart(World world) { diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java index 5acd959cb1..b63deb27e3 100644 --- a/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/EntityPlayer.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Set; // CraftBukkit start +import java.util.EnumSet; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.ChunkCompressionThread; import org.bukkit.craftbukkit.CraftWorld; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryType; // CraftBukkit end public class EntityPlayer extends EntityHuman implements ICrafting { @@ -34,6 +36,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { public boolean h; public int ping; public boolean viewingCredits = false; + public int i; public EntityPlayer(MinecraftServer minecraftserver, World world, String s, ItemInWorldManager iteminworldmanager) { super(world); @@ -448,54 +451,85 @@ public class EntityPlayer extends EntityHuman implements ICrafting { super.a(d0, flag); } - private void aS() { + public int aS() { // CraftBukkit - private void -> public int this.cl = this.cl % 100 + 1; + return this.cl; // CraftBukkit } public void b(int i, int j, int k) { + // CraftBukkit start - INVENTORY_OPEN hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerWorkbench(this.inventory, this.world, i, j, k)); + if(container == null) return; + // CraftBukkit end + this.aS(); this.netServerHandler.sendPacket(new Packet100OpenWindow(this.cl, 1, "Crafting", 9)); - this.activeContainer = new ContainerWorkbench(this.inventory, this.world, i, j, k); + this.activeContainer = container; // CraftBukkit - Use container we passed to event this.activeContainer.windowId = this.cl; this.activeContainer.a((ICrafting) this); } public void c(int i, int j, int k) { + // CraftBukkit start - INVENTORY_OPEN hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerEnchantTable(this.inventory, this.world, i, j, k)); + if(container == null) return; + // CraftBukkit end + this.aS(); this.netServerHandler.sendPacket(new Packet100OpenWindow(this.cl, 4, "Enchanting", 9)); - this.activeContainer = new ContainerEnchantTable(this.inventory, this.world, i, j, k); + this.activeContainer = container; this.activeContainer.windowId = this.cl; this.activeContainer.a((ICrafting) this); } public void a(IInventory iinventory) { + // CraftBukkit start - INVENTORY_OPEN hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerChest(this.inventory, iinventory)); + if(container == null) return; + // CraftBukkit end + this.aS(); this.netServerHandler.sendPacket(new Packet100OpenWindow(this.cl, 0, iinventory.getName(), iinventory.getSize())); - this.activeContainer = new ContainerChest(this.inventory, iinventory); + this.activeContainer = container; // CraftBukkit - Use container passed to event this.activeContainer.windowId = this.cl; this.activeContainer.a((ICrafting) this); } public void a(TileEntityFurnace tileentityfurnace) { + // CraftBukkit start - INVENTORY_OPEN hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerFurnace(this.inventory, tileentityfurnace)); + if(container == null) return; + // CraftBukkit end + this.aS(); this.netServerHandler.sendPacket(new Packet100OpenWindow(this.cl, 2, tileentityfurnace.getName(), tileentityfurnace.getSize())); - this.activeContainer = new ContainerFurnace(this.inventory, tileentityfurnace); + this.activeContainer = container; // CraftBukkit - Use container passed to event this.activeContainer.windowId = this.cl; this.activeContainer.a((ICrafting) this); } public void a(TileEntityDispenser tileentitydispenser) { + // CraftBukkit start - INVENTORY_OPEN hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerDispenser(this.inventory, tileentitydispenser)); + if(container == null) return; + // CraftBukkit end + this.aS(); this.netServerHandler.sendPacket(new Packet100OpenWindow(this.cl, 3, tileentitydispenser.getName(), tileentitydispenser.getSize())); - this.activeContainer = new ContainerDispenser(this.inventory, tileentitydispenser); + this.activeContainer = container; // CraftBukkit - Use container passed to event this.activeContainer.windowId = this.cl; this.activeContainer.a((ICrafting) this); } public void a(TileEntityBrewingStand tileentitybrewingstand) { + // CraftBukkit start - INVENTORY_OPEN hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerBrewingStand(this.inventory, tileentitybrewingstand)); + if(container == null) return; + // CraftBukkit end + this.aS(); this.netServerHandler.sendPacket(new Packet100OpenWindow(this.cl, 5, tileentitybrewingstand.getName(), tileentitybrewingstand.getSize())); - this.activeContainer = new ContainerBrewingStand(this.inventory, tileentitybrewingstand); + this.activeContainer = container; this.activeContainer.windowId = this.cl; this.activeContainer.a((ICrafting) this); } @@ -515,6 +549,11 @@ public class EntityPlayer extends EntityHuman implements ICrafting { public void a(Container container, List list) { this.netServerHandler.sendPacket(new Packet104WindowItems(container.windowId, list)); this.netServerHandler.sendPacket(new Packet103SetSlot(-1, -1, this.inventory.l())); + // CraftBukkit start - send a Set Slot to update the crafting result slot + if (EnumSet.of(InventoryType.CRAFTING,InventoryType.WORKBENCH).contains(container.getBukkitView().getType())) { + this.netServerHandler.sendPacket(new Packet103SetSlot(container.windowId, 0, container.b(0).getItem())); + } + // CraftBukkit end } public void a(Container container, int i, int j) { diff --git a/src/main/java/net/minecraft/server/IInventory.java b/src/main/java/net/minecraft/server/IInventory.java index b94ab24aa5..63c3f85659 100644 --- a/src/main/java/net/minecraft/server/IInventory.java +++ b/src/main/java/net/minecraft/server/IInventory.java @@ -1,5 +1,13 @@ package net.minecraft.server; +// CraftBukkit start +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end + public interface IInventory { int getSize(); @@ -22,5 +30,15 @@ public interface IInventory { void g(); - public abstract ItemStack[] getContents(); // CraftBukkit + // CraftBukkit start + ItemStack[] getContents(); + + void onOpen(CraftHumanEntity who); + + void onClose(CraftHumanEntity who); + + List getViewers(); + + InventoryHolder getOwner(); + //CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/InventoryCraftResult.java b/src/main/java/net/minecraft/server/InventoryCraftResult.java index 154b603a46..537f22ae70 100644 --- a/src/main/java/net/minecraft/server/InventoryCraftResult.java +++ b/src/main/java/net/minecraft/server/InventoryCraftResult.java @@ -1,5 +1,14 @@ package net.minecraft.server; +// CraftBukkit start +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end + public class InventoryCraftResult implements IInventory { private ItemStack[] items = new ItemStack[1]; @@ -8,6 +17,16 @@ public class InventoryCraftResult implements IInventory { public ItemStack[] getContents() { return this.items; } + public InventoryHolder getOwner() { + return null; // Result slots don't get an owner + } + + // Don't need a transaction; the InventoryCrafting keeps track of it for us + public void onOpen(CraftHumanEntity who) {} + public void onClose(CraftHumanEntity who) {} + public List getViewers() { + return new ArrayList(); + } // CraftBukkit end public InventoryCraftResult() {} diff --git a/src/main/java/net/minecraft/server/InventoryCrafting.java b/src/main/java/net/minecraft/server/InventoryCrafting.java index 1ed97d7994..1e22c7cccd 100644 --- a/src/main/java/net/minecraft/server/InventoryCrafting.java +++ b/src/main/java/net/minecraft/server/InventoryCrafting.java @@ -1,5 +1,15 @@ package net.minecraft.server; +// CraftBukkit start +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end + public class InventoryCrafting implements IInventory { private ItemStack[] items; @@ -7,9 +17,33 @@ public class InventoryCrafting implements IInventory { private Container c; // CraftBukkit start + public List transaction = new ArrayList(); + public CraftingRecipe currentRecipe; + public IInventory resultInventory; + public ItemStack[] getContents() { return this.items; } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public InventoryType getInvType() { + return items.length == 4 ? InventoryType.CRAFTING : InventoryType.WORKBENCH; + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } + + public InventoryHolder getOwner() { + return null; // TODO: Crafting grids don't really have an owner? Maybe they should? + } // CraftBukkit end public InventoryCrafting(Container container, int i, int j) { diff --git a/src/main/java/net/minecraft/server/InventoryLargeChest.java b/src/main/java/net/minecraft/server/InventoryLargeChest.java index 5090563f77..88cfdcce30 100644 --- a/src/main/java/net/minecraft/server/InventoryLargeChest.java +++ b/src/main/java/net/minecraft/server/InventoryLargeChest.java @@ -1,12 +1,23 @@ package net.minecraft.server; +// CraftBukkit start +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end + public class InventoryLargeChest implements IInventory { private String a; - private IInventory b; - private IInventory c; + public IInventory b; // CraftBukkit - private -> public + public IInventory c; // CraftBukkit - private -> public // CraftBukkit start + public List transaction = new ArrayList(); + public ItemStack[] getContents() { ItemStack[] result = new ItemStack[this.getSize()]; for (int i = 0; i < result.length; i++) { @@ -14,6 +25,26 @@ public class InventoryLargeChest implements IInventory { } return result; } + + public void onOpen(CraftHumanEntity who) { + b.onOpen(who); + c.onOpen(who); + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + b.onClose(who); + c.onClose(who); + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } + + public InventoryHolder getOwner() { + return null; // Double chests technically have multiple owners, so there's no sensible way to pick one + } // CraftBukkit end public InventoryLargeChest(String s, IInventory iinventory, IInventory iinventory1) { diff --git a/src/main/java/net/minecraft/server/NetServerHandler.java b/src/main/java/net/minecraft/server/NetServerHandler.java index d2cd707c98..cf6ecc8519 100644 --- a/src/main/java/net/minecraft/server/NetServerHandler.java +++ b/src/main/java/net/minecraft/server/NetServerHandler.java @@ -9,16 +9,20 @@ import java.util.logging.Logger; // CraftBukkit start import java.util.Arrays; import java.util.HashSet; + import org.bukkit.ChatColor; import org.bukkit.craftbukkit.ChunkCompressionThread; import org.bukkit.Location; import org.bukkit.command.CommandException; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.TextWrapper; +import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.block.Action; @@ -34,6 +38,12 @@ import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.event.player.PlayerToggleSprintEvent; +import org.bukkit.event.Event.Result; +import org.bukkit.event.inventory.*; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.inventory.CraftingInventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.Recipe; // CraftBukkit end public class NetServerHandler extends NetHandler implements ICommandListener { @@ -980,6 +990,12 @@ public class NetServerHandler extends NetHandler implements ICommandListener { public void a(Packet101CloseWindow packet101closewindow) { if (this.player.dead) return; // CraftBukkit + // CraftBukkit start - INVENTORY_CLOSE hook + InventoryCloseEvent event = new InventoryCloseEvent(this.player.activeContainer.getBukkitView()); + server.getPluginManager().callEvent(event); + this.player.activeContainer.transferTo(this.player.defaultContainer, getPlayer()); + // CraftBukkit end + this.player.E(); } @@ -987,10 +1003,53 @@ public class NetServerHandler extends NetHandler implements ICommandListener { if (this.player.dead) return; // CraftBukkit if (this.player.activeContainer.windowId == packet102windowclick.a && this.player.activeContainer.c(this.player)) { - ItemStack itemstack = this.player.activeContainer.a(packet102windowclick.b, packet102windowclick.c, packet102windowclick.f, this.player); + // CraftBukkit start - fire InventoryClickEvent + InventoryView inventory = this.player.activeContainer.getBukkitView(); + SlotType type = CraftInventoryView.getSlotType(inventory, packet102windowclick.b); - if (ItemStack.matches(packet102windowclick.e, itemstack)) { - this.player.netServerHandler.sendPacket(new Packet106Transaction(packet102windowclick.a, packet102windowclick.d, true)); + InventoryClickEvent event; + if (inventory instanceof CraftingInventory) { + Recipe recipe = ((CraftingInventory)inventory.getTopInventory()).getRecipe(); + event = new CraftItemEvent(recipe, inventory, type, packet102windowclick.b, packet102windowclick.c != 0, packet102windowclick.f); + } else { + event = new InventoryClickEvent(inventory, type, packet102windowclick.b, packet102windowclick.c != 0, packet102windowclick.f); + } + server.getPluginManager().callEvent(event); + + ItemStack itemstack = null; + boolean defaultBehaviour = false; + + switch(event.getResult()) { + case DEFAULT: + itemstack = this.player.activeContainer.a(packet102windowclick.b, packet102windowclick.c, packet102windowclick.f, this.player); + defaultBehaviour = true; + break; + case DENY: // Deny any change, including changes from the event + break; + case ALLOW: // Allow changes unconditionally + org.bukkit.inventory.ItemStack cursor = event.getCursor(); + if (cursor == null) { + this.player.inventory.b((ItemStack) null); + } else { + this.player.inventory.b(CraftItemStack.createNMSItemStack(cursor)); + } + org.bukkit.inventory.ItemStack item = event.getCurrentItem(); + if (item != null) { + itemstack = CraftItemStack.createNMSItemStack(item); + if(packet102windowclick.b == -999) { + this.player.b(itemstack); + } else { + this.player.activeContainer.b(packet102windowclick.b).c(itemstack); + } + } else if (packet102windowclick.b != -999) { + this.player.activeContainer.b(packet102windowclick.b).c((ItemStack) null); + } + break; + } + // CraftBukkit end + + if (defaultBehaviour && ItemStack.matches(packet102windowclick.e, itemstack)) { // CraftBukkit - additional condition added + this.player.netServerHandler.sendPacket((Packet) (new Packet106Transaction(packet102windowclick.a, packet102windowclick.d, true))); this.player.h = true; this.player.activeContainer.a(); this.player.D(); @@ -1006,6 +1065,11 @@ public class NetServerHandler extends NetHandler implements ICommandListener { } this.player.a(this.player.activeContainer, arraylist); + + // CraftBukkit start - send a Set Slot to update the crafting result slot + if(type == SlotType.RESULT && itemstack != null) + this.player.netServerHandler.sendPacket((Packet) (new Packet103SetSlot(this.player.activeContainer.windowId, 0, itemstack))); + // CraftBukkit end } } } @@ -1025,17 +1089,46 @@ public class NetServerHandler extends NetHandler implements ICommandListener { boolean flag2 = itemstack == null || itemstack.id < Item.byId.length && itemstack.id >= 0 && Item.byId[itemstack.id] != null && !invalidItems.contains(itemstack.id); // CraftBukkit boolean flag3 = itemstack == null || itemstack.getData() >= 0 && itemstack.getData() >= 0 && itemstack.count <= 64 && itemstack.count > 0; - if (flag1 && flag2 && flag3) { - if (itemstack == null) { - this.player.defaultContainer.a(packet107setcreativeslot.a, (ItemStack) null); - } else { - this.player.defaultContainer.a(packet107setcreativeslot.a, itemstack); - } - - this.player.defaultContainer.a(this.player, true); - } else if (flag && flag2 && flag3) { - this.player.b(itemstack); + // CraftBukkit start - Fire INVENTORY_CLICK event + HumanEntity player = this.player.getBukkitEntity(); + InventoryView inventory = new CraftInventoryView(player, player.getInventory(), this.player.defaultContainer); + SlotType slot = SlotType.QUICKBAR; + if (packet107setcreativeslot.a == -1) { + slot = SlotType.OUTSIDE; } + InventoryClickEvent event = new InventoryClickEvent(inventory, slot, slot == SlotType.OUTSIDE ? -999 : packet107setcreativeslot.a, false, false); + server.getPluginManager().callEvent(event); + org.bukkit.inventory.ItemStack item = event.getCurrentItem(); + if (event.getResult() == Result.ALLOW) { + if (slot == SlotType.QUICKBAR) { + if (item == null) { + this.player.defaultContainer.a(packet107setcreativeslot.a, (ItemStack) null); + } else { + this.player.defaultContainer.a(packet107setcreativeslot.a, CraftItemStack.createNMSItemStack(item)); + } + } else if (item != null) { + this.player.b(CraftItemStack.createNMSItemStack(item)); + } + } else if (event.getResult() == Result.DENY) { + // TODO: Will this actually work? + if (packet107setcreativeslot.a > -1) { + this.player.netServerHandler.sendPacket(new Packet103SetSlot(this.player.defaultContainer.windowId, packet107setcreativeslot.a, CraftItemStack.createNMSItemStack(item))); + } + this.player.netServerHandler.sendPacket(new Packet103SetSlot(this.player.defaultContainer.windowId, -1, null)); + } else if (event.getResult() == Result.DEFAULT) { + // CraftBukkit end + if (flag1 && flag2 && flag3) { + if (itemstack == null) { + this.player.defaultContainer.a(packet107setcreativeslot.a, (ItemStack) null); + } else { + this.player.defaultContainer.a(packet107setcreativeslot.a, itemstack); + } + + this.player.defaultContainer.a(this.player, true); + } else if (flag && flag2 && flag3) { + this.player.b(itemstack); + } + } // CraftBukkit closing brace } } @@ -1152,4 +1245,4 @@ public class NetServerHandler extends NetHandler implements ICommandListener { } } // CraftBukkit end -} \ No newline at end of file +} diff --git a/src/main/java/net/minecraft/server/Packet.java b/src/main/java/net/minecraft/server/Packet.java index 5f425338dd..930acd410a 100644 --- a/src/main/java/net/minecraft/server/Packet.java +++ b/src/main/java/net/minecraft/server/Packet.java @@ -157,7 +157,7 @@ public abstract class Packet { } protected void a(ItemStack itemstack, DataOutputStream dataoutputstream) throws IOException { // CraftBukkit - if (itemstack == null) { + if (itemstack == null || itemstack.id <= 0) { dataoutputstream.writeShort(-1); } else { dataoutputstream.writeShort(itemstack.id); diff --git a/src/main/java/net/minecraft/server/PlayerInventory.java b/src/main/java/net/minecraft/server/PlayerInventory.java index dda79ed3e2..98116eb3b0 100644 --- a/src/main/java/net/minecraft/server/PlayerInventory.java +++ b/src/main/java/net/minecraft/server/PlayerInventory.java @@ -1,5 +1,14 @@ package net.minecraft.server; +// CraftBukkit start +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end + public class PlayerInventory implements IInventory { public ItemStack[] items = new ItemStack[36]; @@ -10,6 +19,8 @@ public class PlayerInventory implements IInventory { public boolean e = false; // CraftBukkit start + public List transaction = new ArrayList(); + public ItemStack[] getContents() { return this.items; } @@ -17,6 +28,22 @@ public class PlayerInventory implements IInventory { public ItemStack[] getArmorContents() { return this.armor; } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } + + public InventoryHolder getOwner() { + return d.getBukkitEntity(); + } // CraftBukkit end public PlayerInventory(EntityHuman entityhuman) { diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java index da9b4913c4..18095d2a4a 100644 --- a/src/main/java/net/minecraft/server/TileEntity.java +++ b/src/main/java/net/minecraft/server/TileEntity.java @@ -3,6 +3,11 @@ package net.minecraft.server; import java.util.HashMap; import java.util.Map; +// CraftBukkit start +import org.bukkit.block.BlockState; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end + public class TileEntity { private static Map a = new HashMap(); @@ -120,4 +125,12 @@ public class TileEntity { a(TileEntityEnchantTable.class, "EnchantTable"); a(TileEntityEnderPortal.class, "Airportal"); } + + // CraftBukkit start + public InventoryHolder getOwner() { + BlockState state = world.getWorld().getBlockAt(x, y, z).getState(); + if(state instanceof InventoryHolder) return (InventoryHolder) state; + return null; + } + // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/TileEntityBrewingStand.java b/src/main/java/net/minecraft/server/TileEntityBrewingStand.java index 328dafa60d..466b65eb42 100644 --- a/src/main/java/net/minecraft/server/TileEntityBrewingStand.java +++ b/src/main/java/net/minecraft/server/TileEntityBrewingStand.java @@ -2,6 +2,16 @@ package net.minecraft.server; import java.util.List; +// CraftBukkit start +import java.util.ArrayList; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.BrewEvent; +import org.bukkit.inventory.BrewerInventory; +// CraftBukkit end + public class TileEntityBrewingStand extends TileEntity implements IInventory { public ItemStack[] a = new ItemStack[4]; // CraftBukkit private -> public @@ -12,6 +22,20 @@ public class TileEntityBrewingStand extends TileEntity implements IInventory { public TileEntityBrewingStand() {} // CraftBukkit start + public List transaction = new ArrayList(); + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } + public ItemStack[] getContents() { return this.a; } @@ -97,6 +121,12 @@ public class TileEntityBrewingStand extends TileEntity implements IInventory { if (this.o()) { ItemStack itemstack = this.a[3]; + // CraftBukkit start - fire BREW event + BrewEvent event = new BrewEvent(world.getWorld().getBlockAt(x, y, z), (BrewerInventory) this.getOwner().getInventory()); + Bukkit.getPluginManager().callEvent(event); + if(event.isCancelled()) return; + // CraftBukkit end + for (int i = 0; i < 3; ++i) { if (this.a[i] != null && this.a[i].id == Item.POTION.id) { int j = this.a[i].getData(); diff --git a/src/main/java/net/minecraft/server/TileEntityChest.java b/src/main/java/net/minecraft/server/TileEntityChest.java index 17e3e236d2..1bae497658 100644 --- a/src/main/java/net/minecraft/server/TileEntityChest.java +++ b/src/main/java/net/minecraft/server/TileEntityChest.java @@ -1,5 +1,13 @@ package net.minecraft.server; +// CraftBukkit start +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +// CraftBukkit end + public class TileEntityChest extends TileEntity implements IInventory { private ItemStack[] items = new ItemStack[27]; // CraftBukkit @@ -14,9 +22,23 @@ public class TileEntityChest extends TileEntity implements IInventory { private int ticks; // CraftBukkit start + public List transaction = new ArrayList(); + public ItemStack[] getContents() { return this.items; } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } // CraftBukkit end public TileEntityChest() {} diff --git a/src/main/java/net/minecraft/server/TileEntityDispenser.java b/src/main/java/net/minecraft/server/TileEntityDispenser.java index 25c9b23cc5..7608aae8e9 100644 --- a/src/main/java/net/minecraft/server/TileEntityDispenser.java +++ b/src/main/java/net/minecraft/server/TileEntityDispenser.java @@ -2,15 +2,37 @@ package net.minecraft.server; import java.util.Random; +// CraftBukkit start +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +// CraftBukkit end + public class TileEntityDispenser extends TileEntity implements IInventory { private ItemStack[] items = new ItemStack[9]; private Random b = new Random(); // CraftBukkit start + public List transaction = new ArrayList(); + public ItemStack[] getContents() { return this.items; } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } // CraftBukkit end public TileEntityDispenser() {} diff --git a/src/main/java/net/minecraft/server/TileEntityFurnace.java b/src/main/java/net/minecraft/server/TileEntityFurnace.java index 6aac0de198..f6f951c74a 100644 --- a/src/main/java/net/minecraft/server/TileEntityFurnace.java +++ b/src/main/java/net/minecraft/server/TileEntityFurnace.java @@ -1,9 +1,16 @@ package net.minecraft.server; // CraftBukkit start +import java.util.ArrayList; +import java.util.List; + import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; // CraftBukkit end public class TileEntityFurnace extends TileEntity implements IInventory { @@ -15,10 +22,23 @@ public class TileEntityFurnace extends TileEntity implements IInventory { // CraftBukkit start private int lastTick = (int) (System.currentTimeMillis() / 50); + public List transaction = new ArrayList(); public ItemStack[] getContents() { return this.items; } + + public void onOpen(CraftHumanEntity who) { + transaction.add(who); + } + + public void onClose(CraftHumanEntity who) { + transaction.remove(who); + } + + public List getViewers() { + return transaction; + } // CraftBukkit end public TileEntityFurnace() {} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 94204e40fa..8bb40a5578 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -59,6 +59,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.serialization.ConfigurationSerialization; import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe; +import org.bukkit.craftbukkit.inventory.CraftInventoryCustom; import org.bukkit.craftbukkit.inventory.CraftRecipe; import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe; @@ -74,6 +75,7 @@ import org.bukkit.craftbukkit.updater.BukkitDLUpdaterService; import org.bukkit.craftbukkit.util.DatFileFilter; import org.bukkit.craftbukkit.util.Versioning; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldSaveEvent; @@ -81,6 +83,8 @@ import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.FurnaceRecipe; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapelessRecipe; @@ -105,6 +109,7 @@ import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.error.MarkedYAMLException; +import org.apache.commons.lang.Validate; import com.avaje.ebean.config.DataSourceConfig; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.SQLitePlatform; @@ -1102,4 +1107,19 @@ public final class CraftServer implements Server { } } } + + public Inventory createInventory(InventoryHolder owner, InventoryType type) { + // TODO: Create the appropriate type, rather than Custom? + return new CraftInventoryCustom(owner, type); + } + + public Inventory createInventory(InventoryHolder owner, int size) throws IllegalArgumentException { + Validate.isTrue(size % 9 == 0, "Chests must have a size that is a multiple of 9!"); + return new CraftInventoryCustom(owner, size); + } + + public Inventory createInventory(InventoryHolder owner, int size, String title) throws IllegalArgumentException { + Validate.isTrue(size % 9 == 0, "Chests must have a size that is a multiple of 9!"); + return new CraftInventoryCustom(owner, size, title); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java index 55b2d49efd..f1d6196449 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java @@ -4,8 +4,8 @@ import net.minecraft.server.TileEntityBrewingStand; import org.bukkit.block.Block; import org.bukkit.block.BrewingStand; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.inventory.CraftInventory; -import org.bukkit.inventory.Inventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryBrewer; +import org.bukkit.inventory.BrewerInventory; public class CraftBrewingStand extends CraftBlockState implements BrewingStand { private final CraftWorld world; @@ -18,8 +18,8 @@ public class CraftBrewingStand extends CraftBlockState implements BrewingStand { brewingStand = (TileEntityBrewingStand) world.getTileEntityAt(getX(), getY(), getZ()); } - public Inventory getInventory() { - return new CraftInventory(brewingStand); + public BrewerInventory getInventory() { + return new CraftInventoryBrewer(brewingStand); } @Override diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java index f5f7fa6aa8..7ccfa80e4c 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java @@ -1,10 +1,13 @@ package org.bukkit.craftbukkit.block; import net.minecraft.server.TileEntityChest; + +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Chest; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest; import org.bukkit.inventory.Inventory; public class CraftChest extends CraftBlockState implements Chest { @@ -19,7 +22,26 @@ public class CraftChest extends CraftBlockState implements Chest { } public Inventory getInventory() { - return new CraftInventory(chest); + // The logic here is basically identical to the logic in BlockChest.interact + int x = getLocation().getBlockX(), y = getLocation().getBlockY(), z = getLocation().hashCode(); + CraftInventory inventory = new CraftInventory(chest); + if (world.getBlockTypeIdAt(x - 1, y, z) == Material.CHEST.getId()) { + CraftInventory left = new CraftInventory((TileEntityChest)world.getHandle().getTileEntity(x - 1, y, z)); + inventory = new CraftInventoryDoubleChest(left, inventory); + } + if (world.getBlockTypeIdAt(x + 1, y, z) == Material.CHEST.getId()) { + CraftInventory right = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(x + 1, y, z)); + inventory = new CraftInventoryDoubleChest(inventory, right); + } + if (world.getBlockTypeIdAt(x, y, z - 1) == Material.CHEST.getId()) { + CraftInventory left = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(x, y, z - 1)); + inventory = new CraftInventoryDoubleChest(left, inventory); + } + if (world.getBlockTypeIdAt(x, y, z + 1) == Material.CHEST.getId()) { + CraftInventory right = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(x, y, z + 1)); + inventory = new CraftInventoryDoubleChest(inventory, right); + } + return inventory; } @Override diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java index dcf0fe1b0f..e4756dcd2b 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java @@ -4,8 +4,8 @@ import net.minecraft.server.TileEntityFurnace; import org.bukkit.block.Block; import org.bukkit.block.Furnace; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.inventory.CraftInventory; -import org.bukkit.inventory.Inventory; +import org.bukkit.craftbukkit.inventory.CraftInventoryFurnace; +import org.bukkit.inventory.FurnaceInventory; public class CraftFurnace extends CraftBlockState implements Furnace { private final CraftWorld world; @@ -18,8 +18,8 @@ public class CraftFurnace extends CraftBlockState implements Furnace { furnace = (TileEntityFurnace) world.getTileEntityAt(getX(), getY(), getZ()); } - public Inventory getInventory() { - return new CraftInventory(furnace); + public FurnaceInventory getInventory() { + return new CraftInventoryFurnace(furnace); } @Override diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 7b5b37ca8e..55163f7a5e 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -1,12 +1,33 @@ package org.bukkit.craftbukkit.entity; import java.util.Set; + +import net.minecraft.server.Container; import net.minecraft.server.EntityHuman; +import net.minecraft.server.EntityPlayer; +import net.minecraft.server.ICrafting; +import net.minecraft.server.Packet100OpenWindow; +import net.minecraft.server.Packet101CloseWindow; +import net.minecraft.server.TileEntityBrewingStand; +import net.minecraft.server.TileEntityDispenser; +import net.minecraft.server.TileEntityFurnace; + import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.inventory.CraftContainer; +import org.bukkit.craftbukkit.inventory.CraftInventory; import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; +import org.bukkit.craftbukkit.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.permissions.PermissibleBase; import org.bukkit.permissions.Permission; @@ -42,6 +63,18 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { getInventory().setItemInHand(item); } + public ItemStack getItemOnCursor() { + return new CraftItemStack(getHandle().inventory.l()); + } + + public void setItemOnCursor(ItemStack item) { + CraftItemStack stack = new CraftItemStack(item.getType(), item.getAmount(), item.getDurability()); + getHandle().inventory.b(stack.getHandle()); + if (this instanceof CraftPlayer) { + ((EntityPlayer)getHandle()).D(); // Send set slot for cursor + } + } + public boolean isSleeping() { return getHandle().sleeping; } @@ -129,4 +162,111 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { public String toString() { return "CraftHumanEntity{" + "id=" + getEntityId() + "name=" + getName() + '}'; } + + public InventoryView getOpenInventory() { + return getHandle().activeContainer.getBukkitView(); + } + + public InventoryView openInventory(Inventory inventory) { + InventoryType type = inventory.getType(); + // TODO: Should we check that it really IS a CraftInventory first? + CraftInventory craftinv = (CraftInventory) inventory; + switch(type) { + case PLAYER: + case CHEST: + getHandle().a(craftinv.getInventory()); + break; + case DISPENSER: + getHandle().a((TileEntityDispenser)craftinv.getInventory()); + break; + case FURNACE: + getHandle().a((TileEntityFurnace)craftinv.getInventory()); + break; + case WORKBENCH: + getHandle().b(getLocation().getBlockX(), getLocation().getBlockY(), getLocation().getBlockZ()); + break; + case BREWING: + getHandle().a((TileEntityBrewingStand)craftinv.getInventory()); + break; + case ENCHANTING: + getHandle().c(getLocation().getBlockX(), getLocation().getBlockY(), getLocation().getBlockZ()); + break; + case CREATIVE: + case CRAFTING: + throw new IllegalArgumentException("Can't open a " + type + " inventory!"); + } + getHandle().activeContainer.checkReachable = false; + return getHandle().activeContainer.getBukkitView(); + } + + public InventoryView openWorkbench(Location location, boolean force) { + if (!force) { + Block block = location.getBlock(); + if (block.getType() != Material.WORKBENCH) { + return null; + } + } + if (location == null) { + location = getLocation(); + } + getHandle().b(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + if (force) { + getHandle().activeContainer.checkReachable = false; + } + return getHandle().activeContainer.getBukkitView(); + } + + public InventoryView openEnchanting(Location location, boolean force) { + if (!force) { + Block block = location.getBlock(); + if (block.getType() != Material.ENCHANTMENT_TABLE) { + return null; + } + } + if (location == null) { + location = getLocation(); + } + getHandle().c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + if (force) { + getHandle().activeContainer.checkReachable = false; + } + return getHandle().activeContainer.getBukkitView(); + } + + public void openInventory(InventoryView inventory) { + if (!(getHandle() instanceof EntityPlayer)) return; // TODO: NPC support? + if (getHandle().activeContainer != getHandle().defaultContainer) { + // fire INVENTORY_CLOSE if one already open + ((EntityPlayer)getHandle()).netServerHandler.a(new Packet101CloseWindow(getHandle().activeContainer.windowId)); + } + EntityPlayer player = (EntityPlayer) getHandle(); + Container container; + if (inventory instanceof CraftInventoryView) { + container = ((CraftInventoryView) inventory).getHandle(); + } else { + container = new CraftContainer(inventory, player.aS()); + } + + // Trigger an INVENTORY_OPEN event + InventoryOpenEvent event = new InventoryOpenEvent(inventory); + player.activeContainer.transferTo(container, this); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) { + container.transferTo(player.activeContainer, this); + return; + } + + // Now open the window + player.netServerHandler.sendPacket(new Packet100OpenWindow(container.windowId, 1, "Crafting", 9)); + player.activeContainer = container; + player.activeContainer.a((ICrafting) player); + } + + public void closeInventory() { + getHandle().closeInventory(); + } + + public boolean setWindowProperty(InventoryView.Property prop, int value) { + return false; + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 0be3c7e28f..417a5ed958 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -17,6 +17,20 @@ import net.minecraft.server.*; import org.apache.commons.lang.Validate; import org.bukkit.*; + +import net.minecraft.server.Container; +import net.minecraft.server.EntityPlayer; +import net.minecraft.server.Packet131ItemData; +import net.minecraft.server.Packet200Statistic; +import net.minecraft.server.Packet201PlayerInfo; +import net.minecraft.server.Packet3Chat; +import net.minecraft.server.Packet51MapChunk; +import net.minecraft.server.Packet53BlockChange; +import net.minecraft.server.Packet54PlayNoteBlock; +import net.minecraft.server.Packet61WorldEvent; +import net.minecraft.server.Packet6SpawnPosition; +import net.minecraft.server.Packet70Bed; +import net.minecraft.server.WorldServer; import org.bukkit.Achievement; import org.bukkit.Material; import org.bukkit.Statistic; @@ -33,6 +47,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.InventoryView.Property; import org.bukkit.map.MapView; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; @@ -742,4 +757,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public void removeMetadata(String metadataKey, Plugin owningPlugin) { server.getPlayerMetadata().removeMetadata(this, metadataKey, owningPlugin); } + + @Override + public boolean setWindowProperty(Property prop, int value) { + Container container = getHandle().activeContainer; + if (container.getBukkitView().getType() != prop.getType()) { + return false; + } + getHandle().a(container, prop.getId(), value); + return true; + } } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 131056522b..bcadbce4dc 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import net.minecraft.server.ChunkCoordinates; +import net.minecraft.server.Container; import net.minecraft.server.DamageSource; import net.minecraft.server.Entity; import net.minecraft.server.EntityArrow; @@ -15,8 +16,10 @@ import net.minecraft.server.EntityItem; import net.minecraft.server.EntityLiving; import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityPotion; +import net.minecraft.server.InventoryCrafting; import net.minecraft.server.Item; import net.minecraft.server.ItemStack; +import net.minecraft.server.Packet101CloseWindow; import net.minecraft.server.World; import net.minecraft.server.WorldServer; @@ -32,6 +35,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.entity.CraftLivingEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.AnimalTamer; import org.bukkit.entity.Arrow; @@ -47,8 +51,11 @@ import org.bukkit.event.block.*; import org.bukkit.event.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.inventory.PrepareItemCraftEvent; import org.bukkit.event.player.*; import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.inventory.InventoryView; public class CraftEventFactory { // helper methods @@ -413,4 +420,36 @@ public class CraftEventFactory { entity.getBukkitEntity().getServer().getPluginManager().callEvent(event); return event; } + + public static Container callInventoryOpenEvent(EntityPlayer player, Container container) { + if (player.activeContainer != player.defaultContainer) { // fire INVENTORY_CLOSE if one already open + player.netServerHandler.a(new Packet101CloseWindow(player.activeContainer.windowId)); + } + + CraftServer server = ((WorldServer) player.world).getServer(); + CraftPlayer craftPlayer = (CraftPlayer) player.getBukkitEntity(); + player.activeContainer.transferTo(container, craftPlayer); + + InventoryOpenEvent event = new InventoryOpenEvent(container.getBukkitView()); + server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + container.transferTo(player.activeContainer, craftPlayer); + return null; + } + + return container; + } + + public static ItemStack callPreCraftEvent(InventoryCrafting matrix, ItemStack result, InventoryView lastCraftView, boolean isRepair) { + CraftInventoryCrafting inventory = new CraftInventoryCrafting(matrix, matrix.resultInventory); + inventory.setResult(new CraftItemStack(result)); + + PrepareItemCraftEvent event = new PrepareItemCraftEvent(inventory, lastCraftView, isRepair); + Bukkit.getPluginManager().callEvent(event); + + org.bukkit.inventory.ItemStack bitem = event.getInventory().getResult(); + + return CraftItemStack.createNMSItemStack(bitem); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java new file mode 100644 index 0000000000..e60ddb718c --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java @@ -0,0 +1,228 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryView; + +import net.minecraft.server.Container; +import net.minecraft.server.EntityHuman; +import net.minecraft.server.IInventory; +import net.minecraft.server.Packet100OpenWindow; +import net.minecraft.server.Slot; + +public class CraftContainer extends Container { + InventoryView view; + InventoryType cachedType; + + public CraftContainer(InventoryView view, int id) { + this.view = view; + this.windowId = id; + // TODO: Do we need to check that it really is a CraftInventory? + IInventory top = ((CraftInventory)view.getTopInventory()).getInventory(); + IInventory bottom = ((CraftInventory)view.getBottomInventory()).getInventory(); + cachedType = view.getType(); + setupSlots(top, bottom); + } + + @Override + public InventoryView getBukkitView() { + return view; + } + + @Override + public boolean b(EntityHuman entityhuman) { + if (cachedType == view.getType()) { + return true; + } + // If the window type has changed for some reason, update the player + // This method will be called every tick or something, so it's + // as good a place as any to put something like this. + cachedType = view.getType(); + if (view.getPlayer() instanceof CraftPlayer) { + CraftPlayer player = (CraftPlayer) view.getPlayer(); + int type; + switch(cachedType) { + case WORKBENCH: + type = 1; + break; + case FURNACE: + type = 2; + break; + case DISPENSER: + type = 3; + break; + default: + type = 0; + break; + } + IInventory top = ((CraftInventory)view.getTopInventory()).getInventory(); + IInventory bottom = ((CraftInventory)view.getBottomInventory()).getInventory(); + this.d.clear(); + this.e.clear(); + setupSlots(top, bottom); + player.getHandle().netServerHandler.sendPacket(new Packet100OpenWindow(this.windowId, type, "Crafting", 9)); + player.updateInventory(); + } + return true; + } + + private void setupSlots(IInventory top, IInventory bottom) { + switch(cachedType) { + case CREATIVE: + break; // TODO: This should be an error? + case PLAYER: + case CHEST: + setupChest(top, bottom); + break; + case DISPENSER: + setupDispenser(top, bottom); + break; + case FURNACE: + setupFurnace(top, bottom); + break; + case CRAFTING: // TODO: This should be an error? + case WORKBENCH: + setupWorkbench(top, bottom); + break; + case ENCHANTING: + setupEnchanting(top, bottom); + break; + case BREWING: + setupBrewing(top, bottom); + break; + } + } + + private void setupChest(IInventory top, IInventory bottom) { + int rows = top.getSize() / 9; + int row; + int col; + // This code copied from ContainerChest + int i = (rows - 4) * 18; + for (row = 0; row < rows; ++row) { + for (col = 0; col < 9; ++col) { + this.a(new Slot(top, col + row * 9, 8 + col * 18, 18 + row * 18)); + } + } + + for (row = 0; row < 3; ++row) { + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col + row * 9 + 9, 8 + col * 18, 103 + row * 18 + i)); + } + } + + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col, 8 + col * 18, 161 + i)); + } + // End copy from ContainerChest + } + + private void setupWorkbench(IInventory top, IInventory bottom) { + // This code copied from ContainerWorkbench + this.a(new Slot(top, 0, 124, 35)); + + int row; + int col; + + for (row = 0; row < 3; ++row) { + for (col = 0; col < 3; ++col) { + this.a(new Slot(top, 1 + col + row * 3, 30 + col * 18, 17 + row * 18)); + } + } + + for (row = 0; row < 3; ++row) { + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col + row * 9 + 9, 8 + col * 18, 84 + row * 18)); + } + } + + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col, 8 + col * 18, 142)); + } + // End copy from ContainerWorkbench + } + + private void setupFurnace(IInventory top, IInventory bottom) { + // This code copied from ContainerFurnace + this.a(new Slot(top, 0, 56, 17)); + this.a(new Slot(top, 1, 56, 53)); + this.a(new Slot(top, 2, 116, 35)); + + int row; + int col; + + for (row = 0; row < 3; ++row) { + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col + row * 9 + 9, 8 + col * 18, 84 + row * 18)); + } + } + + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col, 8 + col * 18, 142)); + } + // End copy from ContainerFurnace + } + + private void setupDispenser(IInventory top, IInventory bottom) { + // This code copied from ContainerDispenser + int row; + int col; + + for (row = 0; row < 3; ++row) { + for (col = 0; col < 3; ++col) { + this.a(new Slot(top, col + row * 3, 61 + col * 18, 17 + row * 18)); + } + } + + for (row = 0; row < 3; ++row) { + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col + row * 9 + 9, 8 + col * 18, 84 + row * 18)); + } + } + + for (col = 0; col < 9; ++col) { + this.a(new Slot(bottom, col, 8 + col * 18, 142)); + } + // End copy from ContainerDispenser + } + + private void setupEnchanting(IInventory top, IInventory bottom) { + // This code copied from ContainerEnchantTable + this.a((new Slot(top, 0, 25, 47))); + + int row; + + for (row = 0; row < 3; ++row) { + for (int i1 = 0; i1 < 9; ++i1) { + this.a(new Slot(bottom, i1 + row * 9 + 9, 8 + i1 * 18, 84 + row * 18)); + } + } + + for (row = 0; row < 9; ++row) { + this.a(new Slot(bottom, row, 8 + row * 18, 142)); + } + // End copy from ContainerEnchantTable + } + + private void setupBrewing(IInventory top, IInventory bottom) { + // This code copied from ContainerBrewingStand + this.a(new Slot(top, 0, 56, 46)); + this.a(new Slot(top, 1, 79, 53)); + this.a(new Slot(top, 2, 102, 46)); + this.a(new Slot(top, 3, 79, 17)); + + int i; + + for (i = 0; i < 3; ++i) { + for (int j = 0; j < 9; ++j) { + this.a(new Slot(bottom, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + } + } + + for (i = 0; i < 9; ++i) { + this.a(new Slot(bottom, i, 8 + i * 18, 142)); + } + // End copy from ContainerBrewingStand + } + +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java index 385a6fc993..79731c50ae 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java @@ -1,13 +1,26 @@ package org.bukkit.craftbukkit.inventory; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import net.minecraft.server.ContainerEnchantTableInventory; import net.minecraft.server.IInventory; +import net.minecraft.server.InventoryCrafting; +import net.minecraft.server.PlayerInventory; +import net.minecraft.server.TileEntityBrewingStand; +import net.minecraft.server.TileEntityDispenser; +import net.minecraft.server.TileEntityFurnace; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.Material; -public class CraftInventory implements org.bukkit.inventory.Inventory { +public class CraftInventory implements Inventory { protected IInventory inventory; public CraftInventory(IInventory inventory) { @@ -27,7 +40,8 @@ public class CraftInventory implements org.bukkit.inventory.Inventory { } public ItemStack getItem(int index) { - return new CraftItemStack(getInventory().getItem(index)); + net.minecraft.server.ItemStack item = getInventory().getItem(index); + return item == null ? null : new CraftItemStack(item); } public ItemStack[] getContents() { @@ -42,18 +56,17 @@ public class CraftInventory implements org.bukkit.inventory.Inventory { } public void setContents(ItemStack[] items) { - if (getInventory().getContents().length != items.length) { - throw new IllegalArgumentException("Invalid inventory size; expected " + getInventory().getContents().length); + if (getInventory().getContents().length < items.length) { + throw new IllegalArgumentException("Invalid inventory size; expected " + getInventory().getContents().length + " or less"); } net.minecraft.server.ItemStack[] mcItems = getInventory().getContents(); - for (int i = 0; i < items.length; i++) { - ItemStack item = items[i]; - if (item == null || item.getTypeId() <= 0) { + for (int i = 0; i < mcItems.length; i++) { + if (i >= items.length) { mcItems[i] = null; } else { - mcItems[i] = CraftItemStack.createNMSItemStack(item); + mcItems[i] = CraftItemStack.createNMSItemStack(items[i]); } } } @@ -363,4 +376,40 @@ public class CraftInventory implements org.bukkit.inventory.Inventory { clear(i); } } + + public ListIterator iterator() { + return new InventoryIterator(this); + } + + public List getViewers() { + return this.inventory.getViewers(); + } + + public String getTitle() { + return inventory.getName(); + } + + public InventoryType getType() { + if (inventory instanceof InventoryCrafting) { + return inventory.getSize() >= 9 ? InventoryType.WORKBENCH : InventoryType.CRAFTING; + } else if (inventory instanceof PlayerInventory) { + return InventoryType.PLAYER; + } else if (inventory instanceof TileEntityDispenser) { + return InventoryType.DISPENSER; + } else if (inventory instanceof TileEntityFurnace) { + return InventoryType.FURNACE; + } else if (inventory instanceof ContainerEnchantTableInventory) { + return InventoryType.ENCHANTING; + } else if (inventory instanceof TileEntityBrewingStand) { + return InventoryType.BREWING; + } else if (inventory instanceof CraftInventoryCustom.MinecraftInventory) { + return ((CraftInventoryCustom.MinecraftInventory) inventory).getType(); + } else { + return InventoryType.CHEST; + } + } + + public InventoryHolder getHolder() { + return inventory.getOwner(); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryBrewer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryBrewer.java new file mode 100644 index 0000000000..6de6e6e6cf --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryBrewer.java @@ -0,0 +1,26 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.block.BrewingStand; +import org.bukkit.inventory.BrewerInventory; +import org.bukkit.inventory.ItemStack; + +import net.minecraft.server.IInventory; + +public class CraftInventoryBrewer extends CraftInventory implements BrewerInventory { + public CraftInventoryBrewer(IInventory inventory) { + super(inventory); + } + + public ItemStack getIngredient() { + return getItem(3); + } + + public void setIngredient(ItemStack ingredient) { + setItem(3, ingredient); + } + + @Override + public BrewingStand getHolder() { + return (BrewingStand) inventory.getOwner(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java new file mode 100644 index 0000000000..e827bc6031 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java @@ -0,0 +1,139 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; + +import net.minecraft.server.CraftingRecipe; +import net.minecraft.server.IInventory; +import net.minecraft.server.InventoryCrafting; + +import org.bukkit.inventory.CraftingInventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; + +public class CraftInventoryCrafting extends CraftInventory implements CraftingInventory { + private IInventory resultInventory; + + public CraftInventoryCrafting(InventoryCrafting inventory, IInventory resultInventory) { + super(inventory); + this.resultInventory = resultInventory; + } + + public IInventory getResultInventory() { + return inventory; + } + + public IInventory getMatrixInventory() { + return resultInventory; + } + + @Override + public int getSize() { + return getResultInventory().getSize() + getMatrixInventory().getSize(); + } + + @Override + public void setContents(ItemStack[] items) { + int resultLen = getResultInventory().getContents().length; + int len = getMatrixInventory().getContents().length + resultLen; + if (len > items.length) { + throw new IllegalArgumentException("Invalid inventory size; expected " + len + " or less"); + } + setContents(items[0], Arrays.copyOfRange(items, 1, items.length)); + } + + @Override + public CraftItemStack[] getContents() { + CraftItemStack[] items = new CraftItemStack[getSize()]; + net.minecraft.server.ItemStack[] mcResultItems = getResultInventory().getContents(); + + int i = 0; + for (i = 0; i < mcResultItems.length; i++ ) { + items[i] = new CraftItemStack(mcResultItems[i]); + } + + net.minecraft.server.ItemStack[] mcItems = getMatrixInventory().getContents(); + + for (int j = 0; j < mcItems.length; j++) { + items[i + j] = new CraftItemStack(mcItems[j]); + } + + return items; + } + + public void setContents(ItemStack result, ItemStack[] contents) { + setResult(result); + setMatrix(contents); + } + + @Override + public CraftItemStack getItem(int index) { + if (index < getResultInventory().getSize()) { + net.minecraft.server.ItemStack item = getResultInventory().getItem(index); + return item == null ? null : new CraftItemStack(item); + } else { + net.minecraft.server.ItemStack item = getMatrixInventory().getItem(index - getResultInventory().getSize()); + return item == null ? null : new CraftItemStack(item); + } + } + + @Override + public void setItem(int index, ItemStack item) { + if (index < getResultInventory().getSize()) { + getResultInventory().setItem(index, (item == null ? null : CraftItemStack.createNMSItemStack(item))); + } else { + getMatrixInventory().setItem((index - getResultInventory().getSize()), (item == null ? null : CraftItemStack.createNMSItemStack(item))); + } + } + + public ItemStack[] getMatrix() { + CraftItemStack[] items = new CraftItemStack[getSize()]; + net.minecraft.server.ItemStack[] matrix = getMatrixInventory().getContents(); + + for (int i = 0; i < matrix.length; i++ ) { + items[i] = new CraftItemStack(matrix[i]); + } + + return items; + } + + public ItemStack getResult() { + net.minecraft.server.ItemStack item = getResultInventory().getItem(0); + if(item != null) return new CraftItemStack(item); + return null; + } + + public void setMatrix(ItemStack[] contents) { + if (getMatrixInventory().getContents().length > contents.length) { + throw new IllegalArgumentException("Invalid inventory size; expected " + getMatrixInventory().getContents().length + " or less"); + } + + net.minecraft.server.ItemStack[] mcItems = getMatrixInventory().getContents(); + + for (int i = 0; i < mcItems.length; i++ ) { + if (i < contents.length) { + ItemStack item = contents[i]; + if (item == null || item.getTypeId() <= 0) { + mcItems[i] = null; + } else { + mcItems[i] = new net.minecraft.server.ItemStack( item.getTypeId(), item.getAmount(), item.getDurability()); + } + } else { + mcItems[i] = null; + } + } + } + + public void setResult(ItemStack item) { + net.minecraft.server.ItemStack[] contents = getResultInventory().getContents(); + if (item == null || item.getTypeId() <= 0) { + contents[0] = null; + } else { + contents[0] = new net.minecraft.server.ItemStack( item.getTypeId(), item.getAmount(), item.getDurability()); + } + } + + public Recipe getRecipe() { + CraftingRecipe recipe = ((InventoryCrafting)getInventory()).currentRecipe; + return recipe == null ? null : recipe.toBukkitRecipe(); + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java new file mode 100644 index 0000000000..0aba33fa3f --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java @@ -0,0 +1,122 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryHolder; + +import net.minecraft.server.EntityHuman; +import net.minecraft.server.IInventory; +import net.minecraft.server.ItemStack; + +public class CraftInventoryCustom extends CraftInventory { + public CraftInventoryCustom(InventoryHolder owner, InventoryType type) { + super(new MinecraftInventory(owner, type)); + } + + public CraftInventoryCustom(InventoryHolder owner, int size) { + super(new MinecraftInventory(owner, size)); + } + + public CraftInventoryCustom(InventoryHolder owner, int size, String title) { + super(new MinecraftInventory(owner, size, title)); + } + + static class MinecraftInventory implements IInventory { + private ItemStack[] items; + private int maxStack; + private List viewers; + private String title; + private InventoryType type; + private InventoryHolder owner; // TODO: Constructors to set this + + public MinecraftInventory(InventoryHolder owner, InventoryType type) { + this(owner, type.getDefaultSize(), type.getDefaultTitle()); + this.type = type; + } + + public MinecraftInventory(InventoryHolder owner, int size) { + this(owner, size, "Chest"); + } + + public MinecraftInventory(InventoryHolder owner, int size, String title) { + this.items = new ItemStack[size]; + this.title = title; + this.viewers = new ArrayList(); + this.owner = owner; + this.type = InventoryType.CHEST; + } + + public int getSize() { + return items.length; + } + + public ItemStack getItem(int i) { + return items[i]; + } + + public ItemStack splitStack(int i, int j) { + ItemStack stack = this.getItem(i); + ItemStack result; + if (stack == null) return null; + if (stack.count <= j) { + this.setItem(i, null); + result = stack; + } else { + result = new ItemStack(stack.id, j, stack.getData()); + stack.count -= j; + } + this.update(); + return result; + } + + public void setItem(int i, ItemStack itemstack) { + items[i] = itemstack; + } + + public String getName() { + return title; + } + + public int getMaxStackSize() { + return maxStack; + } + + public void update() {} + + public boolean a(EntityHuman entityhuman) { + return true; + } + + public ItemStack[] getContents() { + return items; + } + + public void onOpen(CraftHumanEntity who) { + viewers.add(who); + } + + public void onClose(CraftHumanEntity who) { + viewers.remove(who); + } + + public List getViewers() { + return viewers; + } + + public InventoryType getType() { + return type; + } + + public void f() {} + + public void g() {} + + public InventoryHolder getOwner() { + return owner; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java new file mode 100644 index 0000000000..37868e1b9a --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java @@ -0,0 +1,53 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.inventory.DoubleChestInventory; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import net.minecraft.server.InventoryLargeChest; + +public class CraftInventoryDoubleChest extends CraftInventory implements DoubleChestInventory { + private CraftInventory left, right; + + public CraftInventoryDoubleChest(CraftInventory left, CraftInventory right) { + super(new InventoryLargeChest("Large chest", left.getInventory(), right.getInventory())); + this.left = left; + this.right = right; + } + + public CraftInventoryDoubleChest(InventoryLargeChest largeChest) { + super(largeChest); + if (largeChest.b instanceof InventoryLargeChest) { + left = new CraftInventoryDoubleChest((InventoryLargeChest)largeChest.b); + } else { + left = new CraftInventory(largeChest.b); + } + if (largeChest.c instanceof InventoryLargeChest) { + right = new CraftInventoryDoubleChest((InventoryLargeChest)largeChest.c); + } else { + right = new CraftInventory(largeChest.c); + } + } + + public Inventory getLeftSide() { + return left; + } + + public Inventory getRightSide() { + return right; + } + + @Override + public void setContents(ItemStack[] items) { + if (getInventory().getContents().length < items.length) { + throw new IllegalArgumentException("Invalid inventory size; expected " + getInventory().getContents().length + " or less"); + } + ItemStack[] leftItems = new ItemStack[left.getSize()], rightItems = new ItemStack[right.getSize()]; + System.arraycopy(items, 0, leftItems, 0, Math.min(left.getSize(),items.length)); + left.setContents(leftItems); + if (items.length >= left.getSize()) { + System.arraycopy(items, 0, rightItems, left.getSize(), Math.min(right.getSize(), items.length - left.getSize())); + right.setContents(rightItems); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java new file mode 100644 index 0000000000..fdc58f1600 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java @@ -0,0 +1,25 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.inventory.EnchantingInventory; +import org.bukkit.inventory.ItemStack; + +import net.minecraft.server.ContainerEnchantTableInventory; + +public class CraftInventoryEnchanting extends CraftInventory implements EnchantingInventory { + public CraftInventoryEnchanting(ContainerEnchantTableInventory inventory) { + super(inventory); + } + + public void setItem(ItemStack item) { + setItem(0,item); + } + + public ItemStack getItem() { + return getItem(0); + } + + @Override + public ContainerEnchantTableInventory getInventory() { + return (ContainerEnchantTableInventory)inventory; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java new file mode 100644 index 0000000000..37a631ebe4 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java @@ -0,0 +1,42 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.block.Furnace; +import org.bukkit.inventory.FurnaceInventory; +import org.bukkit.inventory.ItemStack; + +import net.minecraft.server.TileEntityFurnace; + +public class CraftInventoryFurnace extends CraftInventory implements FurnaceInventory { + public CraftInventoryFurnace(TileEntityFurnace inventory) { + super(inventory); + } + + public ItemStack getResult() { + return getItem(2); + } + + public ItemStack getFuel() { + return getItem(1); + } + + public ItemStack getSmelting() { + return getItem(0); + } + + public void setFuel(ItemStack stack) { + setItem(1,stack); + } + + public void setResult(ItemStack stack) { + setItem(2,stack); + } + + public void setSmelting(ItemStack stack) { + setItem(0,stack); + } + + @Override + public Furnace getHolder() { + return (Furnace) inventory.getOwner(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java index 369d80fe6b..21867fcf72 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java @@ -2,6 +2,7 @@ package org.bukkit.craftbukkit.inventory; import net.minecraft.server.PlayerInventory; +import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.ItemStack; public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.inventory.PlayerInventory { @@ -9,10 +10,12 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i super(inventory); } + @Override public PlayerInventory getInventory() { return (PlayerInventory) inventory; } + @Override public int getSize() { return super.getSize() - 4; } @@ -85,4 +88,9 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i } } } + + @Override + public HumanEntity getHolder() { + return (HumanEntity) inventory.getOwner(); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java new file mode 100644 index 0000000000..ab34e52a8f --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java @@ -0,0 +1,117 @@ +package org.bukkit.craftbukkit.inventory; + +import org.bukkit.GameMode; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; + +import net.minecraft.server.Container; + +public class CraftInventoryView extends InventoryView { + private Container container; + private CraftHumanEntity player; + private CraftInventory viewing; + + public CraftInventoryView(HumanEntity player, Inventory viewing, Container container) { + // TODO: Should we make sure it really IS a CraftHumanEntity first? And a CraftInventory? + this.player = (CraftHumanEntity) player; + this.viewing = (CraftInventory) viewing; + this.container = container; + } + + @Override + public Inventory getTopInventory() { + return viewing; + } + + @Override + public Inventory getBottomInventory() { + return player.getInventory(); + } + + @Override + public HumanEntity getPlayer() { + return player; + } + + @Override + public InventoryType getType() { + InventoryType type = viewing.getType(); + if (type == InventoryType.CRAFTING && player.getGameMode() == GameMode.CREATIVE) { + return InventoryType.CREATIVE; + } + return type; + } + + @Override + public void setItem(int slot, ItemStack item) { + if (slot != -999) { + CraftItemStack stack = new CraftItemStack(item); + container.b(slot).c(stack.getHandle()); + } + } + + @Override + public ItemStack getItem(int slot) { + if (slot == -999) { + return null; + } + return new CraftItemStack(container.b(slot).getItem()); + } + + public boolean isInTop(int rawSlot) { + return rawSlot < viewing.getSize(); + } + + public Container getHandle() { + return container; + } + + public static SlotType getSlotType(InventoryView inventory, int slot) { + SlotType type = SlotType.CONTAINER; + if (slot < inventory.getTopInventory().getSize()) { + switch(inventory.getType()) { + case FURNACE: + if (slot == 2) { + type = SlotType.RESULT; + } else if(slot == 1) { + type = SlotType.FUEL; + } + break; + case BREWING: + if (slot == 0) { + type = SlotType.FUEL; + } else { + type = SlotType.CRAFTING; + } + break; + case ENCHANTING: + type = SlotType.CRAFTING; + break; + case WORKBENCH: + case CRAFTING: + if (slot == 0) { + type = SlotType.RESULT; + } else { + type = SlotType.CRAFTING; + } + break; + default: + // Nothing to do, it's a CONTAINER slot + } + } else { + if (slot == -999) { + type = SlotType.OUTSIDE; + } else if (inventory.getType() == InventoryType.CRAFTING && slot < 9) { + type = SlotType.ARMOR; + } else if (slot >= (inventory.countSlots() - 9)) { + type = SlotType.QUICKBAR; + } + } + return type; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 5316f7771f..a363402b42 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -87,7 +87,9 @@ public class CraftItemStack extends ItemStack { } else { if (item == null) { item = new net.minecraft.server.ItemStack(type, 1, 0); + super.setTypeId(type); super.setAmount(1); + super.setDurability((short) 0); } else { item.id = type; super.setTypeId(item.id); @@ -224,6 +226,9 @@ public class CraftItemStack extends ItemStack { } public static net.minecraft.server.ItemStack createNMSItemStack(ItemStack original) { + if (original == null || original.getTypeId() <= 0) { + return null; + } return new CraftItemStack(original).getHandle(); } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java index 54287b9221..919df56196 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java @@ -15,7 +15,7 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe public CraftShapelessRecipe(ItemStack result) { super(result); } - + public CraftShapelessRecipe(ItemStack result, ShapelessRecipes recipe) { this(result); this.recipe = recipe; diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java deleted file mode 100644 index 3899eb75cb..0000000000 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bukkit.craftbukkit.inventory; - -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import net.minecraft.server.Slot; - -public class CraftSlot implements org.bukkit.inventory.Slot { - private final Slot slot; - - public CraftSlot(Slot slot) { - this.slot = slot; - } - - public Inventory getInventory() { - return new CraftInventory(slot.inventory); - } - - public int getIndex() { - return slot.index; - } - - public ItemStack getItem() { - return new CraftItemStack(slot.getItem()); - } -} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/InventoryIterator.java b/src/main/java/org/bukkit/craftbukkit/inventory/InventoryIterator.java new file mode 100644 index 0000000000..cd4a0d0705 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/InventoryIterator.java @@ -0,0 +1,56 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.ListIterator; + +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class InventoryIterator implements ListIterator { + private final Inventory inventory; + private int nextIndex; + private boolean lastDirection; // true = forward, false = backward + + InventoryIterator(Inventory craftInventory) { + this.inventory = craftInventory; + this.nextIndex = 0; + } + + public boolean hasNext() { + return nextIndex < inventory.getSize(); + } + + public ItemStack next() { + lastDirection = true; + return inventory.getItem(nextIndex++); + } + + public int nextIndex() { + return nextIndex; + } + + public boolean hasPrevious() { + return nextIndex > 0; + } + + public ItemStack previous() { + lastDirection = false; + return inventory.getItem(--nextIndex); + } + + public int previousIndex() { + return nextIndex - 1; + } + + public void set(ItemStack item) { + int i = lastDirection ? nextIndex - 1 : nextIndex; + inventory.setItem(i, item); + } + + public void add(ItemStack item) { + throw new UnsupportedOperationException("Can't change the size of an inventory!"); + } + + public void remove() { + throw new UnsupportedOperationException("Can't change the size of an inventory!"); + } +} \ No newline at end of file