From 472b179cd10838699474108e8e04c661bc6a0fd7 Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot 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). By: Celtic Minstrel --- .../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 +++++ 21 files changed, 1134 insertions(+), 43 deletions(-) create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryBrewer.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/InventoryIterator.java diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 94204e40fa..8bb40a5578 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java index 55b2d49efd..f1d6196449 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java index f5f7fa6aa8..7ccfa80e4c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java index dcf0fe1b0f..e4756dcd2b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 7b5b37ca8e..55163f7a5e 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 0be3c7e28f..417a5ed958 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 131056522b..bcadbce4dc 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java new file mode 100644 index 0000000000..e60ddb718c --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java index 385a6fc993..79731c50ae 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryBrewer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryBrewer.java new file mode 100644 index 0000000000..6de6e6e6cf --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java new file mode 100644 index 0000000000..e827bc6031 --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java new file mode 100644 index 0000000000..0aba33fa3f --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java new file mode 100644 index 0000000000..37868e1b9a --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java new file mode 100644 index 0000000000..fdc58f1600 --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java new file mode 100644 index 0000000000..37a631ebe4 --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java index 369d80fe6b..21867fcf72 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java new file mode 100644 index 0000000000..ab34e52a8f --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 5316f7771f..a363402b42 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java index 54287b9221..919df56196 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +++ b/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSlot.java deleted file mode 100644 index 3899eb75cb..0000000000 --- a/paper-server/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/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/InventoryIterator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/InventoryIterator.java new file mode 100644 index 0000000000..cd4a0d0705 --- /dev/null +++ b/paper-server/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