package erogenousbeef.bigreactors.common.tileentity.base; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; import cofh.lib.util.helpers.BlockHelper; import erogenousbeef.bigreactors.utils.AdjacentInventoryHelper; public abstract class TileEntityInventory extends TileEntityBeefBase implements IInventory, ISidedInventory { // Inventory protected ItemStack[] _inventories; protected int[][] invSlotExposures; private AdjacentInventoryHelper[] adjacentInvs; protected static final int SLOT_NONE = TileEntityBeefBase.SIDE_UNEXPOSED; public TileEntityInventory() { super(); _inventories = new ItemStack[getSizeInventory()]; invSlotExposures = new int[getSizeInventory()][1]; for(int i = 0; i < invSlotExposures.length; i++) { // Set up a cached array with all possible exposed inventory slots, so we don't have to alloc at runtime invSlotExposures[i][0] = i; } adjacentInvs = new AdjacentInventoryHelper[ForgeDirection.VALID_DIRECTIONS.length]; for(ForgeDirection dir: ForgeDirection.VALID_DIRECTIONS) { adjacentInvs[dir.ordinal()] = new AdjacentInventoryHelper(dir); } resetAdjacentInventories(); } @Override public void onNeighborBlockChange() { super.onNeighborBlockChange(); checkAdjacentInventories(); } @Override public void onNeighborTileChange(int x, int y, int z) { super.onNeighborTileChange(x, y, z); int side = BlockHelper.determineAdjacentSide(this, x, y, z); checkAdjacentInventory(ForgeDirection.getOrientation(side)); } // TileEntity overrides @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); // Inventories _inventories = new ItemStack[getSizeInventory()]; if(tag.hasKey("Items")) { NBTTagList tagList = tag.getTagList("Items", 10); for(int i = 0; i < tagList.tagCount(); i++) { NBTTagCompound itemTag = (NBTTagCompound)tagList.getCompoundTagAt(i); int slot = itemTag.getByte("Slot") & 0xff; if(slot >= 0 && slot <= _inventories.length) { ItemStack itemStack = new ItemStack((Block)null,0,0); itemStack.readFromNBT(itemTag); _inventories[slot] = itemStack; } } } } @Override public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); // Inventories NBTTagList tagList = new NBTTagList(); for(int i = 0; i < _inventories.length; i++) { if((_inventories[i]) != null) { NBTTagCompound itemTag = new NBTTagCompound(); itemTag.setByte("Slot", (byte)i); _inventories[i].writeToNBT(itemTag); tagList.appendTag(itemTag); } } if(tagList.tagCount() > 0) { tag.setTag("Items", tagList); } } // IInventory @Override public abstract int getSizeInventory(); @Override public ItemStack getStackInSlot(int slot) { return _inventories[slot]; } @Override public ItemStack decrStackSize(int slot, int amount) { if(_inventories[slot] != null) { if(_inventories[slot].stackSize <= amount) { ItemStack itemstack = _inventories[slot]; _inventories[slot] = null; return itemstack; } ItemStack newStack = _inventories[slot].splitStack(amount); if(_inventories[slot].stackSize == 0) { _inventories[slot] = null; } return newStack; } else { return null; } } @Override public ItemStack getStackInSlotOnClosing(int slot) { return null; } @Override public void setInventorySlotContents(int slot, ItemStack itemstack) { _inventories[slot] = itemstack; if(itemstack != null && itemstack.stackSize > getInventoryStackLimit()) { itemstack.stackSize = getInventoryStackLimit(); } } @Override public abstract String getInventoryName(); @Override public boolean hasCustomInventoryName() { return false; } @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUseableByPlayer(EntityPlayer entityplayer) { if(worldObj.getTileEntity(xCoord, yCoord, zCoord) != this) { return false; } return entityplayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D; } @Override public void openInventory() { } @Override public void closeInventory() { } @Override public abstract boolean isItemValidForSlot(int slot, ItemStack itemstack); // ISidedInventory /** * Get the exposed inventory slot from a given world side. * Remember to translate this into a reference side! * @param side The side being queried for exposure. * @return The index of the exposed slot, -1 (SLOT_UNEXPOSED) if none. */ protected abstract int getExposedInventorySlotFromSide(int side); @Override public int[] getAccessibleSlotsFromSide(int side) { int exposedSlot = getExposedInventorySlotFromSide(side); if(exposedSlot >= 0 && exposedSlot < invSlotExposures.length) { return invSlotExposures[exposedSlot]; } else { return kEmptyIntArray; } } @Override public boolean canInsertItem(int slot, ItemStack itemstack, int side) { return isItemValidForSlot(slot, itemstack); } @Override public boolean canExtractItem(int slot, ItemStack itemstack, int side) { return isItemValidForSlot(slot, itemstack); } // IItemDuctConnection public boolean canConduitConnect(ForgeDirection from) { return from != ForgeDirection.UNKNOWN; } /** * This method distributes items from all exposed slots to linked inventories * on their respective sides. */ protected void distributeItems() { for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { distributeSide(dir); } } protected void distributeItemsFromSlot(int slot) { if(slot == SLOT_NONE) { return; } for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { int sideSlot = getExposedInventorySlotFromSide(dir.ordinal()); if(slot == sideSlot) { _inventories[slot] = distributeItemToSide(dir, _inventories[slot]); } if(_inventories[slot] == null) { break; } } } /** * Distributes items from whichever slot is currently exposed on a given * side to any adjacent pipes/ducts/inventories. * @param dir The side whose exposed items you wish to distribute. */ protected void distributeSide(ForgeDirection dir) { int slot = getExposedInventorySlotFromSide(dir.ordinal()); if(slot == SLOT_NONE) { return; } if(_inventories[slot] == null) { return; } _inventories[slot] = distributeItemToSide(dir, _inventories[slot]); } /** * Distributes a given item stack to a given side. * Note that this method does not check for exposures. * @param dir Direction/side to which you wish to distribute items. * @param itemstack An item stack to distribute. * @return An itemstack containing the undistributed items, or null if all items were distributed. */ protected ItemStack distributeItemToSide(ForgeDirection dir, ItemStack itemstack) { return adjacentInvs[dir.ordinal()].distribute(itemstack); } // Adjacent Inventory Detection private void checkAdjacentInventories() { boolean changed = false; for(ForgeDirection dir: ForgeDirection.VALID_DIRECTIONS) { checkAdjacentInventory(dir); } } private void checkAdjacentInventory(ForgeDirection dir) { TileEntity te = worldObj.getTileEntity(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ); if(adjacentInvs[dir.ordinal()].set(te)) { distributeSide(dir); } } private void resetAdjacentInventories() { for(int i = 0; i < ForgeDirection.VALID_DIRECTIONS.length; i++) { adjacentInvs[i].set(null); } } }