diff --git a/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java b/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java index afd7f87f0..a36a60f18 100644 --- a/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java +++ b/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java @@ -18,9 +18,8 @@ package appeng.parts.automation; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Callable; + +import com.google.common.collect.Lists; import net.minecraft.block.Block; import net.minecraft.block.material.Material; @@ -29,7 +28,6 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.WorldServer; @@ -59,23 +57,27 @@ import appeng.api.storage.data.IAEItemStack; import appeng.client.texture.CableBusTextures; import appeng.core.settings.TickRates; import appeng.core.sync.packets.PacketTransitionEffect; -import appeng.hooks.TickHandler; import appeng.me.GridAccessException; import appeng.parts.PartBasicState; import appeng.server.ServerHelper; import appeng.util.Platform; import appeng.util.item.AEItemStack; -public class PartAnnihilationPlane extends PartBasicState implements IGridTickable, Callable + +public class PartAnnihilationPlane extends PartBasicState implements IGridTickable { - public PartAnnihilationPlane(ItemStack is) { + private boolean isAccepting = true; + private final BaseActionSource mySrc = new MachineSource( this ); + + public PartAnnihilationPlane( ItemStack is ) + { super( PartAnnihilationPlane.class, is ); } @Override - @SideOnly(Side.CLIENT) - public void renderInventory(IPartRenderHelper rh, RenderBlocks renderer) + @SideOnly( Side.CLIENT ) + public void renderInventory( IPartRenderHelper rh, RenderBlocks renderer ) { rh.setTexture( CableBusTextures.PartPlaneSides.getIcon(), CableBusTextures.PartPlaneSides.getIcon(), CableBusTextures.PartTransitionPlaneBack.getIcon(), this.is.getIconIndex(), CableBusTextures.PartPlaneSides.getIcon(), @@ -89,32 +91,40 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab } @Override - @SideOnly(Side.CLIENT) - public void renderStatic(int x, int y, int z, IPartRenderHelper rh, RenderBlocks renderer) + @SideOnly( Side.CLIENT ) + public void renderStatic( int x, int y, int z, IPartRenderHelper rh, RenderBlocks renderer ) { int minX = 1; int minY = 1; int maxX = 15; int maxY = 15; - ForgeDirection e = rh.getWorldX(); - ForgeDirection u = rh.getWorldY(); + final ForgeDirection e = rh.getWorldX(); + final ForgeDirection u = rh.getWorldY(); - TileEntity te = this.getHost().getTile(); + final TileEntity te = this.getHost().getTile(); - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x - e.offsetX, y - e.offsetY, z - e.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x - e.offsetX, y - e.offsetY, z - e.offsetZ ), this.side ) ) + { minX = 0; + } - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x + e.offsetX, y + e.offsetY, z + e.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x + e.offsetX, y + e.offsetY, z + e.offsetZ ), this.side ) ) + { maxX = 16; + } - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x - u.offsetX, y - u.offsetY, z - u.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x - u.offsetX, y - u.offsetY, z - u.offsetZ ), this.side ) ) + { minY = 0; + } - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x + u.offsetX, y + u.offsetY, z + u.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x + u.offsetX, y + u.offsetY, z + u.offsetZ ), this.side ) ) + { maxY = 16; + } - boolean isActive = (this.clientFlags & (this.POWERED_FLAG | this.CHANNEL_FLAG)) == (this.POWERED_FLAG | this.CHANNEL_FLAG); + final boolean isActive = ( this.clientFlags & ( this.POWERED_FLAG | this.CHANNEL_FLAG ) ) == ( this.POWERED_FLAG | this.CHANNEL_FLAG ); this.renderCache = rh.useSimplifiedRendering( x, y, z, this, this.renderCache ); rh.setTexture( CableBusTextures.PartPlaneSides.getIcon(), CableBusTextures.PartPlaneSides.getIcon(), @@ -134,47 +144,55 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab this.renderLights( x, y, z, rh, renderer ); } - private boolean isTransitionPlane(TileEntity blockTileEntity, ForgeDirection side) + private boolean isAnnihilationPlane( TileEntity blockTileEntity, ForgeDirection side ) { if ( blockTileEntity instanceof IPartHost ) { - IPart p = ((IPartHost) blockTileEntity).getPart( side ); + final IPart p = ( ( IPartHost ) blockTileEntity ).getPart( side ); return p instanceof PartAnnihilationPlane; } return false; } @Override - public void getBoxes(IPartCollisionHelper bch) + public void getBoxes( IPartCollisionHelper bch ) { int minX = 1; int minY = 1; int maxX = 15; int maxY = 15; - IPartHost host = this.getHost(); + final IPartHost host = this.getHost(); if ( host != null ) { - TileEntity te = host.getTile(); + final TileEntity te = host.getTile(); - int x = te.xCoord; - int y = te.yCoord; - int z = te.zCoord; + final int x = te.xCoord; + final int y = te.yCoord; + final int z = te.zCoord; - ForgeDirection e = bch.getWorldX(); - ForgeDirection u = bch.getWorldY(); + final ForgeDirection e = bch.getWorldX(); + final ForgeDirection u = bch.getWorldY(); - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x - e.offsetX, y - e.offsetY, z - e.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x - e.offsetX, y - e.offsetY, z - e.offsetZ ), this.side ) ) + { minX = 0; + } - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x + e.offsetX, y + e.offsetY, z + e.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x + e.offsetX, y + e.offsetY, z + e.offsetZ ), this.side ) ) + { maxX = 16; + } - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x - u.offsetX, y - u.offsetY, z - u.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x - u.offsetX, y - u.offsetY, z - u.offsetZ ), this.side ) ) + { minY = 0; + } - if ( this.isTransitionPlane( te.getWorldObj().getTileEntity( x + u.offsetX, y + u.offsetY, z + u.offsetZ ), this.side ) ) + if ( this.isAnnihilationPlane( te.getWorldObj().getTileEntity( x + u.offsetX, y + u.offsetY, z + u.offsetZ ), this.side ) ) + { maxY = 16; + } } bch.addBox( 5, 5, 14, 11, 11, 15 ); @@ -187,56 +205,21 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab return 1; } - boolean breaking = false; - final LinkedList Buffer = new LinkedList(); - final BaseActionSource mySrc = new MachineSource( this ); - - @Override - public void writeToNBT(NBTTagCompound data) - { - super.writeToNBT( data ); - - data.setInteger( "bufferSize", this.Buffer.size() ); - for (int x = 0; x < this.Buffer.size(); x++) - { - NBTTagCompound pack = new NBTTagCompound(); - this.Buffer.get( x ).writeToNBT( pack ); - data.setTag( "buffer" + x, pack ); - } - } - - @Override - public void readFromNBT(NBTTagCompound data) - { - super.readFromNBT( data ); - - int size = data.getInteger( "bufferSize" ); - this.Buffer.clear(); - for (int x = 0; x < size; x++) - { - NBTTagCompound pack = (NBTTagCompound) data.getTag( "buffer" + x ); - IAEItemStack ais = AEItemStack.loadItemStackFromNBT( pack ); - if ( ais != null ) - this.Buffer.add( ais ); - } - } - + /** + * If the plane is accepting items. + * + * This might be improved if a performance problem shows up. + * + * @return true if planes accepts items. + */ private boolean isAccepting() { - return this.Buffer.isEmpty(); - } - - @Override - public void getDrops(List drops, boolean wrenched) - { - for (IAEItemStack is : this.Buffer) - if ( is != null ) - drops.add( is.getItemStack() ); + return this.isAccepting; } @Override @MENetworkEventSubscribe - public void chanRender(MENetworkChannelsChanged c) + public void chanRender( MENetworkChannelsChanged c ) { this.onNeighborChanged(); this.getHost().markForUpdate(); @@ -244,107 +227,91 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab @Override @MENetworkEventSubscribe - public void powerRender(MENetworkPowerStatusChange c) + public void powerRender( MENetworkPowerStatusChange c ) { this.onNeighborChanged(); this.getHost().markForUpdate(); } - public TickRateModulation EatBlock(boolean eatForReal) + public TickRateModulation breakblock() { if ( this.isAccepting() && this.proxy.isActive() ) { try { - TileEntity te = this.getTile(); - WorldServer w = (WorldServer) te.getWorldObj(); + final TileEntity te = this.getTile(); + final WorldServer w = ( WorldServer ) te.getWorldObj(); - int x = te.xCoord + this.side.offsetX; - int y = te.yCoord + this.side.offsetY; - int z = te.zCoord + this.side.offsetZ; + final int x = te.xCoord + this.side.offsetX; + final int y = te.yCoord + this.side.offsetY; + final int z = te.zCoord + this.side.offsetZ; - Block blk = w.getBlock( x, y, z ); + final Block blk = w.getBlock( x, y, z ); - IStorageGrid storage = this.proxy.getStorage(); - IEnergyGrid energy = this.proxy.getEnergy(); + final IEnergyGrid energy = this.proxy.getEnergy(); - Material mat = blk.getMaterial(); - boolean ignore = mat == Material.air || mat == Material.lava || mat == Material.water || mat.isLiquid() || blk == Blocks.bedrock + final Material mat = blk.getMaterial(); + final boolean ignore = mat == Material.air || mat == Material.lava || mat == Material.water || mat.isLiquid() || blk == Blocks.bedrock || blk == Blocks.end_portal || blk == Blocks.end_portal_frame || blk == Blocks.command_block; - if ( !ignore ) + if ( !ignore && !w.isAirBlock( x, y, z ) && w.blockExists( x, y, z ) && w.canMineBlock( Platform.getPlayer( w ), x, y, z ) ) { - if ( !w.isAirBlock( x, y, z ) && w.blockExists( x, y, z ) && w.canMineBlock( Platform.getPlayer( w ), x, y, z ) ) + final float hardness = blk.getBlockHardness( w, x, y, z ); + + if ( hardness >= 0.0 ) { - float hardness = blk.getBlockHardness( w, x, y, z ); - if ( hardness >= 0.0 ) + final ItemStack[] out = Platform.getBlockDrops( w, x, y, z ); + + float total = 1 + hardness; + for ( final ItemStack is : out ) { - ItemStack[] out = Platform.getBlockDrops( w, x, y, z ); - float total = 1 + hardness; - for (ItemStack is : out) - total += is.stackSize; + total += is.stackSize; + } - boolean hasPower = energy.extractAEPower( total, Actionable.SIMULATE, PowerMultiplier.CONFIG ) > total - 0.1; - if ( hasPower ) + final boolean hasPower = energy.extractAEPower( total, Actionable.SIMULATE, PowerMultiplier.CONFIG ) > total - 0.1; + final boolean canStore = this.canStoreItemStacks( out ); + + if ( hasPower && canStore ) + { + w.setBlock( x, y, z, Platform.AIR, 0, 3 ); + energy.extractAEPower( total, Actionable.MODULATE, PowerMultiplier.CONFIG ); + + final AxisAlignedBB box = AxisAlignedBB.getBoundingBox( x - 0.2, y - 0.2, z - 0.2, x + 1.2, y + 1.2, z + 1.2 ); + for ( final Object ei : w.getEntitiesWithinAABB( EntityItem.class, box ) ) { - if ( eatForReal ) + if ( ei instanceof EntityItem ) { - energy.extractAEPower( total, Actionable.MODULATE, PowerMultiplier.CONFIG ); - w.setBlock( x, y, z, Platform.AIR, 0, 3 ); - - AxisAlignedBB box = AxisAlignedBB.getBoundingBox( x - 0.2, y - 0.2, z - 0.2, x + 1.2, y + 1.2, z + 1.2 ); - for (Object ei : w.getEntitiesWithinAABB( EntityItem.class, box )) - { - if ( ei instanceof EntityItem ) - { - EntityItem item = (EntityItem) ei; - if ( !item.isDead ) - { - IAEItemStack storedItem = AEItemStack.create( item.getEntityItem() ); - storedItem = Platform.poweredInsert( energy, storage.getItemInventory(), storedItem, this.mySrc ); - if ( storedItem != null ) - this.Buffer.add( storedItem ); - - item.setDead(); - } - } - } - - ServerHelper.proxy.sendToAllNearExcept( null, x, y, z, 64, w, new PacketTransitionEffect( x, y, z, this.side, true ) ); - - for (ItemStack snaggedItem : out) - { - IAEItemStack storedItem = AEItemStack.create( snaggedItem ); - storedItem = Platform.poweredInsert( energy, storage.getItemInventory(), storedItem, this.mySrc ); - if ( storedItem != null ) - this.Buffer.add( storedItem ); - } - - return TickRateModulation.URGENT; - } - else - { - this.breaking = true; - TickHandler.INSTANCE.addCallable( this.tile.getWorldObj(), this ); - return TickRateModulation.URGENT; + final EntityItem entityItem = ( EntityItem ) ei; + this.storeEntityItem( entityItem ); } } + + for ( final ItemStack snaggedItem : out ) + { + if ( this.storeItemStack( snaggedItem ) ) + { + ServerHelper.proxy.sendToAllNearExcept( null, x, y, z, 64, w, new PacketTransitionEffect( x, y, z, this.side, true ) ); + } + } + + return TickRateModulation.URGENT; + } } } } - catch (GridAccessException e1) + catch ( final GridAccessException e1 ) { // :P } } // nothing to do here :) - return TickRateModulation.SLEEP; + return TickRateModulation.IDLE; } @Override - public TickingRequest getTickingRequest(IGridNode node) + public TickingRequest getTickingRequest( IGridNode node ) { return new TickingRequest( TickRates.AnnihilationPlane.min, TickRates.AnnihilationPlane.max, false, true ); } @@ -352,113 +319,179 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab @Override public void onNeighborChanged() { + this.isAccepting = true; try { this.proxy.getTick().alertDevice( this.proxy.getNode() ); } - catch (GridAccessException e) + catch ( final GridAccessException e ) { // :P } } @Override - public void onEntityCollision(Entity entity) + public void onEntityCollision( Entity entity ) { - if ( entity instanceof EntityItem && !entity.isDead && this.isAccepting() ) + if ( this.isAccepting() && entity instanceof EntityItem && !entity.isDead && Platform.isServer() && this.proxy.isActive() ) { boolean capture = false; - switch (this.side) + switch ( this.side ) { - case DOWN: - case UP: - if ( entity.posX > this.tile.xCoord && entity.posX < this.tile.xCoord + 1 ) + case DOWN: + case UP: + if ( entity.posX > this.tile.xCoord && entity.posX < this.tile.xCoord + 1 ) + { + if ( entity.posZ > this.tile.zCoord && entity.posZ < this.tile.zCoord + 1 ) + { + if ( ( entity.posY > this.tile.yCoord + 0.9 && this.side == ForgeDirection.UP ) || ( entity.posY < this.tile.yCoord + 0.1 && this.side == ForgeDirection.DOWN ) ) + { + capture = true; + } + } + } + break; + case SOUTH: + case NORTH: + if ( entity.posX > this.tile.xCoord && entity.posX < this.tile.xCoord + 1 ) + { + if ( entity.posY > this.tile.yCoord && entity.posY < this.tile.yCoord + 1 ) + { + if ( ( entity.posZ > this.tile.zCoord + 0.9 && this.side == ForgeDirection.SOUTH ) + || ( entity.posZ < this.tile.zCoord + 0.1 && this.side == ForgeDirection.NORTH ) ) + { + capture = true; + } + } + } + break; + case EAST: + case WEST: if ( entity.posZ > this.tile.zCoord && entity.posZ < this.tile.zCoord + 1 ) - if ( (entity.posY > this.tile.yCoord + 0.9 && this.side == ForgeDirection.UP) || (entity.posY < this.tile.yCoord + 0.1 && this.side == ForgeDirection.DOWN) ) - capture = true; - break; - case SOUTH: - case NORTH: - if ( entity.posX > this.tile.xCoord && entity.posX < this.tile.xCoord + 1 ) - if ( entity.posY > this.tile.yCoord && entity.posY < this.tile.yCoord + 1 ) - if ( (entity.posZ > this.tile.zCoord + 0.9 && this.side == ForgeDirection.SOUTH) - || (entity.posZ < this.tile.zCoord + 0.1 && this.side == ForgeDirection.NORTH) ) - capture = true; - break; - case EAST: - case WEST: - if ( entity.posZ > this.tile.zCoord && entity.posZ < this.tile.zCoord + 1 ) - if ( entity.posY > this.tile.yCoord && entity.posY < this.tile.yCoord + 1 ) - if ( (entity.posX > this.tile.xCoord + 0.9 && this.side == ForgeDirection.EAST) - || (entity.posX < this.tile.xCoord + 0.1 && this.side == ForgeDirection.WEST) ) - capture = true; - break; - default: - // umm? - break; + { + if ( entity.posY > this.tile.yCoord && entity.posY < this.tile.yCoord + 1 ) + { + if ( ( entity.posX > this.tile.xCoord + 0.9 && this.side == ForgeDirection.EAST ) + || ( entity.posX < this.tile.xCoord + 0.1 && this.side == ForgeDirection.WEST ) ) + { + capture = true; + } + } + } + break; + default: + // umm? + break; } - if ( capture && Platform.isServer() && this.proxy.isActive() ) + if ( capture ) { - IAEItemStack stack = AEItemStack.create( ((EntityItem) entity).getEntityItem() ); - if ( stack != null ) - { - ServerHelper.proxy.sendToAllNearExcept( null, this.tile.xCoord, this.tile.yCoord, this.tile.zCoord, 64, this.tile.getWorldObj(), - new PacketTransitionEffect( entity.posX, entity.posY, entity.posZ, this.side, false ) ); - - this.Buffer.add( stack ); - this.storeBuffer(); - entity.setDead(); - } + ServerHelper.proxy.sendToAllNearExcept( null, this.tile.xCoord, this.tile.yCoord, this.tile.zCoord, 64, this.tile.getWorldObj(), + new PacketTransitionEffect( entity.posX, entity.posY, entity.posZ, this.side, false ) ); + this.storeEntityItem( ( EntityItem ) entity ); } } } @Override - public TickRateModulation tickingRequest(IGridNode node, int TicksSinceLastCall) + public TickRateModulation tickingRequest( IGridNode node, int TicksSinceLastCall ) { - if ( this.breaking ) - return TickRateModulation.URGENT; - - if ( this.isAccepting() ) - return this.EatBlock( false ); - else - { - this.storeBuffer(); - return TickRateModulation.IDLE; - } + this.isAccepting = true; + return this.breakblock(); } - private void storeBuffer() + /** + * Checks if the network can store the possible drops. + * + * It also sets isAccepting to false, if the item can not be stored. + * + * @param itemStacks an array of {@link ItemStack} to test + * @return true, if the network can store at least a single item of all drops or no drops are reported + */ + private boolean canStoreItemStacks( ItemStack[] itemStacks ) { + boolean canStore = itemStacks.length == 0; + try { - IStorageGrid storage = this.proxy.getStorage(); - IEnergyGrid energy = this.proxy.getEnergy(); + final IStorageGrid storage = this.proxy.getStorage(); - while (!this.Buffer.isEmpty()) + for ( final ItemStack itemStack : itemStacks ) { - IAEItemStack storedItem = this.Buffer.pop(); - storedItem = Platform.poweredInsert( energy, storage.getItemInventory(), storedItem, this.mySrc ); - if ( storedItem != null ) + final IAEItemStack itemToTest = AEItemStack.create( itemStack ); + final IAEItemStack overflow = storage.getItemInventory().injectItems( itemToTest, Actionable.SIMULATE, this.mySrc ); + if ( overflow == null || itemToTest.getStackSize() > overflow.getStackSize() ) { - this.Buffer.add( storedItem ); - break; + canStore = true; } } } - catch (GridAccessException e1) + catch ( final GridAccessException e ) { // :P } + + this.isAccepting = canStore; + return canStore; } - @Override - public Object call() throws Exception + /** + * Stores an {@link ItemStack} inside the network. + * + * @param item {@link ItemStack} to store + * @return null or leftover {@link IAEItemStack} + */ + private boolean storeItemStack( ItemStack item ) { - this.breaking = false; - return this.EatBlock( true ); + final IAEItemStack itemToStore = AEItemStack.create( item ); + try + { + final IStorageGrid storage = this.proxy.getStorage(); + final IEnergyGrid energy = this.proxy.getEnergy(); + final IAEItemStack overflow = Platform.poweredInsert( energy, storage.getItemInventory(), itemToStore, this.mySrc ); + + this.spawnOverflowItemStack( overflow ); + + this.isAccepting = overflow == null; + return overflow == null || item.stackSize < overflow.getStackSize(); + } + catch ( final GridAccessException e1 ) + { + // :P + } + return false; + } + + /** + * Stores an {@link EntityItem} inside the network and either marks it as dead or sets it to the leftover stackSize. + * + * @param entityItem {@link EntityItem} to store + */ + private void storeEntityItem( EntityItem entityItem ) + { + if ( !entityItem.isDead ) + { + this.storeItemStack( entityItem.getEntityItem() ); + entityItem.setDead(); + } + } + + private void spawnOverflowItemStack( IAEItemStack overflow ) + { + if ( overflow == null ) + { + return; + } + + final TileEntity tileEntity = this.getTile(); + final WorldServer world = ( WorldServer ) tileEntity.getWorldObj(); + + final int x = tileEntity.xCoord + this.side.offsetX; + final int y = tileEntity.yCoord + this.side.offsetY; + final int z = tileEntity.zCoord + this.side.offsetZ; + + Platform.spawnDrops( world, x, y, z, Lists.newArrayList( overflow.getItemStack() ) ); } }