package blusunrize.immersiveengineering.common.blocks.metal;
import blusunrize.immersiveengineering.api.Lib;
import blusunrize.immersiveengineering.api.crafting.FermenterRecipe;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IAdvancedCollisionBounds;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IAdvancedSelectionBounds;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IGuiTile;
import blusunrize.immersiveengineering.common.blocks.multiblocks.MultiblockFermenter;
import blusunrize.immersiveengineering.common.util.Utils;
import blusunrize.immersiveengineering.common.util.inventory.IEInventoryHandler;
import com.google.common.collect.Lists;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.oredict.OreDictionary;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class TileEntityFermenter extends TileEntityMultiblockMetal<TileEntityFermenter,FermenterRecipe> implements IAdvancedSelectionBounds,IAdvancedCollisionBounds, IGuiTile
{
public TileEntityFermenter()
{
super(MultiblockFermenter.instance, new int[]{3,3,3}, 16000, true);
}
public FluidTank[] tanks = new FluidTank[]{new FluidTank(24000)};
public ItemStack[] inventory = new ItemStack[11];
@Override
public void readCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
super.readCustomNBT(nbt, descPacket);
tanks[0].readFromNBT(nbt.getCompoundTag("tank"));
if(!descPacket)
inventory = Utils.readInventory(nbt.getTagList("inventory", 10), 11);
}
@Override
public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
super.writeCustomNBT(nbt, descPacket);
NBTTagCompound tankTag = tanks[0].writeToNBT(new NBTTagCompound());
nbt.setTag("tank", tankTag);
if(!descPacket)
nbt.setTag("inventory", Utils.writeInventory(inventory));
}
@Override
public void update()
{
super.update();
if(isDummy() || isRSDisabled())
return;
if(!worldObj.isRemote)
{
boolean update = false;
if(energyStorage.getEnergyStored()>0 && processQueue.size()<this.getProcessQueueMaxLength())
{
final int[] usedInvSlots = new int[8];
for(MultiblockProcess process : processQueue)
if(process instanceof MultiblockProcessInMachine)
for(int i : ((MultiblockProcessInMachine)process).inputSlots)
usedInvSlots[i]++;
Integer[] preferredSlots = new Integer[]{0,1,2,3,4,5,6,7};
Arrays.sort(preferredSlots, 0,8, new Comparator<Integer>(){
@Override
public int compare(Integer arg0, Integer arg1)
{
return Integer.compare(usedInvSlots[arg0],usedInvSlots[arg1]);
}});
for(int slot : preferredSlots)
{
ItemStack stack = this.getInventory()[slot];
if(stack!=null)
{
stack = stack.copy();
stack.stackSize-=usedInvSlots[slot];
}
if(stack!=null && stack.stackSize>0)
{
FermenterRecipe recipe = this.findRecipeForInsertion(stack);
if(recipe!=null)
{
MultiblockProcessInMachine<FermenterRecipe> process = new MultiblockProcessInMachine(recipe, slot);
if(this.addProcessToQueue(process, true))
{
this.addProcessToQueue(process, false);
update = true;
}
}
}
}
}
EnumFacing fw = mirrored?facing.rotateYCCW():facing.rotateY();
if(this.tanks[0].getFluidAmount()>0)
{
FluidStack out = Utils.copyFluidStackWithAmount(this.tanks[0].getFluid(), Math.min(this.tanks[0].getFluidAmount(), 80), false);
BlockPos outputPos = this.getPos().add(0,-1,0).offset(fw,2);
IFluidHandler output = FluidUtil.getFluidHandler(worldObj, outputPos, fw.getOpposite());
if(output!=null)
{
int accepted = output.fill(out, false);
if(accepted>0)
{
int drained = output.fill(Utils.copyFluidStackWithAmount(out,Math.min(out.amount, accepted),false), true);
this.tanks[0].drain(drained, true);
update=true;
}
}
ItemStack empty = getInventory()[9];
if (empty!=null&&tanks[0].getFluidAmount()>0)
{
ItemStack full = Utils.fillFluidContainer(tanks[0], empty, getInventory()[10], null);
if (full!=null)
{
if (getInventory()[10]!=null&&OreDictionary.itemMatches(full, getInventory()[10], true))
getInventory()[10].stackSize+=full.stackSize;
else
getInventory()[10] = full;
if(--inventory[9].stackSize<=0)
inventory[9]=null;
}
}
}
if(inventory[8]!=null && worldObj.getTotalWorldTime()%8==0)
{
BlockPos outputPos = this.getPos().offset(fw);
TileEntity outputTile = this.worldObj.getTileEntity(outputPos);
if(outputTile != null)
{
ItemStack stack = Utils.copyStackWithAmount(inventory[8], 1);
stack = Utils.insertStackIntoInventory(outputTile, stack, fw.getOpposite());
if(stack == null)
if((--this.inventory[8].stackSize) <= 0)
this.inventory[8] = null;
}
}
if(update)
{
this.markDirty();
this.markContainingBlockForUpdate(null);
}
}
}
@Override
public float[] getBlockBounds()
{
if(pos>0&&pos<9 && pos!=5)
return new float[]{0,0,0, 1,.5f,1};
if(pos==11)
return new float[]{facing==EnumFacing.WEST?.5f:0,0,facing==EnumFacing.NORTH?.5f:0, facing==EnumFacing.EAST?.5f:1,1,facing==EnumFacing.SOUTH?.5f:1};
return new float[]{0,0,0, 1,1,1};
}
@Override
public List<AxisAlignedBB> getAdvancedSelectionBounds()
{
EnumFacing fl = facing;
EnumFacing fw = facing.rotateY();
if(mirrored)
fw = fw.getOpposite();
if(pos==2)
{
List<AxisAlignedBB> list = Lists.newArrayList(new AxisAlignedBB(0,0,0, 1,.5f,1).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
float minX = fl==EnumFacing.WEST?.625f: fl==EnumFacing.EAST?.125f: .125f;
float maxX = fl==EnumFacing.EAST?.375f: fl==EnumFacing.WEST?.875f: .25f;
float minZ = fl==EnumFacing.NORTH?.625f: fl==EnumFacing.SOUTH?.125f: .125f;
float maxZ = fl==EnumFacing.SOUTH?.375f: fl==EnumFacing.NORTH?.875f: .25f;
list.add(new AxisAlignedBB(minX,.5f,minZ, maxX,1,maxZ).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
minX = fl==EnumFacing.WEST?.625f: fl==EnumFacing.EAST?.125f: .75f;
maxX = fl==EnumFacing.EAST?.375f: fl==EnumFacing.WEST?.875f: .875f;
minZ = fl==EnumFacing.NORTH?.625f: fl==EnumFacing.SOUTH?.125f: .75f;
maxZ = fl==EnumFacing.SOUTH?.375f: fl==EnumFacing.NORTH?.875f: .875f;
list.add(new AxisAlignedBB(minX,.5f,minZ, maxX,1,maxZ).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
return list;
}
if(pos==3||pos==4||pos==6||pos==7)
{
List<AxisAlignedBB> list = Lists.newArrayList(new AxisAlignedBB(0,0,0, 1,.5f,1).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
if(pos>5)
fl = fl.getOpposite();
if(pos%3==1)
fw = fw.getOpposite();
float minX = fl==EnumFacing.WEST?.6875f: fl==EnumFacing.EAST?.0625f: fw==EnumFacing.EAST?.0625f: .6875f;
float maxX = fl==EnumFacing.EAST?.3125f: fl==EnumFacing.WEST?.9375f: fw==EnumFacing.EAST?.3125f: .9375f;
float minZ = fl==EnumFacing.NORTH?.6875f: fl==EnumFacing.SOUTH?.0625f: fw==EnumFacing.SOUTH?.0625f: .6875f;
float maxZ = fl==EnumFacing.SOUTH?.3125f: fl==EnumFacing.NORTH?.9375f: fw==EnumFacing.SOUTH?.3125f: .9375f;
list.add(new AxisAlignedBB(minX,.5f,minZ, maxX,1.1875f,maxZ).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
if(pos==4)
{
minX = fl==EnumFacing.WEST?.375f: fl==EnumFacing.EAST?.625f: fw==EnumFacing.WEST?-.125f: 0;
maxX = fl==EnumFacing.EAST?.375f: fl==EnumFacing.WEST?.625f: fw==EnumFacing.EAST?1.125f: 1;
minZ = fl==EnumFacing.NORTH?.375f: fl==EnumFacing.SOUTH?.625f: fw==EnumFacing.NORTH?-.125f: 0;
maxZ = fl==EnumFacing.SOUTH?.375f: fl==EnumFacing.NORTH?.625f: fw==EnumFacing.SOUTH?1.125f: 1;
list.add(new AxisAlignedBB(minX,.5f,minZ, maxX,.75f,maxZ).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
minX = fl==EnumFacing.WEST?-.125f: fl==EnumFacing.EAST?.625f: fw==EnumFacing.WEST?-.125f: .875f;
maxX = fl==EnumFacing.EAST?1.125f: fl==EnumFacing.WEST?.375f: fw==EnumFacing.EAST?1.125f: .125f;
minZ = fl==EnumFacing.NORTH?-.125f: fl==EnumFacing.SOUTH?.625f: fw==EnumFacing.NORTH?-.125f: .875f;
maxZ = fl==EnumFacing.SOUTH?1.25f: fl==EnumFacing.NORTH?.375f: fw==EnumFacing.SOUTH?1.125f: .125f;
list.add(new AxisAlignedBB(minX,.5f,minZ, maxX,.75f,maxZ).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
minX = fl==EnumFacing.WEST?-.125f: fl==EnumFacing.EAST?.875f: fw==EnumFacing.WEST?-.125f: .875f;
maxX = fl==EnumFacing.EAST?1.125f: fl==EnumFacing.WEST?.125f: fw==EnumFacing.EAST?1.125f: .125f;
minZ = fl==EnumFacing.NORTH?-.125f: fl==EnumFacing.SOUTH?.875f: fw==EnumFacing.NORTH?-.125f: .875f;
maxZ = fl==EnumFacing.SOUTH?1.25f: fl==EnumFacing.NORTH?.125f: fw==EnumFacing.SOUTH?1.125f: .125f;
list.add(new AxisAlignedBB(minX,.75f,minZ, maxX,1,maxZ).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
}
return list;
}
if((pos==12||pos==13||pos==15||pos==16)||(pos==21||pos==22||pos==24||pos==25))
{
List<AxisAlignedBB> list = new ArrayList<AxisAlignedBB>(2);
if(pos%9>5)
fl = fl.getOpposite();
if(pos%3==1)
fw = fw.getOpposite();
float minY = pos<18?.1875f:-.8125f;
float maxY = pos<18?2:1;
float minX = fl==EnumFacing.WEST?0: fl==EnumFacing.EAST?.0625f: fw==EnumFacing.EAST?.0625f: 0;
float maxX = fl==EnumFacing.EAST?1: fl==EnumFacing.WEST?.9375f: fw==EnumFacing.EAST?1: .9375f;
float minZ = fl==EnumFacing.NORTH?0: fl==EnumFacing.SOUTH?.0625f: fw==EnumFacing.SOUTH?.0625f: 0;
float maxZ = fl==EnumFacing.SOUTH?1: fl==EnumFacing.NORTH?.9375f: fw==EnumFacing.SOUTH?1: .9375f;
list.add(new AxisAlignedBB(minX,minY,minZ, maxX,maxY,maxZ).offset(getPos().getX(),getPos().getY(),getPos().getZ()));
return list;
}
return null;
}
@Override
public boolean isOverrideBox(AxisAlignedBB box, EntityPlayer player, RayTraceResult mop, ArrayList<AxisAlignedBB> list)
{
return false;
}
@Override
public List<AxisAlignedBB> getAdvancedColisionBounds()
{
return getAdvancedSelectionBounds();
}
@Override
public int[] getEnergyPos()
{
return new int[]{9};
}
@Override
public int[] getRedstonePos()
{
return new int[]{11};
}
@Override
public boolean isInWorldProcessingMachine()
{
return false;
}
@Override
public boolean additionalCanProcessCheck(MultiblockProcess<FermenterRecipe> process)
{
return true;
}
@Override
public void doProcessOutput(ItemStack output)
{
BlockPos pos = getPos().offset(facing,2);
TileEntity inventoryTile = this.worldObj.getTileEntity(pos);
if(inventoryTile!=null)
output = Utils.insertStackIntoInventory(inventoryTile, output, facing.getOpposite());
if(output!=null)
Utils.dropStackAtPos(worldObj, pos, output, facing);
}
@Override
public void doProcessFluidOutput(FluidStack output)
{
}
@Override
public void onProcessFinish(MultiblockProcess<FermenterRecipe> process)
{
}
@Override
public int getMaxProcessPerTick()
{
return 8;
}
@Override
public int getProcessQueueMaxLength()
{
return 8;
}
@Override
public float getMinProcessDistance(MultiblockProcess<FermenterRecipe> process)
{
return 0;
}
@Override
public ItemStack[] getInventory()
{
return inventory;
}
@Override
public boolean isStackValid(int slot, ItemStack stack)
{
return true;
}
@Override
public int getSlotLimit(int slot)
{
return 64;
}
@Override
public int[] getOutputSlots()
{
return new int[]{8};
}
@Override
public int[] getOutputTanks()
{
return new int[]{0};
}
@Override
public IFluidTank[] getInternalTanks()
{
return tanks;
}
@Override
protected IFluidTank[] getAccessibleFluidTanks(EnumFacing side)
{
TileEntityFermenter master = this.master();
if(master!=null && pos==5 && (side==null||side==(mirrored?facing.rotateYCCW():facing.rotateY())))
return master.tanks;
return new FluidTank[0];
}
@Override
protected boolean canFillTankFrom(int iTank, EnumFacing side, FluidStack resources)
{
return false;
}
@Override
protected boolean canDrainTankFrom(int iTank, EnumFacing side)
{
return true;
}
@Override
public void doGraphicalUpdates(int slot)
{
this.markDirty();
this.markContainingBlockForUpdate(null);
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
if((pos==15||pos==13)&&capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return true;
return super.hasCapability(capability, facing);
}
IItemHandler insertionHandler = new IEInventoryHandler(8, this, 0, new boolean[]{true,true,true,true,true,true,true,true}, new boolean[8]);
IItemHandler extractionHandler = new IEInventoryHandler(1, this, 8, new boolean[1], new boolean[]{true});
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
if((pos==15||pos==13)&&capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
{
TileEntityFermenter master = master();
if(master==null)
return null;
if(pos==15)
return (T)master.insertionHandler;
if(pos==13)
return (T)master.extractionHandler;
return null;
}
return super.getCapability(capability, facing);
}
@Override
public FermenterRecipe findRecipeForInsertion(ItemStack inserting)
{
return FermenterRecipe.findRecipe(inserting);
}
@Override
protected FermenterRecipe readRecipeFromNBT(NBTTagCompound tag)
{
return FermenterRecipe.loadFromNBT(tag);
}
@Override
public boolean canOpenGui()
{
return formed;
}
@Override
public int getGuiID()
{
return Lib.GUIID_Fermenter;
}
@Override
public TileEntity getGuiMaster()
{
return master();
}
}