package blusunrize.immersiveengineering.common.blocks; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IBlockBounds; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IDirectionalTile; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.IFluidTank; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.FluidTankProperties; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidTankProperties; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class TileEntityMultiblockPart<T extends TileEntityMultiblockPart<T>> extends TileEntityIEBase implements ITickable, IDirectionalTile, IBlockBounds { public boolean formed = false; public int pos=-1; public int[] offset = {0,0,0}; public boolean mirrored = false; public EnumFacing facing = EnumFacing.NORTH; @Override public EnumFacing getFacing() { return this.facing; } @Override public void setFacing(EnumFacing facing) { this.facing = facing; } @Override public int getFacingLimitation() { return 2; } @Override public boolean mirrorFacingOnPlacement(EntityLivingBase placer) { return false; } @Override public boolean canHammerRotate(EnumFacing side, float hitX, float hitY, float hitZ, EntityLivingBase entity) { return false; } @Override public boolean canRotate(EnumFacing axis) { return false; } // ================================= // DATA MANAGEMENT // ================================= @Override public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) { formed = nbt.getBoolean("formed"); pos = nbt.getInteger("pos"); offset = nbt.getIntArray("offset"); mirrored = nbt.getBoolean("mirrored"); facing = EnumFacing.getFront(nbt.getInteger("facing")); } @Override public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) { nbt.setBoolean("formed", formed); nbt.setInteger("pos", pos); nbt.setIntArray("offset", offset); nbt.setBoolean("mirrored", mirrored); nbt.setInteger("facing", facing.ordinal()); } @Override public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing) { if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && facing!=null&&this.getAccessibleFluidTanks(facing).length>0) 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&&this.getAccessibleFluidTanks(facing).length>0) return (T)new MultiblockFluidWrapper(this, facing); return super.getCapability(capability, facing); } // ================================= // FLUID MANAGEMENT // ================================= @Nonnull protected abstract IFluidTank[] getAccessibleFluidTanks(EnumFacing side); protected abstract boolean canFillTankFrom(int iTank, EnumFacing side, FluidStack resource); protected abstract boolean canDrainTankFrom(int iTank, EnumFacing side); public static class MultiblockFluidWrapper implements IFluidHandler { final TileEntityMultiblockPart multiblock; final EnumFacing side; public MultiblockFluidWrapper(TileEntityMultiblockPart multiblock, EnumFacing side) { this.multiblock = multiblock; this.side = side; } @Override public IFluidTankProperties[] getTankProperties() { if(!this.multiblock.formed) return new IFluidTankProperties[0]; IFluidTank[] tanks = this.multiblock.getAccessibleFluidTanks(side); IFluidTankProperties[] array = new IFluidTankProperties[tanks.length]; for(int i=0; i<tanks.length; i++) array[i] = new FluidTankProperties(tanks[i].getFluid(), tanks[i].getCapacity()); return array; } @Override public int fill(FluidStack resource, boolean doFill) { if(!this.multiblock.formed || resource==null) return 0; IFluidTank[] tanks = this.multiblock.getAccessibleFluidTanks(side); int fill = -1; for(int i=0; i<tanks.length; i++) { IFluidTank tank = tanks[i]; if(tank != null && this.multiblock.canFillTankFrom(i, side, resource) && tank.getFluid()!= null && tank.getFluid().isFluidEqual(resource)) { fill = tank.fill(resource, doFill); if(fill>0) break; } } if(fill==-1) for(int i=0; i<tanks.length; i++) { IFluidTank tank = tanks[i]; if(tank != null && this.multiblock.canFillTankFrom(i, side, resource)) { fill = tank.fill(resource, doFill); if(fill>0) break; } } if(fill>0) this.multiblock.updateMasterBlock(null, true); return fill<0?0:fill; } @Nullable @Override public FluidStack drain(FluidStack resource, boolean doDrain) { if(!this.multiblock.formed || resource==null) return null; IFluidTank[] tanks = this.multiblock.getAccessibleFluidTanks(side); FluidStack drain = null; for(int i=0; i<tanks.length; i++) { IFluidTank tank = tanks[i]; if(tank != null && this.multiblock.canDrainTankFrom(i, side)) { if(tank instanceof IFluidHandler) drain = ((IFluidHandler)tank).drain(resource, doDrain); else drain = tank.drain(resource.amount, doDrain); if(drain!=null) break; } } if(drain!=null) this.multiblock.updateMasterBlock(null, true); return drain; } @Nullable @Override public FluidStack drain(int maxDrain, boolean doDrain) { if(!this.multiblock.formed || maxDrain==0) return null; IFluidTank[] tanks = this.multiblock.getAccessibleFluidTanks(side); FluidStack drain = null; for(int i=0; i<tanks.length; i++) { IFluidTank tank = tanks[i]; if(tank!=null && this.multiblock.canDrainTankFrom(i, side)) { drain = tank.drain(maxDrain, doDrain); if(drain!=null) break; } } if(drain!=null) this.multiblock.updateMasterBlock(null, true); return drain; } } @Override public void invalidate() { super.invalidate(); } public static boolean _Immovable() { return true; } public T master() { if(offset[0]==0&&offset[1]==0&&offset[2]==0) return (T)this; TileEntity te = worldObj.getTileEntity(getPos().add(-offset[0],-offset[1],-offset[2])); return this.getClass().isInstance(te)?(T)te: null; } public void updateMasterBlock(IBlockState state, boolean blockUpdate) { T master = master(); if(master!=null) { master.markDirty(); if(blockUpdate) master.markContainingBlockForUpdate(state); } } public boolean isDummy() { return offset[0]!=0 || offset[1]!=0 || offset[2]!=0; } public abstract ItemStack getOriginalBlock(); public abstract void disassemble(); }