package appeng.fluids.parts; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.block.state.IBlockState; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fluids.FluidUtil; import net.minecraftforge.fluids.IFluidBlock; import net.minecraftforge.fluids.capability.IFluidHandler; import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.config.PowerMultiplier; import appeng.api.networking.IGridNode; import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.events.MENetworkChannelsChanged; import appeng.api.networking.events.MENetworkEventSubscribe; import appeng.api.networking.events.MENetworkPowerStatusChange; import appeng.api.networking.security.IActionSource; import appeng.api.networking.storage.IStorageGrid; import appeng.api.networking.ticking.IGridTickable; import appeng.api.networking.ticking.TickRateModulation; import appeng.api.networking.ticking.TickingRequest; import appeng.api.parts.IPart; import appeng.api.parts.IPartCollisionHelper; import appeng.api.parts.IPartHost; import appeng.api.parts.IPartModel; import appeng.api.storage.IMEInventory; import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.data.IAEFluidStack; import appeng.api.util.AECableType; import appeng.api.util.AEPartLocation; import appeng.core.AppEng; import appeng.core.settings.TickRates; import appeng.core.sync.packets.PacketTransitionEffect; import appeng.fluids.util.AEFluidStack; import appeng.items.parts.PartModels; import appeng.me.GridAccessException; import appeng.me.helpers.MachineSource; import appeng.parts.PartBasicState; import appeng.parts.automation.PlaneConnections; import appeng.parts.automation.PlaneModels; import appeng.util.Platform; public class PartFluidAnnihilationPlane extends PartBasicState implements IGridTickable { private static final PlaneModels MODELS = new PlaneModels( "part/fluid_annihilation_plane_", "part/fluid_annihilation_plane_on_" ); @PartModels public static List getModels() { return MODELS.getModels(); } private final IActionSource mySrc = new MachineSource( this ); public PartFluidAnnihilationPlane( final ItemStack is ) { super( is ); } @Override public void getBoxes( final IPartCollisionHelper bch ) { int minX = 1; int minY = 1; int maxX = 15; int maxY = 15; final IPartHost host = this.getHost(); if( host != null ) { final TileEntity te = host.getTile(); final BlockPos pos = te.getPos(); final EnumFacing e = bch.getWorldX(); final EnumFacing u = bch.getWorldY(); if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( e.getOpposite() ) ), this.getSide() ) ) { minX = 0; } if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( e ) ), this.getSide() ) ) { maxX = 16; } if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( u.getOpposite() ) ), this.getSide() ) ) { minY = 0; } if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( e ) ), this.getSide() ) ) { maxY = 16; } } bch.addBox( 5, 5, 14, 11, 11, 15 ); bch.addBox( minX, minY, 15, maxX, maxY, 16 ); } public PlaneConnections getConnections() { final EnumFacing facingRight, facingUp; AEPartLocation location = this.getSide(); switch( location ) { case UP: facingRight = EnumFacing.EAST; facingUp = EnumFacing.NORTH; break; case DOWN: facingRight = EnumFacing.WEST; facingUp = EnumFacing.NORTH; break; case NORTH: facingRight = EnumFacing.WEST; facingUp = EnumFacing.UP; break; case SOUTH: facingRight = EnumFacing.EAST; facingUp = EnumFacing.UP; break; case WEST: facingRight = EnumFacing.SOUTH; facingUp = EnumFacing.UP; break; case EAST: facingRight = EnumFacing.NORTH; facingUp = EnumFacing.UP; break; default: case INTERNAL: return PlaneConnections.of( false, false, false, false ); } boolean left = false, right = false, down = false, up = false; final IPartHost host = this.getHost(); if( host != null ) { final TileEntity te = host.getTile(); final BlockPos pos = te.getPos(); if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( facingRight.getOpposite() ) ), this.getSide() ) ) { left = true; } if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( facingRight ) ), this.getSide() ) ) { right = true; } if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( facingUp.getOpposite() ) ), this.getSide() ) ) { down = true; } if( this.isAnnihilationPlane( te.getWorld().getTileEntity( pos.offset( facingUp ) ), this.getSide() ) ) { up = true; } } return PlaneConnections.of( up, right, down, left ); } @Override public void onNeighborChanged( IBlockAccess w, BlockPos pos, BlockPos neighbor ) { if( pos.offset( this.getSide().getFacing() ).equals( neighbor ) ) { this.refresh(); } } @Override public float getCableConnectionLength( AECableType cable ) { return 1; } private boolean isAnnihilationPlane( final TileEntity blockTileEntity, final AEPartLocation side ) { if( blockTileEntity instanceof IPartHost ) { final IPart p = ( (IPartHost) blockTileEntity ).getPart( side ); return p != null && p.getClass() == this.getClass(); } return false; } private void refresh() { try { this.getProxy().getTick().alertDevice( this.getProxy().getNode() ); } catch( final GridAccessException e ) { // :P } } @Override @MENetworkEventSubscribe public void chanRender( final MENetworkChannelsChanged c ) { this.refresh(); this.getHost().markForUpdate(); } @Override @MENetworkEventSubscribe public void powerRender( final MENetworkPowerStatusChange c ) { this.refresh(); this.getHost().markForUpdate(); } private TickRateModulation pickupFluid() { if( !this.getProxy().isActive() ) { return TickRateModulation.SLEEP; } final TileEntity te = this.getTile(); final World w = te.getWorld(); final BlockPos pos = te.getPos().offset( this.getSide().getFacing() ); final IBlockState state = w.getBlockState( pos ); final Block block = state.getBlock(); if( block instanceof IFluidBlock || block instanceof BlockLiquid ) { final IFluidHandler fh = FluidUtil.getFluidHandler( w, pos, null ); final IAEFluidStack blockFluid = AEFluidStack.fromFluidStack( fh.drain( Integer.MAX_VALUE, false ) ); if( blockFluid != null ) { if( this.storeFluid( blockFluid, false ) ) { this.storeFluid( AEFluidStack.fromFluidStack( fh.drain( Integer.MAX_VALUE, true ) ), true ); AppEng.proxy.sendToAllNearExcept( null, pos.getX(), pos.getY(), pos.getZ(), 64, w, new PacketTransitionEffect( pos.getX(), pos.getY(), pos.getZ(), this.getSide(), true ) ); return TickRateModulation.URGENT; } return TickRateModulation.IDLE; } } // nothing to do here :) return TickRateModulation.SLEEP; } @Override public TickingRequest getTickingRequest( final IGridNode node ) { return new TickingRequest( TickRates.AnnihilationPlane.getMin(), TickRates.AnnihilationPlane.getMax(), false, true ); } @Override public TickRateModulation tickingRequest( final IGridNode node, final int ticksSinceLastCall ) { return this.pickupFluid(); } private boolean storeFluid( IAEFluidStack stack, boolean modulate ) { try { final IStorageGrid storage = this.getProxy().getStorage(); final IMEInventory inv = storage.getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ); if( modulate ) { final IEnergyGrid energy = this.getProxy().getEnergy(); return Platform.poweredInsert( energy, inv, stack, this.mySrc ) == null; } else { final float requiredPower = stack.getStackSize() / Math.min( 1.0f, stack.getChannel().transferFactor() ); final IEnergyGrid energy = this.getProxy().getEnergy(); if( energy.extractAEPower( requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG ) < requiredPower ) { return false; } final IAEFluidStack leftOver = inv.injectItems( stack, Actionable.SIMULATE, this.mySrc ); return leftOver == null || leftOver.getStackSize() == 0; } } catch( final GridAccessException e ) { // :P } return false; } @Override public IPartModel getStaticModels() { return MODELS.getModel( this.getConnections(), this.isPowered(), this.isActive() ); } }