package crazypants.enderio.machine.tank;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.MathHelper;
import net.minecraft.world.EnumSkyBlock;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidContainerItem;
import net.minecraftforge.fluids.IFluidHandler;
import com.enderio.core.api.common.util.ITankAccess;
import com.enderio.core.common.util.BlockCoord;
import com.enderio.core.common.util.FluidUtil;
import com.enderio.core.common.util.FluidUtil.FluidAndStackResult;
import com.enderio.core.common.util.ItemUtil;
import crazypants.enderio.machine.AbstractMachineEntity;
import crazypants.enderio.machine.IoMode;
import crazypants.enderio.machine.SlotDefinition;
import crazypants.enderio.machine.tank.GuiTank.VoidMode;
import crazypants.enderio.network.PacketHandler;
import crazypants.enderio.tool.ArrayMappingTool;
import crazypants.enderio.tool.SmartTank;
public class TileTank extends AbstractMachineEntity implements IFluidHandler, ITankAccess {
private static int IO_MB_TICK = 100;
protected SmartTank tank;// = new FluidTankEio(16000);
protected int lastUpdateLevel = -1;
private boolean tankDirty = false;
private Fluid lastFluid = null;
private VoidMode voidMode = VoidMode.NEVER;
public TileTank(int meta) {
super(new SlotDefinition(0, 2, 3, 4, -1, -1));
if(meta == 1) {
tank = new SmartTank(32000);
} else {
tank = new SmartTank(16000);
}
}
public TileTank() {
this(0);
}
@Override
protected boolean doPush(ForgeDirection dir) {
if(isSideDisabled(dir.ordinal())) {
return false;
}
boolean res = super.doPush(dir);
if(tank.getFluidAmount() > 0) {
BlockCoord loc = getLocation().getLocation(dir);
IFluidHandler target = FluidUtil.getFluidHandler(worldObj, loc);
if(target != null) {
if(target.canFill(dir.getOpposite(), tank.getFluid().getFluid())) {
FluidStack push = tank.getFluid().copy();
push.amount = Math.min(push.amount, IO_MB_TICK);
int filled = target.fill(dir.getOpposite(), push, true);
if(filled > 0) {
tank.drain(filled, true);
tankDirty = true;
return res;
}
}
}
}
return res;
}
@Override
protected boolean doPull(ForgeDirection dir) {
if(isSideDisabled(dir.ordinal())) {
return false;
}
boolean res = super.doPull(dir);
if(tank.getFluidAmount() < tank.getCapacity()) {
BlockCoord loc = getLocation().getLocation(dir);
IFluidHandler target = FluidUtil.getFluidHandler(worldObj, loc);
if(target != null) {
if(tank.getFluidAmount() > 0) {
FluidStack canPull = tank.getFluid().copy();
canPull.amount = tank.getCapacity() - tank.getFluidAmount();
canPull.amount = Math.min(canPull.amount, IO_MB_TICK);
FluidStack drained = target.drain(dir.getOpposite(), canPull, true);
if(drained != null && drained.amount > 0) {
tank.fill(drained, true);
tankDirty = true;
return res;
}
} else {
FluidTankInfo[] infos = target.getTankInfo(dir.getOpposite());
if(infos != null) {
for (FluidTankInfo info : infos) {
if(info.fluid != null && info.fluid.amount > 0) {
if(canFill(dir, info.fluid.getFluid())) {
FluidStack canPull = info.fluid.copy();
canPull.amount = Math.min(IO_MB_TICK, canPull.amount);
FluidStack drained = target.drain(dir.getOpposite(), canPull, true);
if(drained != null && drained.amount > 0) {
tank.fill(drained, true);
tankDirty = true;
return res;
}
}
}
}
}
}
}
}
return res;
}
@Override
public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
if(!canFill(from)) {
return 0;
}
return fillInternal(resource, doFill);
}
int fillInternal(FluidStack resource, boolean doFill) {
int res = tank.fill(resource, doFill);
if(res > 0 && doFill) {
tankDirty = true;
}
return res;
}
@Override
public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
if(!canDrain(from)) {
return null;
}
return drainInternal(resource, doDrain);
}
FluidStack drainInternal(FluidStack resource, boolean doDrain) {
FluidStack res = tank.drain(resource, doDrain);
if(res != null && res.amount > 0 && doDrain) {
tankDirty = true;
}
return res;
}
@Override
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
if(!canDrain(from)) {
return null;
}
return drainInternal(maxDrain, doDrain);
}
FluidStack drainInternal(int maxDrain, boolean doDrain) {
FluidStack res = tank.drain(maxDrain, doDrain);
if(res != null && res.amount > 0 && doDrain) {
tankDirty = true;
}
return res;
}
@Override
public boolean canFill(ForgeDirection from, Fluid fluid) {
return canFill(from) && fluid != null
&& (tank.getFluidAmount() > 0 && tank.getFluid().getFluidID() == fluid.getID() || tank.getFluidAmount() == 0);
}
private boolean canFill(ForgeDirection from) {
IoMode mode = getIoMode(from);
return mode != IoMode.PUSH && mode != IoMode.DISABLED;
}
@Override
public boolean canDrain(ForgeDirection from, Fluid fluid) {
return canDrain(from) && tank.canDrainFluidType(fluid);
}
private boolean canDrain(ForgeDirection from) {
IoMode mode = getIoMode(from);
return mode != IoMode.PULL && mode != IoMode.DISABLED;
}
@Override
public FluidTankInfo[] getTankInfo(ForgeDirection from) {
return new FluidTankInfo[] { new FluidTankInfo(tank) };
}
private int getFilledLevel() {
int level = (int) Math.floor(16 * tank.getFilledRatio());
if(level == 0 && tank.getFluidAmount() > 0) {
level = 1;
}
return level;
}
public boolean canVoidItems() {
return tank.getFluid() != null && tank.getFluid().getFluid().getTemperature() > 973;
}
public VoidMode getVoidMode() {
return voidMode;
}
public void setVoidMode(VoidMode mode) {
this.voidMode = mode;
}
@Override
public String getMachineName() {
return "tank";
}
@Override
protected boolean isMachineItemValidForSlot(int i, ItemStack item) {
if (canVoidItems() && voidMode == VoidMode.ALWAYS && i < getSlotDefinition().getMaxInputSlot()) {
return false;
}
if (i == 0) {
FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(item);
if (fluid != null) {
return true;
}
if (item.getItem() == Items.water_bucket) {
return true;
}
if (item.getItem() == Items.lava_bucket) {
return true;
}
if (item.getItem() instanceof IFluidContainerItem && ((IFluidContainerItem) item.getItem()).getFluid(item) != null) {
return true;
}
return false;
} else if (i == 1) {
if (item.getItem() instanceof IFluidContainerItem
&& (((IFluidContainerItem) item.getItem()).getFluid(item) == null || ((IFluidContainerItem) item.getItem()).getFluid(item).amount < ((IFluidContainerItem) item
.getItem()).getCapacity(item))) {
return true;
}
return FluidContainerRegistry.isEmptyContainer(item) || item.getItem() == Items.bucket;
} else if (i == 2 && canVoidItems()) {
return voidMode == VoidMode.ALWAYS || (voidMode == VoidMode.NEVER ? false : !FluidContainerRegistry.isContainer(item));
}
return false;
}
@Override
public void setInventorySlotContents(int slot, ItemStack contents) {
super.setInventorySlotContents(slot, contents);
}
@Override
public boolean isActive() {
return false;
}
@Override
protected boolean processTasks(boolean redstoneCheckPassed) {
boolean res = processItems(redstoneCheckPassed);
int filledLevel = getFilledLevel();
if(lastUpdateLevel != filledLevel) {
lastUpdateLevel = filledLevel;
tankDirty = false;
return true;
}
if(tankDirty && shouldDoWorkThisTick(10)) {
PacketHandler.sendToAllAround(new PacketTankFluid(this), this);
worldObj.func_147453_f(xCoord, yCoord, zCoord, getBlockType());
Fluid held = tank.getFluid() == null ? null : tank.getFluid().getFluid();
if(lastFluid != held) {
lastFluid = held;
worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord, zCoord);
}
tankDirty = false;
}
return res;
}
public int getComparatorOutput() {
FluidTankInfo info = getTankInfo(null)[0];
if (info == null || info.fluid == null) {
return 0;
}
return info.fluid.amount == 0 ? 0 : (int) (1 + ((double) info.fluid.amount / (double) info.capacity) * 14);
}
private boolean processItems(boolean redstoneCheckPassed) {
if(!redstoneCheckPassed) {
return false;
}
if(!shouldDoWorkThisTick(20)) {
return false;
}
if (canVoidItems()) {
inventory[2] = null;
}
return drainFullContainer() || fillEmptyContainer();
}
private boolean fillEmptyContainer() {
FluidAndStackResult fill = FluidUtil.tryFillContainer(inventory[getSlotDefinition().getMinInputSlot() + 1], getOutputTanks()[0].getFluid());
if (fill.result.fluidStack == null) {
return false;
}
int slot = getSlotDefinition().getMaxOutputSlot();
if (inventory[slot] != null) {
if (inventory[slot].isStackable() && ItemUtil.areStackMergable(inventory[slot], fill.result.itemStack)
&& inventory[slot].stackSize < inventory[slot].getMaxStackSize()) {
fill.result.itemStack.stackSize += inventory[slot].stackSize;
} else {
return false;
}
}
getOutputTanks()[0].setFluid(fill.remainder.fluidStack);
setInventorySlotContents(getSlotDefinition().getMinInputSlot() + 1, fill.remainder.itemStack);
setInventorySlotContents(slot, fill.result.itemStack);
setTanksDirty();
markDirty();
return false;
}
private boolean drainFullContainer() {
FluidAndStackResult fill = FluidUtil.tryDrainContainer(inventory[getSlotDefinition().getMinInputSlot()], this);
if (fill.result.fluidStack == null) {
return false;
}
int slot = getSlotDefinition().getMinOutputSlot();
if (inventory[slot] != null && fill.result.itemStack != null) {
if (inventory[slot].isStackable() && ItemUtil.areStackMergable(inventory[slot], fill.result.itemStack)
&& inventory[slot].stackSize < inventory[slot].getMaxStackSize()) {
fill.result.itemStack.stackSize += inventory[slot].stackSize;
} else {
return false;
}
}
getInputTank(fill.result.fluidStack).setFluid(fill.remainder.fluidStack);
setInventorySlotContents(getSlotDefinition().getMinInputSlot(), fill.remainder.itemStack);
if (fill.result.itemStack != null) {
setInventorySlotContents(slot, fill.result.itemStack);
}
setTanksDirty();
markDirty();
return false;
}
@Override
public void writeCommon(NBTTagCompound nbtRoot) {
super.writeCommon(nbtRoot);
nbtRoot.setInteger("slotLayoutVersion", 1);
nbtRoot.setInteger("tankType", getBlockMetadata());
nbtRoot.setInteger("voidMode", voidMode.ordinal());
saveTank(nbtRoot, tank);
}
public static void saveTank(NBTTagCompound nbtRoot, FluidTank tank) {
if(tank.getFluidAmount() > 0) {
NBTTagCompound fluidRoot = new NBTTagCompound();
tank.getFluid().writeToNBT(fluidRoot);
nbtRoot.setTag("tankContents", fluidRoot);
} else {
nbtRoot.removeTag("tankContents");
}
}
@Override
public void readCommon(NBTTagCompound nbtRoot) {
super.readCommon(nbtRoot);
tank = loadTank(nbtRoot);
if (nbtRoot.hasKey("voidMode")) {
voidMode = VoidMode.values()[nbtRoot.getInteger("voidMode")];
}
int slotLayoutVersion = nbtRoot.getInteger("slotLayoutVersion");
if (slotLayoutVersion == 0) {
inventory = new ArrayMappingTool<ItemStack>("IIOO", "IIIOO").map(inventory);
}
}
public static SmartTank loadTank(NBTTagCompound nbtRoot) {
int tankType = nbtRoot.getInteger("tankType");
tankType = MathHelper.clamp_int(tankType, 0, 1);
SmartTank ret;
if(tankType == 1) {
ret = new SmartTank(32000);
} else {
ret = new SmartTank(16000);
}
if(nbtRoot.hasKey("tankContents")) {
FluidStack fl = FluidStack.loadFluidStackFromNBT((NBTTagCompound) nbtRoot.getTag("tankContents"));
ret.setFluid(fl);
} else {
ret.setFluid(null);
}
return ret;
}
@Override
public FluidTank getInputTank(FluidStack forFluidType) {
return tank;
}
@Override
public FluidTank[] getOutputTanks() {
return new FluidTank[] { tank };
}
@Override
public void setTanksDirty() {
tankDirty = true;
}
}