diff --git a/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java b/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java index 2c57e27e3..8cb836c6d 100644 --- a/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java +++ b/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java @@ -19,17 +19,10 @@ package appeng.parts.misc; -import java.util.*; - -import appeng.api.config.Settings; -import appeng.api.config.StorageFilter; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.item.ItemStack; -import net.minecraftforge.items.IItemHandler; - import appeng.api.AEApi; import appeng.api.config.Actionable; +import appeng.api.config.Settings; +import appeng.api.config.StorageFilter; import appeng.api.networking.security.IActionSource; import appeng.api.networking.storage.IBaseMonitor; import appeng.api.networking.ticking.TickRateModulation; @@ -39,12 +32,24 @@ import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; import appeng.core.AELog; +import appeng.me.GridAccessException; import appeng.me.helpers.IGridProxyable; import appeng.me.storage.ITickingMonitor; import appeng.util.Platform; +import appeng.util.inv.ItemHandlerIterator; +import appeng.util.inv.ItemSlot; import appeng.util.item.AEItemStack; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandler; import org.apache.commons.lang3.tuple.Pair; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + /** * Wraps an Item Handler in such a way that it can be used as an IMEInventory for items. @@ -79,22 +84,15 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor> injectedList = new ArrayList<>(); + // This uses a brute force approach and tries to jam it in every slot the inventory exposes. for( int i = 0; i < slotCount && !remaining.isEmpty(); i++ ) { - int countPre = remaining.getCount(); remaining = this.itemHandler.insertItem( i, remaining, simulate ); - int countPos = remaining.getCount(); if( remaining.isEmpty() ) { - injectedList.add( Pair.of( i, countPre ) ); break; } - else if( countPos < countPre ) - { - injectedList.add( Pair.of( i, countPre - countPos ) ); - } } // At this point, we still have some items left... @@ -106,28 +104,13 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor pair : injectedList ) - { - if( pair.getKey() >= this.cache.cachedAeStacks.length ) - { - this.cache.update(); - break; - } - if( this.cache.cachedAeStacks[pair.getKey()] == null ) - { - this.cache.cachedAeStacks[pair.getKey()] = iox.copy().setStackSize( pair.getValue() ); - } - else - { - this.cache.cachedAeStacks[pair.getKey()].incStackSize( pair.getValue() ); - } - } + // meh } } @@ -145,10 +128,8 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor> extractedList = new ArrayList<>(); - - for ( int i = 0; i < this.itemHandler.getSlots(); i++ ) + for( int i = 0; i < this.itemHandler.getSlots(); i++ ) { ItemStack stackInInventorySlot = this.itemHandler.getStackInSlot( i ); @@ -191,16 +172,10 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor 0 ); + } while ( !extracted.isEmpty() && remainingCurrentSlot > 0 ); remainingSize -= stackSizeCurrentSlot - remainingCurrentSlot; - if (!gathered.isEmpty()) - { - extractedList.add( Pair.of( i, gathered.getCount() ) ); - } - // Done? if( remainingSize <= 0 ) { @@ -212,23 +187,13 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor pair : extractedList ) - { - if( this.cache.cachedAeStacks[pair.getKey()] != null ) - { - this.cache.cachedAeStacks[pair.getKey()].decStackSize( pair.getValue() ); - if( this.cache.cachedAeStacks[pair.getKey()].getStackSize() == 0 ) - { - this.cache.cachedAeStacks[pair.getKey()] = null; - } - } - } + // meh } } @@ -286,7 +251,7 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor a ) { final Iterator, Object>> i = this.listeners.entrySet().iterator(); - while( i.hasNext() ) + while ( i.hasNext() ) { final Map.Entry, Object> l = i.next(); final IMEMonitorHandlerReceiver key = l.getKey(); @@ -301,9 +266,9 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor { - private IAEItemStack[] cachedAeStacks = new IAEItemStack[0]; + private IItemList cachedAeStacks = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemHandler itemHandler; private final StorageFilter mode; @@ -315,106 +280,78 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor getAvailableItems( IItemList out ) { - Arrays.stream( this.cachedAeStacks ).forEach( out::add ); + this.cachedAeStacks.forEach( out::add ); return out; } + private StorageFilter getMode() + { + return this.mode; + } + public List update() { final List changes = new ArrayList<>(); - final int slots = this.itemHandler.getSlots(); - // Make room for new slots - if( slots > this.cachedAeStacks.length ) + IItemList storage = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + + for( final ItemSlot is : this ) { - this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots ); + final ItemStack stackInSlot = !is.isExtractable() && this.getMode() == StorageFilter.EXTRACTABLE_ONLY ? ItemStack.EMPTY : is.getItemStack(); + if( !stackInSlot.isEmpty() ) + { + storage.add( AEItemStack.fromItemStack( stackInSlot ) ); + } } - for( int slot = 0; slot < slots; slot++ ) + Iterator cachedAeStacksIterator = cachedAeStacks.iterator(); + while ( cachedAeStacksIterator.hasNext() ) { - // Save the old stuff - final IAEItemStack oldAeIS = this.cachedAeStacks[slot]; - ItemStack newIS = this.itemHandler.getStackInSlot( slot ); - if( this.mode == StorageFilter.EXTRACTABLE_ONLY && !newIS.isEmpty() ) + IAEItemStack cachedStack = cachedAeStacksIterator.next(); + IAEItemStack storedStack = storage.findPrecise( cachedStack ); + if( storedStack == null ) { - if( this.itemHandler.extractItem( slot, 1, true ).isEmpty() ) - { - newIS = ItemStack.EMPTY; - } + changes.add( cachedStack.setStackSize( -cachedStack.getStackSize() ) ); + cachedAeStacksIterator.remove(); + } + else if( cachedStack.getStackSize() != storedStack.getStackSize() ) + { + handleStackSizeChanged( cachedStack, storedStack, changes ); } - this.handlePossibleSlotChanges( slot, oldAeIS, newIS, changes ); } - // Handle cases where the number of slots actually is lower now than before - if( slots < this.cachedAeStacks.length ) + for( IAEItemStack storedStack : storage ) { - for( int slot = slots; slot < this.cachedAeStacks.length; slot++ ) + if( cachedAeStacks.findPrecise( storedStack ) == null ) { - final IAEItemStack aeStack = this.cachedAeStacks[slot]; - - if( aeStack != null ) - { - final IAEItemStack a = aeStack.copy(); - a.setStackSize( -a.getStackSize() ); - changes.add( a ); - } + cachedAeStacks.add( storedStack ); + changes.add( storedStack.copy() ); } - - // Reduce the cache size - this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots ); } return changes; } - private void handlePossibleSlotChanges( int slot, IAEItemStack oldAeIS, ItemStack newIS, List changes ) - { - if( oldAeIS != null && oldAeIS.isSameType( newIS ) ) - { - this.handleStackSizeChanged( slot, oldAeIS, newIS, changes ); - } - else - { - this.handleItemChanged( slot, oldAeIS, newIS, changes ); - } - } - - private void handleStackSizeChanged( int slot, IAEItemStack oldAeIS, ItemStack newIS, List changes ) + private void handleStackSizeChanged( IAEItemStack cachedStack, IAEItemStack storedStack, List changes ) { // Still the same item, but amount might have changed - final long diff = newIS.getCount() - oldAeIS.getStackSize(); + final long diff = storedStack.getStackSize() - cachedStack.getStackSize(); if( diff != 0 ) { - final IAEItemStack stack = oldAeIS.copy(); - stack.setStackSize( newIS.getCount() ); + cachedStack.setStackSize( storedStack.getStackSize() ); - this.cachedAeStacks[slot] = stack; - - final IAEItemStack a = stack.copy(); - a.setStackSize( diff ); - changes.add( a ); + final IAEItemStack diffStack = cachedStack.copy(); + diffStack.setStackSize( diff ); + changes.add( diffStack ); } } - private void handleItemChanged( int slot, IAEItemStack oldAeIS, ItemStack newIS, List changes ) + @Override + public Iterator iterator() { - // Completely different item - this.cachedAeStacks[slot] = AEItemStack.fromItemStack( newIS ); - - // If we had a stack previously in this slot, notify the network about its disappearance - if( oldAeIS != null ) - { - oldAeIS.setStackSize( -oldAeIS.getStackSize() ); - changes.add( oldAeIS ); - } - - // Notify the network about the new stack. Note that this is null if newIS was null - if( this.cachedAeStacks[slot] != null ) - { - changes.add( this.cachedAeStacks[slot] ); - } + return new ItemHandlerIterator( this.itemHandler ); } - } + } } diff --git a/src/main/java/appeng/parts/misc/ItemRepositoryAdapter.java b/src/main/java/appeng/parts/misc/ItemRepositoryAdapter.java index 0bfe588eb..0c6e62de1 100644 --- a/src/main/java/appeng/parts/misc/ItemRepositoryAdapter.java +++ b/src/main/java/appeng/parts/misc/ItemRepositoryAdapter.java @@ -1,16 +1,5 @@ package appeng.parts.misc; -import java.util.*; -import java.util.stream.Collectors; - -import appeng.api.storage.IStorageChannel; - -import appeng.core.AELog; -import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.item.ItemStack; - import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.networking.security.IActionSource; @@ -18,15 +7,24 @@ import appeng.api.networking.storage.IBaseMonitor; import appeng.api.networking.ticking.TickRateModulation; import appeng.api.storage.IMEInventory; import appeng.api.storage.IMEMonitorHandlerReceiver; +import appeng.api.storage.IStorageChannel; import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; +import appeng.core.AELog; import appeng.me.GridAccessException; import appeng.me.helpers.IGridProxyable; import appeng.me.storage.ITickingMonitor; import appeng.util.item.AEItemStack; +import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.item.ItemStack; -import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; /** * Wraps an Item Repository in such a way that it can be used as an IMEInventory for items. @@ -86,7 +84,7 @@ class ItemRepositoryAdapter implements IMEInventory, IBaseMonitor< public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src ) { ItemStack requestedItemStack = request.getDefinition(); - int remainingSize = (int) Math.min( Integer.MAX_VALUE, request.getStackSize()); + int remainingSize = (int) Math.min( Integer.MAX_VALUE, request.getStackSize() ); final boolean simulate = ( mode == Actionable.SIMULATE ); @@ -146,7 +144,7 @@ class ItemRepositoryAdapter implements IMEInventory, IBaseMonitor< private void postDifference( Iterable a ) { final Iterator, Object>> i = this.listeners.entrySet().iterator(); - while( i.hasNext() ) + while ( i.hasNext() ) { final Map.Entry, Object> l = i.next(); final IMEMonitorHandlerReceiver key = l.getKey(); @@ -186,7 +184,7 @@ class ItemRepositoryAdapter implements IMEInventory, IBaseMonitor< private static class InventoryCache { - private IAEItemStack[] cachedAeStacks = new IAEItemStack[0]; + private IItemList cachedAeStacks = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemRepository iItemRepository; public InventoryCache( IItemRepository iItemRepository ) @@ -196,102 +194,59 @@ class ItemRepositoryAdapter implements IMEInventory, IBaseMonitor< public IItemList getAvailableItems( IItemList out ) { - Arrays.stream( this.cachedAeStacks ).forEach( out::add ); + this.cachedAeStacks.forEach( out::add ); return out; } public List update() { final List changes = new ArrayList<>(); - IItemList storage = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + IItemList storage = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); this.iItemRepository.getAllItems().stream().map( s -> AEItemStack.fromItemStack( s.itemPrototype ).setStackSize( s.count ) ).forEach( storage::add ); - final int size = storage.size(); - - // Make room for new slots - if( size > this.cachedAeStacks.length ) + Iterator cachedAeStacksIterator = cachedAeStacks.iterator(); + while ( cachedAeStacksIterator.hasNext() ) { - this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, size ); - } - - int sx = 0; - for( IAEItemStack iaeItemStack : storage ) - { - // Save the old stuff - final IAEItemStack oldAeIS = this.cachedAeStacks[sx]; - - this.handlePossibleSlotChanges( sx, oldAeIS, iaeItemStack, changes ); - sx++; - } - - // Handle cases where the number of slots actually is lower now than before - if( size < this.cachedAeStacks.length ) - { - for( final IAEItemStack aeStack : this.cachedAeStacks ) + IAEItemStack cachedStack = cachedAeStacksIterator.next(); + IAEItemStack storedStack = storage.findPrecise( cachedStack ); + if( storedStack == null ) { - if( aeStack != null ) - { - final IAEItemStack a = aeStack.copy(); - a.setStackSize( -a.getStackSize() ); - changes.add( a ); - } + changes.add( cachedStack.setStackSize( -cachedStack.getStackSize() ) ); + cachedAeStacksIterator.remove(); } + else if( cachedStack.getStackSize() != storedStack.getStackSize() ) + { + handleStackSizeChanged( cachedStack, storedStack, changes ); + } + } - // Reduce the cache size - this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, size ); + for( IAEItemStack storedStack : storage ) + { + if( cachedAeStacks.findPrecise( storedStack ) == null ) + { + cachedAeStacks.add( storedStack ); + changes.add( storedStack.copy() ); + } } return changes; } - private void handlePossibleSlotChanges( int slot, IAEItemStack oldAeIS, IAEItemStack newIS, List changes ) - { - if( oldAeIS != null && oldAeIS.isSameType( newIS ) ) - { - this.handleStackSizeChanged( slot, oldAeIS, newIS, changes ); - } - else - { - this.handleItemChanged( slot, oldAeIS, newIS, changes ); - } - } - - private void handleStackSizeChanged( int slot, IAEItemStack oldAeIS, IAEItemStack newIS, List changes ) + private void handleStackSizeChanged( IAEItemStack cachedStack, IAEItemStack storedStack, List changes ) { // Still the same item, but amount might have changed - final long diff = newIS.getStackSize() - oldAeIS.getStackSize(); + final long diff = storedStack.getStackSize() - cachedStack.getStackSize(); if( diff != 0 ) { - final IAEItemStack stack = oldAeIS.copy(); - stack.setStackSize( newIS.getStackSize() ); + cachedStack.setStackSize( storedStack.getStackSize() ); - this.cachedAeStacks[slot] = stack; - - final IAEItemStack a = stack.copy(); - a.setStackSize( diff ); - changes.add( a ); + final IAEItemStack diffStack = cachedStack.copy(); + diffStack.setStackSize( diff ); + changes.add( diffStack ); } } - private void handleItemChanged( int slot, IAEItemStack oldAeIS, IAEItemStack newIS, List changes ) - { - // Completely different item - this.cachedAeStacks[slot] = newIS ; - - // If we had a stack previously in this slot, notify the network about its disappearance - if( oldAeIS != null ) - { - oldAeIS.setStackSize( -oldAeIS.getStackSize() ); - changes.add( oldAeIS ); - } - - // Notify the network about the new stack. Note that this is null if newIS was null - if( this.cachedAeStacks[slot] != null ) - { - changes.add( this.cachedAeStacks[slot] ); - } - } } }