package crazypants.enderio.machine.generator.combustion; import net.minecraft.block.Block; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; 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.IFluidHandler; import com.enderio.core.api.common.util.ITankAccess; import com.enderio.core.common.util.BlockCoord; import com.enderio.core.common.util.FluidUtil; import crazypants.enderio.ModObject; import crazypants.enderio.fluid.FluidFuelRegister; import crazypants.enderio.fluid.IFluidCoolant; import crazypants.enderio.fluid.IFluidFuel; import crazypants.enderio.machine.IoMode; import crazypants.enderio.machine.SlotDefinition; import crazypants.enderio.machine.generator.AbstractGeneratorEntity; import crazypants.enderio.network.PacketHandler; import crazypants.enderio.power.PowerDistributor; public class TileCombustionGenerator extends AbstractGeneratorEntity implements IFluidHandler, ITankAccess { private final FluidTank coolantTank = new FluidTank(FluidContainerRegistry.BUCKET_VOLUME * 5); private final FluidTank fuelTank = new FluidTank(FluidContainerRegistry.BUCKET_VOLUME * 5); private boolean tanksDirty; private int ticksRemaingFuel; private int ticksRemaingCoolant; private boolean active; private PowerDistributor powerDis; private int generated; private boolean inPause = false; private boolean generatedDirty = false; private int maxOutputTick = 1280; private static int IO_MB_TICK = 250; private IFluidFuel curFuel; private IFluidCoolant curCoolant; public TileCombustionGenerator() { super(new SlotDefinition(-1, -1, -1, -1, -1, -1)); } @Override protected boolean doPull(ForgeDirection dir) { boolean res = super.doPull(dir); BlockCoord loc = getLocation().getLocation(dir); IFluidHandler target = FluidUtil.getFluidHandler(worldObj, loc); if(target != null) { 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, false); if(drained != null && drained.amount > 0) { int filled = fill(dir, drained, false); if(filled > 0) { drained = target.drain(dir.getOpposite(), filled, true); fill(dir, drained, true); return res; } } } } } } } return res; } @Override public boolean supportsMode(ForgeDirection faceHit, IoMode mode) { return mode != IoMode.PUSH && mode != IoMode.PUSH_PULL; } @Override public String getMachineName() { return ModObject.blockCombustionGenerator.unlocalisedName; } @Override protected boolean isMachineItemValidForSlot(int i, ItemStack itemstack) { return false; } @Override public boolean isActive() { return active; } @Override public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { if(resource == null || resource.getFluid() == null || !canFill(from, resource.getFluid())) { return 0; } int res = 0; IFluidCoolant cool = FluidFuelRegister.instance.getCoolant(resource.getFluid()); if(cool != null) { res = getCoolantTank().fill(resource, doFill); } else { IFluidFuel f = FluidFuelRegister.instance.getFuel(resource.getFluid()); if(f != null) { res = getFuelTank().fill(resource, doFill); } } if(res > 0) { tanksDirty = true; } return res; } @Override public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { return null; } @Override public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { return null; } @Override public void onNeighborBlockChange(Block blockId) { super.onNeighborBlockChange(blockId); if(powerDis != null) { powerDis.neighboursChanged(); } } @Override protected boolean processTasks(boolean redstoneChecksPassed) { boolean res = false; if(!redstoneChecksPassed) { if(active) { active = false; res = true; } return res; } else { int lastGenerated = generated; boolean isActive = generateEnergy(); if(isActive != active) { active = isActive; res = true; } if(lastGenerated != generated) { generatedDirty = true; } if(getEnergyStored() >= getMaxEnergyStored()) { inPause = true; } transmitEnergy(); } if(tanksDirty && shouldDoWorkThisTick(10)) { PacketHandler.sendToAllAround(new PacketCombustionTank(this), this); tanksDirty = false; } if(generatedDirty && shouldDoWorkThisTick(10)) { generatedDirty = false; res = true; } return res; } private boolean transmitEnergy() { if(getEnergyStored() <= 0) { return false; } if(powerDis == null) { powerDis = new PowerDistributor(new BlockCoord(this)); } int transmitted = powerDis.transmitEnergy(worldObj, Math.min(maxOutputTick, getEnergyStored())); setEnergyStored(getEnergyStored() - transmitted); return transmitted > 0; } private boolean generateEnergy() { generated = 0; if((ticksRemaingCoolant <= 0 && getCoolantTank().getFluidAmount() <= 0) || (ticksRemaingFuel <= 0 && getFuelTank().getFluidAmount() <= 0) || getEnergyStored() >= getMaxEnergyStored()) { return false; } //once full, don't start again until we have drained 10 seconds worth of power to prevent //flickering on and off constantly when powering a machine that draws less than this produces if(inPause) { int powerPerCycle = getPowerPerCycle(); if (getEnergyStored() >= (getMaxEnergyStored() - (powerPerCycle * 200)) && getEnergyStored() > (getMaxEnergyStored() / 8)) { return false; } } inPause = false; ticksRemaingFuel--; if(ticksRemaingFuel <= 0) { curFuel = FluidFuelRegister.instance.getFuel(getFuelTank().getFluid()); if(curFuel == null) { return false; } FluidStack drained = getFuelTank().drain(100, true); if(drained == null) { return false; } ticksRemaingFuel = getNumTicksPerMbFuel(curFuel) * drained.amount; tanksDirty = true; } else if(curFuel == null) { curFuel = FluidFuelRegister.instance.getFuel(getFuelTank().getFluid()); if(curFuel == null) { return false; } } ticksRemaingCoolant--; if(ticksRemaingCoolant <= 0) { updateCoolantFromTank(); if(curCoolant == null) { return false; } FluidStack drained = getCoolantTank().drain(100, true); if(drained == null) { return false; } ticksRemaingCoolant = getNumTicksPerMbCoolant(curCoolant, curFuel) * drained.amount; } else if(curCoolant == null) { updateCoolantFromTank(); if(curCoolant == null) { return false; } } generated = getPowerPerCycle(); setEnergyStored(getEnergyStored() + generated); return getFuelTank().getFluidAmount() > 0 && getCoolantTank().getFluidAmount() > 0; } protected void updateCoolantFromTank() { curCoolant = FluidFuelRegister.instance.getCoolant(getCoolantTank().getFluid()); } private int getPowerPerCycle() { return curFuel == null ? 0 : curFuel.getPowerPerCycle(); } public int getNumTicksPerMbFuel() { if(getFuelTank().getFluidAmount() <= 0) { return 0; } return getNumTicksPerMbFuel(FluidFuelRegister.instance.getFuel(getFuelTank().getFluid().getFluid())); } public int getNumTicksPerMbCoolant() { if(getFuelTank().getFluidAmount() <= 0) { return 0; } if(worldObj.isRemote) { curFuel = FluidFuelRegister.instance.getFuel(getFuelTank().getFluid()); updateCoolantFromTank(); } return getNumTicksPerMbCoolant(curCoolant, curFuel); } static int getNumTicksPerMbFuel(IFluidFuel fuel) { if(fuel == null) { return 0; } return fuel.getTotalBurningTime() / 1000; } public static float HEAT_PER_RF = 0.00023F; static int getNumTicksPerMbCoolant(IFluidCoolant coolant, IFluidFuel fuel) { if(coolant == null || fuel == null) { return 0; } float power = fuel.getPowerPerCycle(); float cooling = coolant.getDegreesCoolingPerMB(100); double toCool = 1d / (HEAT_PER_RF * power); int numTicks = (int) Math.round(toCool / (cooling * 1000)); return numTicks; } @Override public boolean canFill(ForgeDirection from, Fluid fluid) { if(isSideDisabled(from.ordinal()) || fluid == null) { return false; } return FluidFuelRegister.instance.getCoolant(fluid) != null || FluidFuelRegister.instance.getFuel(fluid) != null; } @Override public boolean canDrain(ForgeDirection from, Fluid fluid) { return false; } @Override public FluidTankInfo[] getTankInfo(ForgeDirection from) { if(isSideDisabled(from.ordinal())) { return new FluidTankInfo[0]; } return new FluidTankInfo[] { getCoolantTank().getInfo(), getFuelTank().getInfo() }; } @Override public void readCustomNBT(NBTTagCompound nbtRoot) { super.readCustomNBT(nbtRoot); active = nbtRoot.getBoolean("active"); generated = nbtRoot.getInteger("generatedRF"); } @Override public void readCommon(NBTTagCompound nbtRoot) { super.readCommon(nbtRoot); if(nbtRoot.hasKey("coolantTank")) { NBTTagCompound tankRoot = (NBTTagCompound) nbtRoot.getTag("coolantTank"); if(tankRoot != null) { getCoolantTank().readFromNBT(tankRoot); } else { getCoolantTank().setFluid(null); } } else { getCoolantTank().setFluid(null); } if(nbtRoot.hasKey("fuelTank")) { NBTTagCompound tankRoot = (NBTTagCompound) nbtRoot.getTag("fuelTank"); if(tankRoot != null) { getFuelTank().readFromNBT(tankRoot); } else { getFuelTank().setFluid(null); } } else { getFuelTank().setFluid(null); } ticksRemaingFuel = nbtRoot.getInteger("ticksRemaingFuel"); ticksRemaingCoolant = nbtRoot.getInteger("ticksRemaingCoolant"); } @Override public void writeCommon(NBTTagCompound nbtRoot) { super.writeCommon(nbtRoot); if(getCoolantTank().getFluidAmount() > 0) { NBTTagCompound tankRoot = new NBTTagCompound(); getCoolantTank().writeToNBT(tankRoot); nbtRoot.setTag("coolantTank", tankRoot); } if(getFuelTank().getFluidAmount() > 0) { NBTTagCompound tankRoot = new NBTTagCompound(); getFuelTank().writeToNBT(tankRoot); nbtRoot.setTag("fuelTank", tankRoot); } nbtRoot.setInteger("ticksRemaingFuel", ticksRemaingFuel); nbtRoot.setInteger("ticksRemaingCoolant", ticksRemaingCoolant); } @Override public void writeCustomNBT(NBTTagCompound nbtRoot) { super.writeCustomNBT(nbtRoot); nbtRoot.setBoolean("active", active); nbtRoot.setInteger("generatedRF", generated); } public int getGeneratedLastTick() { if(!active) { return 0; } return generated; } @Override public int getPowerUsePerTick() { if(getFuelTank().getFluidAmount() <= 0) { return 0; } IFluidFuel fuel = FluidFuelRegister.instance.getFuel(getFuelTank().getFluid()); if(fuel == null) { return 0; } return fuel.getPowerPerCycle(); } public FluidTank getCoolantTank() { return coolantTank; } public FluidTank getFuelTank() { return fuelTank; } @Override public FluidTank getInputTank(FluidStack forFluidType) { if (forFluidType != null) { if (FluidFuelRegister.instance.getCoolant(forFluidType.getFluid()) != null) { return coolantTank; } if (FluidFuelRegister.instance.getFuel(forFluidType.getFluid()) != null) { return fuelTank; } } return null; } @Override public FluidTank[] getOutputTanks() { return new FluidTank[] { /* coolantTank, fuelTank */}; } @Override public void setTanksDirty() { tanksDirty = true; } }