package blusunrize.immersiveengineering.common.blocks.metal; import blusunrize.immersiveengineering.api.IEEnums.SideConfig; import blusunrize.immersiveengineering.api.Lib; import blusunrize.immersiveengineering.api.energy.immersiveflux.FluxStorage; import blusunrize.immersiveengineering.api.fluid.IFluidPipe; import blusunrize.immersiveengineering.common.Config.IEConfig; import blusunrize.immersiveengineering.common.IEContent; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IBlockBounds; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IBlockOverlayText; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IConfigurableSides; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IHasDummyBlocks; import blusunrize.immersiveengineering.common.blocks.TileEntityIEBase; import blusunrize.immersiveengineering.common.blocks.metal.TileEntityFluidPipe.DirectionalFluidOutput; import blusunrize.immersiveengineering.common.util.ChatUtils; import blusunrize.immersiveengineering.common.util.EnergyHelper.IEForgeEnergyWrapper; import blusunrize.immersiveengineering.common.util.EnergyHelper.IIEInternalFluxHandler; import blusunrize.immersiveengineering.common.util.Utils; import net.minecraft.block.state.IBlockState; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.TextComponentTranslation; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidTankProperties; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.HashMap; public class TileEntityFluidPump extends TileEntityIEBase implements ITickable, IBlockBounds, IHasDummyBlocks, IConfigurableSides, IFluidPipe, IIEInternalFluxHandler, IBlockOverlayText { public int[] sideConfig = new int[] {0,-1,-1,-1,-1,-1}; public boolean dummy = false; public FluidTank tank = new FluidTank(4000); public FluxStorage energyStorage = new FluxStorage(8000); public boolean placeCobble = true; boolean checkingArea = false; Fluid searchFluid = null; ArrayList<BlockPos> openList = new ArrayList<BlockPos>(); ArrayList<BlockPos> closedList = new ArrayList<BlockPos>(); ArrayList<BlockPos> checked = new ArrayList<BlockPos>(); @Override public void update() { if(dummy || worldObj.isRemote) return; if(tank.getFluidAmount()>0) { int i = outputFluid(tank.getFluid(), false); tank.drain(i, true); } if(worldObj.isBlockIndirectlyGettingPowered(getPos())>0||worldObj.isBlockIndirectlyGettingPowered(getPos().add(0,1,0))>0) { for(EnumFacing f : EnumFacing.values()) if(sideConfig[f.ordinal()]==0) { TileEntity tile = worldObj.getTileEntity(getPos().offset(f)); if(tile!=null && tile.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, f.getOpposite())) { IFluidHandler handler = tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, f.getOpposite()); FluidStack drain = handler.drain(500, false); if(drain == null || drain.amount <= 0) continue; int out = this.outputFluid(drain, false); handler.drain(out, true); } else if(worldObj.getTotalWorldTime()%20==((getPos().getX()^getPos().getZ())&19) && worldObj.getBlockState(getPos().offset(f)).getBlock()==Blocks.WATER && IEConfig.Machines.pump_infiniteWater && tank.fill(new FluidStack(FluidRegistry.WATER,1000), false)==1000 && this.energyStorage.extractEnergy(IEConfig.Machines.pump_consumption, true)>= IEConfig.Machines.pump_consumption) { int connectedSources = 0; for(EnumFacing f2 : EnumFacing.HORIZONTALS) { IBlockState waterState = worldObj.getBlockState(getPos().offset(f).offset(f2)); if(waterState.getBlock()==Blocks.WATER && Blocks.WATER.getMetaFromState(waterState)==0) connectedSources++; } if(connectedSources>1) { this.energyStorage.extractEnergy(IEConfig.Machines.pump_consumption, false); this.tank.fill(new FluidStack(FluidRegistry.WATER,1000), true); } } } if(worldObj.getTotalWorldTime()%40==(((getPos().getX()^getPos().getZ()))%40+40)%40) { if(closedList.isEmpty()) prepareAreaCheck(); else { int target = closedList.size()-1; BlockPos pos = closedList.get(target); FluidStack fs = Utils.drainFluidBlock(worldObj, pos, false); if(fs==null) closedList.remove(target); else if(tank.fill(fs, false)==fs.amount && this.energyStorage.extractEnergy(IEConfig.Machines.pump_consumption, true)>= IEConfig.Machines.pump_consumption) { this.energyStorage.extractEnergy(IEConfig.Machines.pump_consumption, false); fs = Utils.drainFluidBlock(worldObj, pos, true); // int rainbow = (closedList.size()%11)+1; // if(rainbow>6) // rainbow+=2; // if(rainbow>9) // rainbow++; // worldObj.setBlock( cc.posX,cc.posY,cc.posZ, Blocks.stained_glass,rainbow, 0x3); if(IEConfig.Machines.pump_placeCobble && placeCobble) worldObj.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); this.tank.fill(fs, true); closedList.remove(target); } } } } if(checkingArea) checkAreaTick(); } public void prepareAreaCheck() { openList.clear(); closedList.clear(); checked.clear(); for(EnumFacing f : EnumFacing.values()) if(sideConfig[f.ordinal()]==0) { openList.add(getPos().offset(f)); checkingArea = true; } } public void checkAreaTick() { BlockPos next = null; final int closedListMax = 2048; int timeout = 0; while(timeout<64 && closedList.size()<closedListMax && !openList.isEmpty()) { timeout++; next = openList.get(0); if(!checked.contains(next)) { Fluid fluid = Utils.getRelatedFluid(worldObj, next); if(fluid!=null && (fluid!=FluidRegistry.WATER||!IEConfig.Machines.pump_infiniteWater) && (searchFluid==null || fluid==searchFluid)) { if(searchFluid==null) searchFluid = fluid; if (Utils.drainFluidBlock(worldObj, next, false)!=null) closedList.add(next); for(EnumFacing f : EnumFacing.values()) { BlockPos pos2 = next.offset(f); fluid = Utils.getRelatedFluid(worldObj, pos2); if(!checked.contains(pos2) && !closedList.contains(pos2) && !openList.contains(pos2) && fluid!=null && (fluid!=FluidRegistry.WATER||!IEConfig.Machines.pump_infiniteWater) && (searchFluid==null || fluid==searchFluid)) openList.add(pos2); } } checked.add(next); } openList.remove(0); } if(closedList.size()>=closedListMax || openList.isEmpty()) checkingArea = false; } public int outputFluid(FluidStack fs, boolean simulate) { if(fs==null) return 0; int canAccept = fs.amount; if(canAccept<=0) return 0; int accelPower = IEConfig.Machines.pump_consumption_accelerate; final int fluidForSort = canAccept; int sum = 0; HashMap<DirectionalFluidOutput,Integer> sorting = new HashMap<DirectionalFluidOutput,Integer>(); for(EnumFacing f : EnumFacing.values()) if(sideConfig[f.ordinal()]==1) { TileEntity tile = worldObj.getTileEntity(getPos().offset(f)); if(tile!=null && tile.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, f.getOpposite())) { IFluidHandler handler = tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, f.getOpposite()); FluidStack insertResource = new FluidStack(fs.getFluid(), fs.amount); if(tile instanceof TileEntityFluidPipe && this.energyStorage.extractEnergy(accelPower, true) >= accelPower) { insertResource.tag = new NBTTagCompound(); insertResource.tag.setBoolean("pressurized", true); } int temp = handler.fill(insertResource, false); if(temp > 0) { sorting.put(new DirectionalFluidOutput(handler, tile, f), temp); sum += temp; } } } if(sum>0) { int f = 0; int i=0; for(DirectionalFluidOutput output : sorting.keySet()) { float prio = sorting.get(output)/(float)sum; int amount = (int)(fluidForSort*prio); if(i++ == sorting.size()-1) amount = canAccept; FluidStack insertResource = new FluidStack(fs.getFluid(), amount); if(output.containingTile instanceof TileEntityFluidPipe && this.energyStorage.extractEnergy(accelPower,true)>=accelPower) { this.energyStorage.extractEnergy(accelPower,false); insertResource.tag = new NBTTagCompound(); insertResource.tag.setBoolean("pressurized", true); } int r = output.output.fill(insertResource, !simulate); f += r; canAccept -= r; if(canAccept<=0) break; } return f; } return 0; } @Override public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) { sideConfig = nbt.getIntArray("sideConfig"); if(sideConfig==null || sideConfig.length!=6) sideConfig = new int[]{0,-1,-1,-1,-1,-1}; dummy = nbt.getBoolean("dummy"); if(nbt.hasKey("placeCobble")) placeCobble = nbt.getBoolean("placeCobble"); tank.readFromNBT(nbt.getCompoundTag("tank")); energyStorage.readFromNBT(nbt); if(descPacket) this.markContainingBlockForUpdate(null); } @Override public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) { nbt.setIntArray("sideConfig", sideConfig); nbt.setBoolean("dummy", dummy); nbt.setBoolean("placeCobble", placeCobble); nbt.setTag("tank", tank.writeToNBT(new NBTTagCompound())); energyStorage.writeToNBT(nbt); } @Override public SideConfig getSideConfig(int side) { return (side>=0&&side<6)?SideConfig.values()[this.sideConfig[side]+1]: SideConfig.NONE; } @Override public boolean toggleSide(int side, EntityPlayer p) { if(side!=1 && !dummy) { sideConfig[side]++; if(sideConfig[side]>1) sideConfig[side]=-1; this.markDirty(); this.markContainingBlockForUpdate(null); worldObj.addBlockEvent(getPos(), this.getBlockType(), 0, 0); return true; } else if (p.isSneaking()) { TileEntityFluidPump master = this; if (dummy) { TileEntity tmp = worldObj.getTileEntity(pos.down()); if (tmp instanceof TileEntityFluidPump) master = (TileEntityFluidPump) tmp; } master.placeCobble = !master.placeCobble; ChatUtils.sendServerNoSpamMessages(p, new TextComponentTranslation(Lib.CHAT_INFO+"pump.placeCobble."+master.placeCobble)); return true; } return false; } SidedFluidHandler[] sidedFluidHandler = new SidedFluidHandler[6]; @Override public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing) { if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && facing!=null && !dummy) return true; return super.hasCapability(capability, facing); } @Override public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing) { if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && facing!=null && !dummy) { if(sidedFluidHandler[facing.ordinal()]==null) sidedFluidHandler[facing.ordinal()] = new SidedFluidHandler(this, facing); return (T)sidedFluidHandler[facing.ordinal()]; } return super.getCapability(capability, facing); } @Override public String[] getOverlayText(EntityPlayer player, RayTraceResult mop, boolean hammer) { if(hammer && IEConfig.colourblindSupport && !dummy) { int i = sideConfig[Math.min(sideConfig.length-1, mop.sideHit.ordinal())]; int j = sideConfig[Math.min(sideConfig.length-1, mop.sideHit.getOpposite().ordinal())]; return new String[]{ I18n.format(Lib.DESC_INFO+"blockSide.facing") +": "+ I18n.format(Lib.DESC_INFO+"blockSide.connectFluid."+i), I18n.format(Lib.DESC_INFO+"blockSide.opposite") +": "+ I18n.format(Lib.DESC_INFO+"blockSide.connectFluid."+j) }; } return null; } @Override public boolean useNixieFont(EntityPlayer player, RayTraceResult mop) { return false; } static class SidedFluidHandler implements IFluidHandler { TileEntityFluidPump pump; EnumFacing facing; SidedFluidHandler(TileEntityFluidPump pump, EnumFacing facing) { this.pump = pump; this.facing = facing; } @Override public int fill(FluidStack resource, boolean doFill) { if (resource == null || pump.sideConfig[facing.ordinal()]!=0) return 0; return pump.tank.fill(resource, doFill); } @Override public FluidStack drain(FluidStack resource, boolean doDrain) { if (resource == null) return null; return this.drain(resource.amount, doDrain); } @Override public FluidStack drain(int maxDrain, boolean doDrain) { if (pump.sideConfig[facing.ordinal()]!=1) return null; return pump.tank.drain(maxDrain, doDrain); } @Override public IFluidTankProperties[] getTankProperties() { return pump.tank.getTankProperties(); } } @Nonnull @Override public FluxStorage getFluxStorage() { if(dummy) { TileEntity te = worldObj.getTileEntity(getPos().add(0,-1,0)); if(te instanceof TileEntityFluidPump) return ((TileEntityFluidPump)te).getFluxStorage(); } return energyStorage; } @Nonnull @Override public SideConfig getEnergySideConfig(EnumFacing facing) { return dummy&&facing==EnumFacing.UP?SideConfig.INPUT:SideConfig.NONE; } IEForgeEnergyWrapper wrapper = new IEForgeEnergyWrapper(this, EnumFacing.UP); @Override public IEForgeEnergyWrapper getCapabilityWrapper(EnumFacing facing) { if(!dummy&&facing==EnumFacing.UP) return null; return wrapper; } @Override public boolean isDummy() { return dummy; } @Override public void placeDummies(BlockPos pos, IBlockState state, EnumFacing side, float hitX, float hitY, float hitZ) { worldObj.setBlockState(pos.add(0,1,0), state); ((TileEntityFluidPump)worldObj.getTileEntity(pos.add(0,1,0))).dummy = true; } @Override public void breakDummies(BlockPos pos, IBlockState state) { for(int i=0; i<=1; i++) if(Utils.isBlockAt(worldObj, getPos().add(0, dummy ? -1 : 0, 0).add(0, i, 0), IEContent.blockMetalDevice0, BlockTypes_MetalDevice0.FLUID_PUMP.getMeta())) worldObj.setBlockToAir(getPos().add(0, dummy ? -1 : 0, 0).add(0, i, 0)); } @Override public float[] getBlockBounds() { if(!dummy) return null; return new float[]{.1875f,0,.1875f, .8125f,1,.8125f}; } @Override public boolean canOutputPressurized(boolean consumePower) { int accelPower = IEConfig.Machines.pump_consumption_accelerate; if(energyStorage.extractEnergy(accelPower, true)>=accelPower) { if(consumePower) energyStorage.extractEnergy(accelPower, false); return true; } return false; } @Override public boolean hasOutputConnection(EnumFacing side) { return side!=null&&this.sideConfig[side.ordinal()]==1; } }