diff --git a/src/main/java/appeng/block/crafting/BlockMolecularAssembler.java b/src/main/java/appeng/block/crafting/BlockMolecularAssembler.java index 7412e83a0..60f3dbdb8 100644 --- a/src/main/java/appeng/block/crafting/BlockMolecularAssembler.java +++ b/src/main/java/appeng/block/crafting/BlockMolecularAssembler.java @@ -56,7 +56,7 @@ public class BlockMolecularAssembler extends AEBaseTileBlock @Override protected IProperty[] getAEStates() { - return new IProperty[] { POWERED }; + return new IProperty[]{POWERED}; } @Override @@ -108,4 +108,14 @@ public class BlockMolecularAssembler extends AEBaseTileBlock return super.onBlockActivated( w, pos, state, p, hand, side, hitX, hitY, hitZ ); } + + @Override + public void onNeighborChange( IBlockAccess world, BlockPos pos, BlockPos neighbor ) + { + final TileMolecularAssembler tg = this.getTileEntity( world, pos ); + if( tg != null ) + { + tg.updateNeighbors( world, pos, neighbor ); + } + } } diff --git a/src/main/java/appeng/helpers/DualityInterface.java b/src/main/java/appeng/helpers/DualityInterface.java index 0c30b43af..8413cae3c 100644 --- a/src/main/java/appeng/helpers/DualityInterface.java +++ b/src/main/java/appeng/helpers/DualityInterface.java @@ -414,6 +414,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn // :P } } + this.notifyNeighbors(); } private void updateCraftingList() diff --git a/src/main/java/appeng/parts/automation/PartExportBus.java b/src/main/java/appeng/parts/automation/PartExportBus.java index 000f72353..4d87fb3ac 100644 --- a/src/main/java/appeng/parts/automation/PartExportBus.java +++ b/src/main/java/appeng/parts/automation/PartExportBus.java @@ -297,17 +297,27 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest ItemStack remaining; - remaining = mode == Actionable.SIMULATE ? d.simulateAdd( inputStack ) : d.addItems( inputStack ); - - if( !remaining.isEmpty() ) + if( mode == Actionable.SIMULATE ) { - items.setCachedItemStack( remaining ); + remaining = d.simulateAdd( inputStack ); } else { - items.setCachedItemStack( inputStack ); + remaining = d.addItems( inputStack ); } + // Store the stack in the cache for next time. + if( mode == Actionable.SIMULATE ) + { + items.setCachedItemStack( inputStack ); + } + else + { + if( !remaining.isEmpty() ) + { + items.setCachedItemStack( remaining ); + } + } if( remaining == inputStack ) { return items; @@ -357,10 +367,10 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest if( !remaining.isEmpty() ) { ais.setCachedItemStack( remaining ); - } - else - { - ais.setCachedItemStack( inputStack ); + if( remaining == inputStack ) + { + return; + } } final long canFit = remaining.isEmpty() ? this.itemToSend : this.itemToSend - remaining.getCount(); diff --git a/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java b/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java index cf69c541b..d45e98b04 100644 --- a/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java +++ b/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java @@ -91,13 +91,16 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor, IBaseMonitor, IBaseMonitor, IBaseMonitor, IBaseMonitor, ITickingMonitor { - private final Object2ObjectMap, Object> listeners = new Object2ObjectOpenHashMap<>(); - private IActionSource mySource; - private final IItemRepository itemRepository; - private final IGridProxyable proxyable; - private final InventoryCache cache; - private AccessRestriction access; + private final Object2ObjectMap, Object> listeners = new Object2ObjectOpenHashMap<>(); + private IActionSource mySource; + private final IItemRepository itemRepository; + private final IGridProxyable proxyable; + private final InventoryCache cache; + private AccessRestriction access; - ItemRepositoryAdapter( IItemRepository itemRepository, IGridProxyable proxy ) - { - this.itemRepository = itemRepository; - this.proxyable = proxy; - this.cache = new InventoryCache( this.itemRepository ); - if( this.proxyable instanceof PartStorageBus ) - { - PartStorageBus partStorageBus = (PartStorageBus) this.proxyable; - this.access = ( (AccessRestriction) partStorageBus.getConfigManager().getSetting( Settings.ACCESS ) ); - } - this.cache.update(); - } + ItemRepositoryAdapter( IItemRepository itemRepository, IGridProxyable proxy ) + { + this.itemRepository = itemRepository; + this.proxyable = proxy; + this.cache = new InventoryCache( this.itemRepository ); + if( this.proxyable instanceof PartStorageBus ) + { + PartStorageBus partStorageBus = (PartStorageBus) this.proxyable; + this.access = ( (AccessRestriction) partStorageBus.getConfigManager().getSetting( Settings.ACCESS ) ); + } + this.cache.update(); + } - @Override - public IAEItemStack injectItems( IAEItemStack iox, Actionable type, IActionSource src ) - { - // Try to reuse the cached stack - ItemStack inputStack = iox.getCachedItemStack( iox.getStackSize() ); + @Override + public IAEItemStack injectItems( IAEItemStack iox, Actionable type, IActionSource src ) + { + // Try to reuse the cached stack + ItemStack inputStack = iox.getCachedItemStack( iox.getStackSize() ); - ItemStack remaining; + ItemStack remaining; - remaining = this.itemRepository.insertItem( inputStack, type == Actionable.SIMULATE ); + remaining = this.itemRepository.insertItem( inputStack, type == Actionable.SIMULATE ); - // Store the stack in the cache for next time. - if( !remaining.isEmpty() ) - { - iox.setCachedItemStack( remaining ); - } - else - { - iox.setCachedItemStack( inputStack ); - } + // Store the stack in the cache for next time. + if( type == Actionable.SIMULATE ) + { + iox.setCachedItemStack( inputStack ); + } + else + { + if( !remaining.isEmpty() ) + { + iox.setCachedItemStack( remaining ); + } + } - // At this point, we still have some items left... - if( remaining == inputStack ) - { - // The stack remained unmodified, target inventory is full - return iox; - } + // At this point, we still have some items left... + if( remaining == inputStack ) + { + // The stack remained unmodified, target inventory is full + return iox; + } - if( type == Actionable.MODULATE ) - { - IAEItemStack added = iox.copy().setStackSize( iox.getStackSize() - remaining.getCount() ); - this.cache.currentlyCached.add( added ); - this.postDifference( Collections.singletonList( added ) ); - try - { - this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); - } - catch( GridAccessException ex ) - { - // meh - } - } + if( type == Actionable.MODULATE ) + { + IAEItemStack added = iox.copy().setStackSize( iox.getStackSize() - remaining.getCount() ); + this.cache.currentlyCached.add( added ); + this.postDifference( Collections.singletonList( added ) ); + try + { + this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); + } + catch( GridAccessException ex ) + { + // meh + } + } - return AEItemStack.fromItemStack( remaining ); + return AEItemStack.fromItemStack( remaining ); - } + } - @Override - public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src ) - { - int remainingSize = Ints.saturatedCast( request.getStackSize() ); + @Override + public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src ) + { + int remainingSize = Ints.saturatedCast( request.getStackSize() ); - final boolean simulate = ( mode == Actionable.SIMULATE ); + final boolean simulate = ( mode == Actionable.SIMULATE ); - ItemStack extracted = this.itemRepository.extractItem( request.getDefinition(), remainingSize, simulate ); + ItemStack extracted = this.itemRepository.extractItem( request.getDefinition(), remainingSize, simulate ); - if( extracted.getCount() > remainingSize ) - { - // Something broke. It should never return more than we requested... - // We're going to silently eat the remainder - AELog.warn( "Mod that provided item handler %s is broken. Returned %s items while only requesting %d.", - this.itemRepository.getClass().getName(), extracted.toString(), remainingSize ); - extracted.setCount( remainingSize ); - } + if( extracted.getCount() > remainingSize ) + { + // Something broke. It should never return more than we requested... + // We're going to silently eat the remainder + AELog.warn( "Mod that provided item handler %s is broken. Returned %s items while only requesting %d.", this.itemRepository.getClass().getName(), extracted.toString(), remainingSize ); + extracted.setCount( remainingSize ); + } - if( !extracted.isEmpty() ) - { - IAEItemStack extractedAEItemStack = AEItemStack.fromItemStack( extracted ); - if( mode == Actionable.MODULATE ) - { - IAEItemStack cachedStack = this.cache.currentlyCached.findPrecise( request ); - if (cachedStack != null) - { - cachedStack.decStackSize( extractedAEItemStack.getStackSize() ); - this.postDifference( Collections.singletonList( extractedAEItemStack.copy().setStackSize( -extractedAEItemStack.getStackSize() ) ) ); - } - try - { - this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); - } - catch( GridAccessException ex ) - { - // meh - } - } - return extractedAEItemStack; - } - return null; - } + if( !extracted.isEmpty() ) + { + IAEItemStack extractedAEItemStack = AEItemStack.fromItemStack( extracted ); + if( mode == Actionable.MODULATE ) + { + IAEItemStack cachedStack = this.cache.currentlyCached.findPrecise( request ); + if( cachedStack != null ) + { + cachedStack.decStackSize( extractedAEItemStack.getStackSize() ); + this.postDifference( Collections.singletonList( extractedAEItemStack.copy().setStackSize( -extractedAEItemStack.getStackSize() ) ) ); + } + try + { + this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); + } + catch( GridAccessException ex ) + { + // meh + } + } + return extractedAEItemStack; + } + return null; + } - @Override - public IItemList getAvailableItems( IItemList out ) - { - return this.cache.getAvailableItems( out ); - } + @Override + public IItemList getAvailableItems( IItemList out ) + { + return this.cache.getAvailableItems( out ); + } - @Override - public IStorageChannel getChannel() - { - return AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ); - } + @Override + public IStorageChannel getChannel() + { + return AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ); + } - @Override - public void addListener( IMEMonitorHandlerReceiver l, Object verificationToken ) - { - this.listeners.put( l, verificationToken ); - } + @Override + public void addListener( IMEMonitorHandlerReceiver l, Object verificationToken ) + { + this.listeners.put( l, verificationToken ); + } - @Override - public void removeListener( IMEMonitorHandlerReceiver l ) - { - this.listeners.remove( l ); - } + @Override + public void removeListener( IMEMonitorHandlerReceiver l ) + { + this.listeners.remove( l ); + } - private void postDifference( Iterable a ) - { - final Iterator, Object>> i = this.listeners.entrySet().iterator(); - while ( i.hasNext() ) - { - final Map.Entry, Object> l = i.next(); - final IMEMonitorHandlerReceiver key = l.getKey(); - if( key.isValid( l.getValue() ) ) - { - key.postChange( this, a, this.mySource ); - } - else - { - i.remove(); - } - } - } + private void postDifference( Iterable a ) + { + final Iterator, Object>> i = this.listeners.entrySet().iterator(); + while ( i.hasNext() ) + { + final Map.Entry, Object> l = i.next(); + final IMEMonitorHandlerReceiver key = l.getKey(); + if( key.isValid( l.getValue() ) ) + { + key.postChange( this, a, this.mySource ); + } + else + { + i.remove(); + } + } + } - @Override - public TickRateModulation onTick() - { - List changes = this.cache.update(); - if( !changes.isEmpty() && access.hasPermission( AccessRestriction.READ ) ) - { - this.postDifference( changes ); - return TickRateModulation.URGENT; - } - else - { - return TickRateModulation.SLOWER; - } - } + @Override + public TickRateModulation onTick() + { + List changes = this.cache.update(); + if( !changes.isEmpty() && access.hasPermission( AccessRestriction.READ ) ) + { + this.postDifference( changes ); + return TickRateModulation.URGENT; + } + else + { + return TickRateModulation.SLOWER; + } + } - @Override - public void setActionSource( final IActionSource mySource ) - { - this.mySource = mySource; - } + @Override + public void setActionSource( final IActionSource mySource ) + { + this.mySource = mySource; + } - private static class InventoryCache - { - private IItemList currentlyCached = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); - private final IItemRepository iItemRepository; + private static class InventoryCache + { + private IItemList currentlyCached = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + private final IItemRepository iItemRepository; - public InventoryCache( IItemRepository iItemRepository ) - { - this.iItemRepository = iItemRepository; - } + public InventoryCache( IItemRepository iItemRepository ) + { + this.iItemRepository = iItemRepository; + } - public IItemList getAvailableItems( IItemList out ) - { - currentlyCached.iterator().forEachRemaining( out::add ); - return out; - } + public IItemList getAvailableItems( IItemList out ) + { + currentlyCached.iterator().forEachRemaining( out::add ); + return out; + } - public List update() - { - final List changes = new ArrayList<>(); + public List update() + { + final List changes = new ArrayList<>(); - IItemList currentlyOnStorage = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); - this.iItemRepository.getAllItems().stream().map( s -> AEItemStack.fromItemStack( s.itemPrototype ).setStackSize( s.count ) ).forEach( currentlyOnStorage::add ); + IItemList currentlyOnStorage = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + this.iItemRepository.getAllItems().stream().map( s -> AEItemStack.fromItemStack( s.itemPrototype ).setStackSize( s.count ) ).forEach( currentlyOnStorage::add ); - for ( final IAEItemStack is : currentlyCached ) - { - is.setStackSize( -is.getStackSize() ); - } + for( final IAEItemStack is : currentlyCached ) + { + is.setStackSize( -is.getStackSize() ); + } - for ( final IAEItemStack is : currentlyOnStorage ) - { - currentlyCached.add( is ); - } + for( final IAEItemStack is : currentlyOnStorage ) + { + currentlyCached.add( is ); + } - for ( final IAEItemStack is : currentlyCached ) - { - if( is.getStackSize() != 0 ) - { - changes.add( is ); - } - } + for( final IAEItemStack is : currentlyCached ) + { + if( is.getStackSize() != 0 ) + { + changes.add( is ); + } + } - currentlyCached = currentlyOnStorage; + currentlyCached = currentlyOnStorage; - return changes; - } + return changes; + } - } + } } diff --git a/src/main/java/appeng/tile/crafting/TileMolecularAssembler.java b/src/main/java/appeng/tile/crafting/TileMolecularAssembler.java index 0eea68ffb..441e1d24a 100644 --- a/src/main/java/appeng/tile/crafting/TileMolecularAssembler.java +++ b/src/main/java/appeng/tile/crafting/TileMolecularAssembler.java @@ -20,7 +20,9 @@ package appeng.tile.crafting; import java.io.IOException; +import java.util.EnumMap; import java.util.List; +import java.util.Map; import appeng.api.networking.security.IActionSource; import appeng.api.storage.IMEMonitor; @@ -28,6 +30,7 @@ import appeng.api.storage.IStorageMonitorable; import appeng.api.storage.IStorageMonitorableAccessor; import appeng.api.storage.channels.IItemStorageChannel; import appeng.capabilities.Capabilities; +import appeng.helpers.PatternHelper; import appeng.me.helpers.MachineSource; import io.netty.buffer.ByteBuf; @@ -37,6 +40,7 @@ import net.minecraft.nbt.NBTTagCompound; 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.minecraft.world.WorldServer; import net.minecraftforge.fml.common.FMLCommonHandler; @@ -93,6 +97,7 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade private final AppEngInternalInventory patternInv = new AppEngInternalInventory( this, 1, 1 ); private final IItemHandler gridInvExt = new WrapperFilteredItemHandler( this.gridInv, new CraftingGridFilter() ); private final IItemHandler internalInv = new WrapperChainedItemHandler( this.gridInv, this.patternInv ); + private final EnumMap neighbors = new EnumMap<>( EnumFacing.class ); private final IConfigManager settings; private final UpgradeInventory upgrades; private boolean isPowered = false; @@ -122,6 +127,127 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade return 5; } + public void updateNeighbors() + { + for( EnumFacing f : EnumFacing.VALUES ) + { + TileEntity te = world.getTileEntity( pos.offset( f ) ); + Object capability = null; + if( te != null ) + { + // Prioritize a handler to directly link to another ME network + IStorageMonitorableAccessor accessor = te.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, f.getOpposite() ); + + if( accessor != null ) + { + IStorageMonitorable inventory = accessor.getInventory( this.mySrc ); + if( inventory != null ) + { + capability = inventory; + } + } + + if( capability == null ) + { + capability = InventoryAdaptor.getAdaptor( te, f.getOpposite() ); + } + } + + if( capability != null ) + { + neighbors.put( f, capability ); + } + else + { + neighbors.remove( f ); + } + } + } + + @Override + public void onReady() + { + super.onReady(); + updateNeighbors(); + } + + public void updateNeighbors( IBlockAccess w, BlockPos pos, BlockPos neighbor ) + { + EnumFacing updateFromFacing; + if( pos.getX() != neighbor.getX() ) + { + if( pos.getX() > neighbor.getX() ) + { + updateFromFacing = EnumFacing.WEST; + } + else + { + updateFromFacing = EnumFacing.EAST; + } + } + else if( pos.getY() != neighbor.getY() ) + { + if( pos.getY() > neighbor.getY() ) + { + updateFromFacing = EnumFacing.DOWN; + } + else + { + updateFromFacing = EnumFacing.UP; + } + } + else if( pos.getZ() != neighbor.getZ() ) + { + if( pos.getZ() > neighbor.getZ() ) + { + updateFromFacing = EnumFacing.NORTH; + } + else + { + updateFromFacing = EnumFacing.SOUTH; + } + } + else + { + return; + } + + if( pos.offset( updateFromFacing ).equals( neighbor ) ) + { + + TileEntity te = w.getTileEntity( neighbor ); + Object capability = null; + if( te != null ) + { + // Prioritize a handler to directly link to another ME network + IStorageMonitorableAccessor accessor = te.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, updateFromFacing.getOpposite() ); + + if( accessor != null ) + { + IStorageMonitorable inventory = accessor.getInventory( this.mySrc ); + if( inventory != null ) + { + capability = inventory; + } + } + + if( capability == null ) + { + capability = InventoryAdaptor.getAdaptor( te, updateFromFacing.getOpposite() ); + } + } + + if( capability != null ) + { + neighbors.put( updateFromFacing, capability ); + } + else + { + neighbors.remove( updateFromFacing ); + } + } + } + @Override public boolean pushPattern( final ICraftingPatternDetails patternDetails, final InventoryCrafting table, final EnumFacing where ) { @@ -151,7 +277,7 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade private void updateSleepiness() { final boolean wasEnabled = this.isAwake; - this.isAwake = this.myPlan != null && this.hasMats() || this.canPush(); + this.isAwake = this.canPush() || this.myPlan != null && this.hasMats(); if( wasEnabled != this.isAwake ) { try @@ -187,9 +313,13 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade for( int x = 0; x < this.craftingInv.getSizeInventory(); x++ ) { this.craftingInv.setInventorySlotContents( x, this.gridInv.getStackInSlot( x ) ); + if( !myPlan.isValidItemForSlot( x, craftingInv.getStackInSlot( x ), world ) ) + { + return false; + } } - return !this.myPlan.getOutput( this.craftingInv, this.getWorld() ).isEmpty(); + return this.myPlan.getOutputs().length > 0; } @Override @@ -433,7 +563,7 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade this.reboot = false; int speed = 10; - switch( this.upgrades.getInstalledUpgrades( Upgrades.SPEED ) ) + switch ( this.upgrades.getInstalledUpgrades( Upgrades.SPEED ) ) { case 0: this.progress += this.userPower( ticksSinceLastCall, speed = 10, 1.0 ); @@ -527,10 +657,7 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade { try { - return (int) ( this.getProxy() - .getEnergy() - .extractAEPower( ticksPassed * bonusValue * acceleratorTax, Actionable.MODULATE, - PowerMultiplier.CONFIG ) / acceleratorTax ); + return (int) ( this.getProxy().getEnergy().extractAEPower( ticksPassed * bonusValue * acceleratorTax, Actionable.MODULATE, PowerMultiplier.CONFIG ) / acceleratorTax ); } catch( final GridAccessException e ) { @@ -542,9 +669,13 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade { if( this.pushDirection == AEPartLocation.INTERNAL ) { - for( final EnumFacing d : EnumFacing.VALUES ) + for( final Map.Entry d : neighbors.entrySet() ) { - output = this.pushTo( output, d ); + output = this.pushTo( output, d.getKey() ); + if( output.isEmpty() ) + { + break; + } } } else @@ -568,55 +699,42 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IUpgrade return output; } - final TileEntity te = this.getWorld().getTileEntity( this.pos.offset( d ) ); - - if( te == null ) + Object capability = neighbors.get( d ); + if( capability instanceof IStorageMonitorable ) { - return output; - } - - // Prioritize a handler to directly link to another ME network - IStorageMonitorableAccessor accessor = te.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, d.getOpposite() ); - - if( accessor != null ) - { - IStorageMonitorable inventory = accessor.getInventory( this.mySrc ); - if( inventory != null ) + // Prioritize a handler to directly link to another ME network + IStorageMonitorable inventory = (IStorageMonitorable) capability; + IAEItemStack toInsert = AEItemStack.fromItemStack( output ); + IMEMonitor inv = inventory.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); + IAEItemStack remainder = inv.injectItems( toInsert, Actionable.SIMULATE, this.mySrc ); + if( remainder == null ) { - IAEItemStack toInsert = AEItemStack.fromItemStack( output ); - IMEMonitor inv = inventory.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); - IAEItemStack remainder = inv.injectItems( toInsert, Actionable.SIMULATE, this.mySrc ); - if( remainder == null ) + inv.injectItems( toInsert, Actionable.MODULATE, this.mySrc ); + return ItemStack.EMPTY; + } + else + { + if( remainder.getStackSize() == toInsert.getStackSize() ) { - inv.injectItems( toInsert, Actionable.MODULATE, this.mySrc ); - return ItemStack.EMPTY; - } - else - { - if( remainder.getStackSize() == toInsert.getStackSize() ) - { - return output.copy(); - } - inv.injectItems( toInsert.setStackSize( toInsert.getStackSize() - remainder.getStackSize() ), Actionable.MODULATE, this.mySrc ); - return remainder.createItemStack(); + return output; } + inv.injectItems( toInsert.setStackSize( toInsert.getStackSize() - remainder.getStackSize() ), Actionable.MODULATE, this.mySrc ); + this.saveChanges(); + return remainder.createItemStack(); } } - - final InventoryAdaptor adaptor = InventoryAdaptor.getAdaptor( te, d.getOpposite() ); - - if( adaptor == null ) + else if( capability instanceof InventoryAdaptor ) { - return output; - } + InventoryAdaptor adaptor = (InventoryAdaptor) capability; - final int size = output.getCount(); - output = adaptor.addItems( output.copy() ); - final int newSize = output.isEmpty() ? 0 : output.getCount(); + final int size = output.getCount(); + output = adaptor.addItems( output ); + final int newSize = output.isEmpty() ? 0 : output.getCount(); - if( size != newSize ) - { - this.saveChanges(); + if( size != newSize ) + { + this.saveChanges(); + } } return output; diff --git a/src/main/java/appeng/tile/inventory/AppEngInternalInventory.java b/src/main/java/appeng/tile/inventory/AppEngInternalInventory.java index 45278557f..80bfa6481 100644 --- a/src/main/java/appeng/tile/inventory/AppEngInternalInventory.java +++ b/src/main/java/appeng/tile/inventory/AppEngInternalInventory.java @@ -77,6 +77,10 @@ public class AppEngInternalInventory extends ItemStackHandler implements Iterabl @Override public void setStackInSlot( int slot, @Nonnull ItemStack stack ) { + if( stack == this.getStackInSlot( slot ) ) + { + return; + } this.previousStack = this.getStackInSlot( slot ).copy(); super.setStackInSlot( slot, stack ); } diff --git a/src/main/java/appeng/util/inv/AdaptorItemHandler.java b/src/main/java/appeng/util/inv/AdaptorItemHandler.java index 87d794b81..65b6843ae 100644 --- a/src/main/java/appeng/util/inv/AdaptorItemHandler.java +++ b/src/main/java/appeng/util/inv/AdaptorItemHandler.java @@ -223,26 +223,24 @@ public class AdaptorItemHandler extends InventoryAdaptor return this.addItems( toBeSimulated, true ); } - protected ItemStack addItems( final ItemStack itemsToAdd, final boolean simulate ) + protected ItemStack addItems( ItemStack itemsToAdd, final boolean simulate ) { if( itemsToAdd.isEmpty() ) { return ItemStack.EMPTY; } - ItemStack left = itemsToAdd.copy(); - for( int slot = 0; slot < this.itemHandler.getSlots(); slot++ ) { - left = this.itemHandler.insertItem( slot, left, simulate ); + itemsToAdd = this.itemHandler.insertItem( slot, itemsToAdd, simulate ); - if( left.isEmpty() ) + if( itemsToAdd.isEmpty() ) { return ItemStack.EMPTY; } } - return left; + return itemsToAdd; } @Override diff --git a/src/main/java/appeng/util/item/AEItemStack.java b/src/main/java/appeng/util/item/AEItemStack.java index 8f869035a..ce09a306d 100644 --- a/src/main/java/appeng/util/item/AEItemStack.java +++ b/src/main/java/appeng/util/item/AEItemStack.java @@ -18,6 +18,7 @@ package appeng.util.item; +import java.lang.ref.WeakReference; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -42,320 +43,351 @@ import appeng.api.storage.data.IAEItemStack; import appeng.core.Api; import appeng.util.Platform; -public final class AEItemStack extends AEStack implements IAEItemStack { - private static final String NBT_STACKSIZE = "Cnt"; - private static final String NBT_REQUESTABLE = "Req"; - private static final String NBT_CRAFTABLE = "Craft"; - private final AESharedItemStack sharedStack; - private Optional oreReference; +public final class AEItemStack extends AEStack implements IAEItemStack +{ + private static final String NBT_STACKSIZE = "Cnt"; + private static final String NBT_REQUESTABLE = "Req"; + private static final String NBT_CRAFTABLE = "Craft"; - @SideOnly(Side.CLIENT) - private String displayName; - @SideOnly( Side.CLIENT ) - private List tooltip; - private ItemStack cachedItemStack; + private final AESharedItemStack sharedStack; + private Optional oreReference; - private AEItemStack(final AEItemStack is) { - this.setStackSize(is.getStackSize()); - this.setCraftable(is.isCraftable()); - this.setCountRequestable(is.getCountRequestable()); - this.sharedStack = is.sharedStack; - this.oreReference = is.oreReference; - } + @SideOnly( Side.CLIENT ) + private String displayName; + @SideOnly( Side.CLIENT ) + private List tooltip; + private WeakReference cachedItemStack; - private AEItemStack(final AESharedItemStack is, long size) { - this.sharedStack = is; - this.setStackSize(size); - this.setCraftable(false); - this.setCountRequestable(0); - this.oreReference = OreHelper.INSTANCE.getOre( is.getDefinition() ); - } + private AEItemStack( final AEItemStack is ) + { + this.setStackSize( is.getStackSize() ); + this.setCraftable( is.isCraftable() ); + this.setCountRequestable( is.getCountRequestable() ); + this.sharedStack = is.sharedStack; + this.oreReference = is.oreReference; + } - @Nullable - public static AEItemStack fromItemStack(@Nonnull final ItemStack stack) { - if (stack.isEmpty()) { - return null; - } + private AEItemStack( final AESharedItemStack is, long size ) + { + this.sharedStack = is; + this.setStackSize( size ); + this.setCraftable( false ); + this.setCountRequestable( 0 ); + this.oreReference = OreHelper.INSTANCE.getOre( is.getDefinition() ); + } - return new AEItemStack(AEItemStackRegistry.getRegisteredStack(stack), stack.getCount()); - } + @Nullable + public static AEItemStack fromItemStack( @Nonnull final ItemStack stack ) + { + if( stack.isEmpty() ) + { + return null; + } - public static IAEItemStack fromNBT( final NBTTagCompound i ) - { - if( i == null ) - { - return null; - } + return new AEItemStack( AEItemStackRegistry.getRegisteredStack( stack ), stack.getCount() ); + } - final ItemStack itemstack = new ItemStack( i ); - if( itemstack.isEmpty() ) - { - return null; - } + public static IAEItemStack fromNBT( final NBTTagCompound i ) + { + if( i == null ) + { + return null; + } - final AEItemStack item = AEItemStack.fromItemStack( itemstack ); + final ItemStack itemstack = new ItemStack( i ); + if( itemstack.isEmpty() ) + { + return null; + } - item.setStackSize(i.getLong(NBT_STACKSIZE)); - item.setCountRequestable(i.getLong(NBT_REQUESTABLE)); - item.setCraftable(i.getBoolean(NBT_CRAFTABLE)); - return item; - } + final AEItemStack item = AEItemStack.fromItemStack( itemstack ); - @Override - public void writeToNBT(final NBTTagCompound i) { - this.getDefinition().writeToNBT( i ); + item.setStackSize( i.getLong( NBT_STACKSIZE ) ); + item.setCountRequestable( i.getLong( NBT_REQUESTABLE ) ); + item.setCraftable( i.getBoolean( NBT_CRAFTABLE ) ); + return item; + } - i.setLong(NBT_STACKSIZE, this.getStackSize()); - i.setLong(NBT_REQUESTABLE, this.getCountRequestable()); - i.setBoolean(NBT_CRAFTABLE, this.isCraftable()); - } + @Override + public void writeToNBT( final NBTTagCompound i ) + { + this.getDefinition().writeToNBT( i ); - public static AEItemStack fromPacket( final ByteBuf data ) - { - final byte mask = data.readByte(); - final byte stackType = (byte) ( ( mask & 0x0C ) >> 2 ); - final byte countReqType = (byte) ( ( mask & 0x30 ) >> 4 ); - final boolean isCraftable = ( mask & 0x40 ) > 0; + i.setLong( NBT_STACKSIZE, this.getStackSize() ); + i.setLong( NBT_REQUESTABLE, this.getCountRequestable() ); + i.setBoolean( NBT_CRAFTABLE, this.isCraftable() ); + } - final ItemStack itemstack = new ItemStack( ByteBufUtils.readTag( data ) ); - final long stackSize = getPacketValue( stackType, data ); - final long countRequestable = getPacketValue( countReqType, data ); + public static AEItemStack fromPacket( final ByteBuf data ) + { + final byte mask = data.readByte(); + final byte stackType = (byte) ( ( mask & 0x0C ) >> 2 ); + final byte countReqType = (byte) ( ( mask & 0x30 ) >> 4 ); + final boolean isCraftable = ( mask & 0x40 ) > 0; - if( itemstack.isEmpty() ) - { - return null; - } + final ItemStack itemstack = new ItemStack( ByteBufUtils.readTag( data ) ); + final long stackSize = getPacketValue( stackType, data ); + final long countRequestable = getPacketValue( countReqType, data ); - final AEItemStack item = new AEItemStack( AEItemStackRegistry.getRegisteredStack( itemstack ), stackSize ); - item.setCountRequestable( countRequestable ); - item.setCraftable( isCraftable ); - return item; - } + if( itemstack.isEmpty() ) + { + return null; + } - @Override - public void writeToPacket( final ByteBuf i ) - { - final byte mask = (byte) ( ( this.getType( this.getStackSize() ) << 2 ) | ( this - .getType( this.getCountRequestable() ) << 4 ) | ( (byte) ( this.isCraftable() ? 1 : 0 ) << 6 ) | ( this.hasTagCompound() ? 1 : 0 ) << 7 ); + final AEItemStack item = new AEItemStack( AEItemStackRegistry.getRegisteredStack( itemstack ), stackSize ); + item.setCountRequestable( countRequestable ); + item.setCraftable( isCraftable ); + return item; + } - i.writeByte( mask ); - ByteBufUtils.writeTag( i, this.getDefinition().serializeNBT() ); - this.putPacketValue( i, this.getStackSize() ); - this.putPacketValue( i, this.getCountRequestable() ); - } + @Override + public void writeToPacket( final ByteBuf i ) + { + final byte mask = (byte) ( ( this.getType( this.getStackSize() ) << 2 ) | ( this.getType( this.getCountRequestable() ) << 4 ) | ( (byte) ( this.isCraftable() ? 1 : 0 ) << 6 ) | ( this.hasTagCompound() ? 1 : 0 ) << 7 ); - @Override - public void add(final IAEItemStack option) { - if (option == null) { - return; - } + i.writeByte( mask ); + ByteBufUtils.writeTag( i, this.getDefinition().serializeNBT() ); + this.putPacketValue( i, this.getStackSize() ); + this.putPacketValue( i, this.getCountRequestable() ); + } - this.incStackSize(option.getStackSize()); - this.setCountRequestable(this.getCountRequestable() + option.getCountRequestable()); - this.setCraftable(this.isCraftable() || option.isCraftable()); - } + @Override + public void add( final IAEItemStack option ) + { + if( option == null ) + { + return; + } - @Override - public boolean fuzzyComparison(final IAEItemStack other, final FuzzyMode mode) { - final ItemStack itemStack = this.getDefinition(); - final ItemStack otherStack = other.getDefinition(); + this.incStackSize( option.getStackSize() ); + this.setCountRequestable( this.getCountRequestable() + option.getCountRequestable() ); + this.setCraftable( this.isCraftable() || option.isCraftable() ); + } - return this.fuzzyItemStackComparison(itemStack, otherStack, mode); - } + @Override + public boolean fuzzyComparison( final IAEItemStack other, final FuzzyMode mode ) + { + final ItemStack itemStack = this.getDefinition(); + final ItemStack otherStack = other.getDefinition(); - @Override - public IAEItemStack copy() { - return new AEItemStack(this); - } + return this.fuzzyItemStackComparison( itemStack, otherStack, mode ); + } - @Override - public boolean isItem() - { - return true; - } + @Override + public IAEItemStack copy() + { + return new AEItemStack( this ); + } - @Override - public boolean isFluid() - { - return false; - } + @Override + public boolean isItem() + { + return true; + } - @Override - public IStorageChannel getChannel() { - return Api.INSTANCE.storage().getStorageChannel(IItemStorageChannel.class); - } + @Override + public boolean isFluid() + { + return false; + } - @Override - public ItemStack createItemStack() { - return ItemHandlerHelper.copyStackWithSize(this.getDefinition(), - (int) Math.min(Integer.MAX_VALUE, this.getStackSize())); - } + @Override + public IStorageChannel getChannel() + { + return Api.INSTANCE.storage().getStorageChannel( IItemStorageChannel.class ); + } - @Override - public Item getItem() { - return this.getDefinition().getItem(); - } + @Override + public ItemStack createItemStack() + { + return ItemHandlerHelper.copyStackWithSize( this.getDefinition(), (int) Math.min( Integer.MAX_VALUE, this.getStackSize() ) ); + } - @Override - public int getItemDamage() { - return this.sharedStack.getItemDamage(); - } + @Override + public Item getItem() + { + return this.getDefinition().getItem(); + } - @Override - public boolean sameOre( final IAEItemStack is ) - { - return OreHelper.INSTANCE.sameOre( this, is ); - } + @Override + public int getItemDamage() + { + return this.sharedStack.getItemDamage(); + } - @Override - public boolean isSameType(final IAEItemStack otherStack) { - if (otherStack == null) { - return false; - } + @Override + public boolean sameOre( final IAEItemStack is ) + { + return OreHelper.INSTANCE.sameOre( this, is ); + } - return Objects.equals(this.sharedStack, ((AEItemStack) otherStack).sharedStack); - } + @Override + public boolean isSameType( final IAEItemStack otherStack ) + { + if( otherStack == null ) + { + return false; + } - @Override - public boolean isSameType(final ItemStack otherStack) { - if (otherStack.isEmpty()) { - return false; - } - int oldSize = otherStack.getCount(); + return Objects.equals( this.sharedStack, ( (AEItemStack) otherStack ).sharedStack ); + } - otherStack.setCount(1); - boolean ret = ItemStack.areItemStacksEqual(this.getDefinition(), otherStack); - otherStack.setCount(oldSize); + @Override + public boolean isSameType( final ItemStack otherStack ) + { + if( otherStack.isEmpty() ) + { + return false; + } + int oldSize = otherStack.getCount(); - return ret; - } + otherStack.setCount( 1 ); + boolean ret = ItemStack.areItemStacksEqual( this.getDefinition(), otherStack ); + otherStack.setCount( oldSize ); - @Override - public int hashCode() { - return this.sharedStack.hashCode(); - } + return ret; + } - @Override - public boolean equals( final Object ia ) - { - if( ia instanceof AEItemStack ) - { - return this.isSameType( (AEItemStack) ia ); - } - else if( ia instanceof ItemStack ) - { - // this actually breaks the equals contract (being equals to unrelated classes) - return equals( (ItemStack) ia ); - } - return false; - } + @Override + public int hashCode() + { + return this.sharedStack.hashCode(); + } - @Override - public boolean equals( final ItemStack is ) - { - return this.isSameType( is ); - } + @Override + public boolean equals( final Object ia ) + { + if( ia instanceof AEItemStack ) + { + return this.isSameType( (AEItemStack) ia ); + } + else if( ia instanceof ItemStack ) + { + // this actually breaks the equals contract (being equals to unrelated classes) + return equals( (ItemStack) ia ); + } + return false; + } - @Override - public ItemStack getCachedItemStack( long stackSize ) - { - @Nullable ItemStack currentCached = this.cachedItemStack; - cachedItemStack = ItemStack.EMPTY; + @Override + public boolean equals( final ItemStack is ) + { + return this.isSameType( is ); + } - ItemStack itemStack; + @Override + public ItemStack getCachedItemStack( long stackSize ) + { + ItemStack currentCached = null; + if( this.cachedItemStack != null ) + { + currentCached = this.cachedItemStack.get(); + } - if( currentCached != null ) - { - // Cache is suitable, just update the count - itemStack = currentCached; - currentCached.setCount( Ints.saturatedCast( stackSize ) ); - } - else - { - // We need a new stack :-( - itemStack = this.createItemStack(); - } - return itemStack; - } + ItemStack itemStack; - @Override - public void setCachedItemStack( ItemStack itemStack ) - { - this.cachedItemStack = itemStack; - } + if( currentCached != null ) + { + // Cache is suitable, just update the count + itemStack = currentCached; + currentCached.setCount( Ints.saturatedCast( stackSize ) ); + } + else + { + // We need a new stack :-( + itemStack = this.createItemStack(); + } + return itemStack; + } - @Override - public String toString() - { - return this.getStackSize() + "x" + this.getDefinition().getItem().getRegistryName(); - } + @Override + public void setCachedItemStack( ItemStack itemStack ) + { + this.cachedItemStack = new WeakReference<>( itemStack ); + } - @SideOnly( Side.CLIENT ) - public List getToolTip() - { - if( this.tooltip == null ) - { - this.tooltip = Platform.getTooltip( this.asItemStackRepresentation() ); - } - return this.tooltip; - } + @Override + public String toString() + { + return this.getStackSize() + "x" + this.getDefinition().getItem().getRegistryName(); + } - @SideOnly( Side.CLIENT ) - public String getDisplayName() - { - if( this.displayName == null ) - { - this.displayName = Platform.getItemDisplayName( this.asItemStackRepresentation() ); - } - return this.displayName; - } + @SideOnly( Side.CLIENT ) + public List getToolTip() + { + if( this.tooltip == null ) + { + this.tooltip = Platform.getTooltip( this.asItemStackRepresentation() ); + } + return this.tooltip; + } - @SideOnly( Side.CLIENT ) - public String getModID() - { - return this.getDefinition().getItem().getRegistryName().getResourceDomain(); - } + @SideOnly( Side.CLIENT ) + public String getDisplayName() + { + if( this.displayName == null ) + { + this.displayName = Platform.getItemDisplayName( this.asItemStackRepresentation() ); + } + return this.displayName; + } - public Optional getOre() - { - return this.oreReference; - } + @SideOnly( Side.CLIENT ) + public String getModID() + { + return this.getDefinition().getItem().getRegistryName().getResourceDomain(); + } - @Override - public boolean hasTagCompound() - { - return this.getDefinition().hasTagCompound(); - } + public Optional getOre() + { + return this.oreReference; + } - @Override - public ItemStack asItemStackRepresentation() { - return this.getDefinition().copy(); - } + @Override + public boolean hasTagCompound() + { + return this.getDefinition().hasTagCompound(); + } - @Override - public ItemStack getDefinition() { - return this.sharedStack.getDefinition(); - } + @Override + public ItemStack asItemStackRepresentation() + { + return this.getDefinition().copy(); + } - AESharedItemStack getSharedStack() { - return this.sharedStack; - } + @Override + public ItemStack getDefinition() + { + return this.sharedStack.getDefinition(); + } - private boolean fuzzyItemStackComparison(ItemStack a, ItemStack b, FuzzyMode mode) { - if (a.getItem() == b.getItem() && a.getItem().isDamageable()) { - if (mode == FuzzyMode.IGNORE_ALL) { - return true; - } else if (mode == FuzzyMode.PERCENT_99) { - return a.getItemDamage() > 1 == b.getItemDamage() > 1; - } else { - final float percentDamageOfA = (float) a.getItemDamage() / a.getMaxDamage(); - final float percentDamageOfB = (float) b.getItemDamage() / b.getMaxDamage(); + AESharedItemStack getSharedStack() + { + return this.sharedStack; + } - return percentDamageOfA > mode.breakPoint == percentDamageOfB > mode.breakPoint; - } - } + private boolean fuzzyItemStackComparison( ItemStack a, ItemStack b, FuzzyMode mode ) + { + if( a.getItem() == b.getItem() && a.getItem().isDamageable() ) + { + if( mode == FuzzyMode.IGNORE_ALL ) + { + return true; + } + else if( mode == FuzzyMode.PERCENT_99 ) + { + return a.getItemDamage() > 1 == b.getItemDamage() > 1; + } + else + { + final float percentDamageOfA = (float) a.getItemDamage() / a.getMaxDamage(); + final float percentDamageOfB = (float) b.getItemDamage() / b.getMaxDamage(); - return false; - } + return percentDamageOfA > mode.breakPoint == percentDamageOfB > mode.breakPoint; + } + } + + return false; + } }