package pneumaticCraft.common.tileentity;
import java.util.List;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
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.minecraft.util.AxisAlignedBB;
import net.minecraftforge.common.util.ForgeDirection;
import pneumaticCraft.common.block.Blockss;
import pneumaticCraft.common.item.ItemMachineUpgrade;
import pneumaticCraft.common.network.DescSynced;
import pneumaticCraft.common.network.GuiSynced;
import pneumaticCraft.common.util.IOHelper;
public class TileEntityOmnidirectionalHopper extends TileEntityBase implements ISidedInventory, IRedstoneControlled{
@DescSynced
protected ForgeDirection inputDir = ForgeDirection.UNKNOWN;
private ItemStack[] inventory = new ItemStack[getInvSize()];
@GuiSynced
public int redstoneMode;
private int cooldown;
@GuiSynced
protected boolean leaveMaterial;//leave items/liquids (used as filter)
public TileEntityOmnidirectionalHopper(){
setUpgradeSlots(5, 6, 7, 8);
}
protected int getInvSize(){
return 9;
}
@Override
public void updateEntity(){
super.updateEntity();
if(!getWorldObj().isRemote && --cooldown <= 0 && redstoneAllows()) {
int maxItems = getMaxItems();
boolean success = suckInItem(maxItems);
success |= exportItem(maxItems);
if(!success) {
cooldown = 8;//When insertion failed, do a long cooldown as penalty for performance.
} else {
cooldown = getItemTransferInterval();
}
}
}
protected boolean exportItem(int maxItems){
ForgeDirection dir = ForgeDirection.getOrientation(getBlockMetadata());
TileEntity neighbor = IOHelper.getNeighbor(this, dir);
for(int i = 0; i < 5; i++) {
ItemStack stack = inventory[i];
if(stack != null && (!leaveMaterial || stack.stackSize > 1)) {
ItemStack exportedStack = stack.copy();
if(leaveMaterial) exportedStack.stackSize--;
if(exportedStack.stackSize > maxItems) exportedStack.stackSize = maxItems;
int count = exportedStack.stackSize;
ItemStack remainder = IOHelper.insert(neighbor, exportedStack, dir.getOpposite(), false);
int exportedItems = count - (remainder == null ? 0 : remainder.stackSize);
stack.stackSize -= exportedItems;
if(stack.stackSize <= 0) {
setInventorySlotContents(i, null);
}
maxItems -= exportedItems;
if(maxItems <= 0) return true;
}
}
return false;
}
protected boolean suckInItem(int maxItems){
TileEntity inputInv = IOHelper.getNeighbor(this, inputDir);
boolean success = false;
//Suck from input inventory.
for(int i = 0; i < maxItems; i++) {
if(hasEmptySlot()) {
ItemStack extracted = IOHelper.extractOneItem(inputInv, inputDir.getOpposite(), true);//simulate extraction from the neighbor.
if(extracted != null) {
ItemStack inserted = IOHelper.insert(this, extracted, ForgeDirection.UNKNOWN, false);//if we can insert the item in this hopper.
if(inserted == null) {
IOHelper.extractOneItem(inputInv, inputDir.getOpposite(), false); //actually retrieve it from the neighbor.
success = true;
} else {
break;
}
} else {
break;
}
} else {
for(int slot = 0; slot < 5; slot++) {
ItemStack stack = inventory[slot];
stack = stack.copy();
stack.stackSize = 1;
ItemStack extracted = IOHelper.extract(inputInv, inputDir.getOpposite(), stack, true, true);//simulate extraction from the neighbor.
if(extracted != null) {
ItemStack inserted = IOHelper.insert(this, extracted, ForgeDirection.UNKNOWN, false);//if we can insert the item in this hopper.
if(inserted == null) {
IOHelper.extract(inputInv, inputDir.getOpposite(), stack, true, false); //actually retrieve it from the neighbor.
success = true;
break;
}
}
}
if(!success) break;
}
}
for(EntityItem entity : getNeighborItems(this, inputDir)) {
if(!entity.isDead) {
ItemStack remainder = IOHelper.insert(this, entity.getEntityItem(), ForgeDirection.UNKNOWN, false);
if(remainder == null) {
entity.setDead();
success = true;//Don't set true when the stack could not be fully consumes, as that means next insertion there won't be any room.
}
}
}
return success;
}
private boolean hasEmptySlot(){
for(int i = 0; i < 5; i++) {
if(inventory[i] == null) return true;
}
return false;
}
public static List<EntityItem> getNeighborItems(TileEntity te, ForgeDirection inputDir){
AxisAlignedBB box = AxisAlignedBB.getBoundingBox(te.xCoord + inputDir.offsetX, te.yCoord + inputDir.offsetY, te.zCoord + inputDir.offsetZ, te.xCoord + inputDir.offsetX + 1, te.yCoord + inputDir.offsetY + 1, te.zCoord + inputDir.offsetZ + 1);
return te.getWorldObj().getEntitiesWithinAABB(EntityItem.class, box);
}
public int getMaxItems(){
int upgrades = getUpgrades(ItemMachineUpgrade.UPGRADE_SPEED_DAMAGE, getUpgradeSlots());
if(upgrades > 3) {
return Math.min((int)Math.pow(2, upgrades - 3), 256);
} else {
return 1;
}
}
public int getItemTransferInterval(){
return 8 / (int)Math.pow(2, getUpgrades(ItemMachineUpgrade.UPGRADE_SPEED_DAMAGE, getUpgradeSlots()));
}
public void setDirection(ForgeDirection dir){
inputDir = dir;
}
public ForgeDirection getDirection(){
return inputDir;
}
@Override
public void writeToNBT(NBTTagCompound tag){
super.writeToNBT(tag);
tag.setInteger("inputDir", inputDir.ordinal());
tag.setInteger("redstoneMode", redstoneMode);
tag.setBoolean("leaveMaterial", leaveMaterial);
NBTTagList tagList = new NBTTagList();
for(int currentIndex = 0; currentIndex < inventory.length; ++currentIndex) {
if(inventory[currentIndex] != null) {
NBTTagCompound tagCompound = new NBTTagCompound();
tagCompound.setByte("Slot", (byte)currentIndex);
inventory[currentIndex].writeToNBT(tagCompound);
tagList.appendTag(tagCompound);
}
}
tag.setTag("Inventory", tagList);
}
@Override
public void readFromNBT(NBTTagCompound tag){
super.readFromNBT(tag);
inputDir = ForgeDirection.getOrientation(tag.getInteger("inputDir"));
redstoneMode = tag.getInteger("redstoneMode");
leaveMaterial = tag.getBoolean("leaveMaterial");
NBTTagList tagList = tag.getTagList("Inventory", 10);
inventory = new ItemStack[inventory.length];
for(int i = 0; i < tagList.tagCount(); ++i) {
NBTTagCompound tagCompound = tagList.getCompoundTagAt(i);
byte slot = tagCompound.getByte("Slot");
if(slot >= 0 && slot < inventory.length) {
inventory[slot] = ItemStack.loadItemStackFromNBT(tagCompound);
}
}
}
/**
* Returns the name of the inventory.
*/
@Override
public String getInventoryName(){
return Blockss.omnidirectionalHopper.getUnlocalizedName();
}
/**
* Returns the number of slots in the inventory.
*/
@Override
public int getSizeInventory(){
return inventory.length;
}
/**
* Returns the stack in slot i
*/
@Override
public ItemStack getStackInSlot(int par1){
return inventory[par1];
}
@Override
public ItemStack decrStackSize(int slot, int amount){
ItemStack itemStack = getStackInSlot(slot);
if(itemStack != null) {
if(itemStack.stackSize <= amount) {
setInventorySlotContents(slot, null);
} else {
itemStack = itemStack.splitStack(amount);
if(itemStack.stackSize == 0) {
setInventorySlotContents(slot, null);
}
}
}
return itemStack;
}
@Override
public ItemStack getStackInSlotOnClosing(int slot){
ItemStack itemStack = getStackInSlot(slot);
if(itemStack != null) {
setInventorySlotContents(slot, null);
}
return itemStack;
}
@Override
public void setInventorySlotContents(int slot, ItemStack itemStack){
inventory[slot] = itemStack;
if(itemStack != null && itemStack.stackSize > getInventoryStackLimit()) {
itemStack.stackSize = getInventoryStackLimit();
}
}
@Override
public void handleGUIButtonPress(int buttonID, EntityPlayer player){
if(buttonID == 0) {
redstoneMode++;
if(redstoneMode > 2) redstoneMode = 0;
} else if(buttonID == 1) {
leaveMaterial = false;
} else if(buttonID == 2) {
leaveMaterial = true;
}
}
@Override
public boolean isItemValidForSlot(int par1, ItemStack par2ItemStack){
return par1 < 5;
}
private static final int[] accessibleSlots = {0, 1, 2, 3, 4};
@Override
public int[] getAccessibleSlotsFromSide(int var1){
return accessibleSlots;
}
@Override
public boolean canInsertItem(int var1, ItemStack var2, int var3){
return var1 < 5;
}
@Override
public boolean canExtractItem(int var1, ItemStack var2, int var3){
return var1 < 5;
}
@Override
public boolean hasCustomInventoryName(){
return false;
}
@Override
public int getInventoryStackLimit(){
return 64;
}
@Override
public boolean isUseableByPlayer(EntityPlayer p_70300_1_){
return isGuiUseableByPlayer(p_70300_1_);
}
@Override
public void openInventory(){}
@Override
public void closeInventory(){}
@Override
public int getRedstoneMode(){
return redstoneMode;
}
public boolean doesLeaveMaterial(){
return leaveMaterial;
}
}