[Bleeding] Fix the openInventory methods for custom inventories. Fixes BUKKIT-1248

Details:
- The attributes of custom inventory views are no longer ignored
- Enchanting or crafting inventories no longer ignore the passed inventory and open a new one
- Inventories associated with tile entities no longer raise a class cast exception if there was no associated tile entity
- InventoryOpenEvent and InventoryCloseEvent (if they already had some other inventory open) now fire in all cases
- If for any reason the inventory failed to open, the method now returns null instead of returned the previous inventory they had open (or the default inventory, if none)

By: Celtic Minstrel <celtic.minstrel.ca@some.place>
This commit is contained in:
CraftBukkit/Spigot 2012-03-17 13:06:21 -04:00
parent 5f0bee3860
commit 7e41baa24b
2 changed files with 100 additions and 33 deletions

View file

@ -3,6 +3,8 @@ package org.bukkit.craftbukkit.entity;
import java.util.Set; import java.util.Set;
import net.minecraft.server.Container; import net.minecraft.server.Container;
import net.minecraft.server.ContainerBrewingStand;
import net.minecraft.server.ContainerWorkbench;
import net.minecraft.server.EntityHuman; import net.minecraft.server.EntityHuman;
import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityPlayer;
import net.minecraft.server.ICrafting; import net.minecraft.server.ICrafting;
@ -23,6 +25,7 @@ import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.craftbukkit.inventory.CraftContainer; import org.bukkit.craftbukkit.inventory.CraftContainer;
import org.bukkit.craftbukkit.inventory.CraftInventory; import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer;
@ -168,7 +171,10 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
} }
public InventoryView openInventory(Inventory inventory) { public InventoryView openInventory(Inventory inventory) {
if(!(getHandle() instanceof EntityPlayer)) return null;
EntityPlayer player = (EntityPlayer) getHandle();
InventoryType type = inventory.getType(); InventoryType type = inventory.getType();
Container formerContainer = getHandle().activeContainer;
// TODO: Should we check that it really IS a CraftInventory first? // TODO: Should we check that it really IS a CraftInventory first?
CraftInventory craftinv = (CraftInventory) inventory; CraftInventory craftinv = (CraftInventory) inventory;
switch(type) { switch(type) {
@ -177,28 +183,57 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
getHandle().openContainer(craftinv.getInventory()); getHandle().openContainer(craftinv.getInventory());
break; break;
case DISPENSER: case DISPENSER:
getHandle().openDispenser((TileEntityDispenser)craftinv.getInventory()); if (craftinv.getInventory() instanceof TileEntityDispenser) {
getHandle().openDispenser((TileEntityDispenser)craftinv.getInventory());
} else {
openCustomInventory(inventory, player, 3);
}
break; break;
case FURNACE: case FURNACE:
getHandle().openFurnace((TileEntityFurnace)craftinv.getInventory()); if (craftinv.getInventory() instanceof TileEntityFurnace) {
getHandle().openFurnace((TileEntityFurnace)craftinv.getInventory());
} else {
openCustomInventory(inventory, player, 2);
}
break; break;
case WORKBENCH: case WORKBENCH:
getHandle().startCrafting(getLocation().getBlockX(), getLocation().getBlockY(), getLocation().getBlockZ()); openCustomInventory(inventory, player, 1);
break; break;
case BREWING: case BREWING:
getHandle().openBrewingStand((TileEntityBrewingStand)craftinv.getInventory()); if (craftinv.getInventory() instanceof TileEntityBrewingStand) {
getHandle().openBrewingStand((TileEntityBrewingStand)craftinv.getInventory());
} else {
openCustomInventory(inventory, player, 5);
}
break; break;
case ENCHANTING: case ENCHANTING:
getHandle().startEnchanting(getLocation().getBlockX(), getLocation().getBlockY(), getLocation().getBlockZ()); openCustomInventory(inventory, player, 4);
break; break;
case CREATIVE: case CREATIVE:
case CRAFTING: case CRAFTING:
throw new IllegalArgumentException("Can't open a " + type + " inventory!"); throw new IllegalArgumentException("Can't open a " + type + " inventory!");
} }
if (getHandle().activeContainer == formerContainer) {
return null;
}
getHandle().activeContainer.checkReachable = false; getHandle().activeContainer.checkReachable = false;
return getHandle().activeContainer.getBukkitView(); return getHandle().activeContainer.getBukkitView();
} }
private void openCustomInventory(Inventory inventory, EntityPlayer player, int windowType) {
Container container = new CraftContainer(inventory, this, player.nextContainerCounter());
container = CraftEventFactory.callInventoryOpenEvent(player, container);
if(container == null) return;
String title = container.getBukkitView().getTitle();
int size = container.getBukkitView().getTopInventory().getSize();
player.netServerHandler.sendPacket(new Packet100OpenWindow(container.windowId, windowType, title, size));
getHandle().activeContainer = container;
getHandle().activeContainer.addSlotListener(player);
}
public InventoryView openWorkbench(Location location, boolean force) { public InventoryView openWorkbench(Location location, boolean force) {
if (!force) { if (!force) {
Block block = location.getBlock(); Block block = location.getBlock();
@ -248,18 +283,19 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
} }
// Trigger an INVENTORY_OPEN event // Trigger an INVENTORY_OPEN event
InventoryOpenEvent event = new InventoryOpenEvent(inventory); container = CraftEventFactory.callInventoryOpenEvent(player, container);
player.activeContainer.transferTo(container, this); if (container == null) {
server.getPluginManager().callEvent(event);
if (event.isCancelled()) {
container.transferTo(player.activeContainer, this);
return; return;
} }
// Now open the window // Now open the window
player.netServerHandler.sendPacket(new Packet100OpenWindow(container.windowId, 1, "Crafting", 9)); InventoryType type = inventory.getType();
int windowType = CraftContainer.getNotchInventoryType(type);
String title = inventory.getTitle();
int size = inventory.getTopInventory().getSize();
player.netServerHandler.sendPacket(new Packet100OpenWindow(container.windowId, windowType, title, size));
player.activeContainer = container; player.activeContainer = container;
player.activeContainer.addSlotListener((ICrafting) player); player.activeContainer.addSlotListener(player);
} }
public void closeInventory() { public void closeInventory() {

View file

@ -1,7 +1,9 @@
package org.bukkit.craftbukkit.inventory; package org.bukkit.craftbukkit.inventory;
import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.InventoryView;
import net.minecraft.server.Container; import net.minecraft.server.Container;
@ -28,6 +30,30 @@ public class CraftContainer extends Container {
setupSlots(top, bottom); setupSlots(top, bottom);
} }
public CraftContainer(final Inventory inventory, final HumanEntity player, int id) {
this(new InventoryView() {
@Override
public Inventory getTopInventory() {
return inventory;
}
@Override
public Inventory getBottomInventory() {
return player.getInventory();
}
@Override
public HumanEntity getPlayer() {
return player;
}
@Override
public InventoryType getType() {
return inventory.getType();
}
}, id);
}
@Override @Override
public InventoryView getBukkitView() { public InventoryView getBukkitView() {
return view; return view;
@ -50,27 +76,7 @@ public class CraftContainer extends Container {
cachedTitle = view.getTitle(); cachedTitle = view.getTitle();
if (view.getPlayer() instanceof CraftPlayer) { if (view.getPlayer() instanceof CraftPlayer) {
CraftPlayer player = (CraftPlayer) view.getPlayer(); CraftPlayer player = (CraftPlayer) view.getPlayer();
int type; int type = getNotchInventoryType(cachedType);
switch(cachedType) {
case WORKBENCH:
type = 1;
break;
case FURNACE:
type = 2;
break;
case DISPENSER:
type = 3;
break;
case ENCHANTING:
type = 4;
break;
case BREWING:
type = 5;
break;
default:
type = 0;
break;
}
IInventory top = ((CraftInventory)view.getTopInventory()).getInventory(); IInventory top = ((CraftInventory)view.getTopInventory()).getInventory();
IInventory bottom = ((CraftInventory)view.getBottomInventory()).getInventory(); IInventory bottom = ((CraftInventory)view.getBottomInventory()).getInventory();
this.d.clear(); this.d.clear();
@ -85,6 +91,31 @@ public class CraftContainer extends Container {
return true; return true;
} }
public static int getNotchInventoryType(InventoryType type) {
int typeID;
switch(type) {
case WORKBENCH:
typeID = 1;
break;
case FURNACE:
typeID = 2;
break;
case DISPENSER:
typeID = 3;
break;
case ENCHANTING:
typeID = 4;
break;
case BREWING:
typeID = 5;
break;
default:
typeID = 0;
break;
}
return typeID;
}
private void setupSlots(IInventory top, IInventory bottom) { private void setupSlots(IInventory top, IInventory bottom) {
switch(cachedType) { switch(cachedType) {
case CREATIVE: case CREATIVE: