From ba9af942285725c73781cd1fb3437f1a8ce76dd4 Mon Sep 17 00:00:00 2001 From: fscan Date: Sun, 12 Nov 2017 18:12:56 +0100 Subject: [PATCH] Fix StorageBus not updating item count correctly (#3218) * Queue tick instead of ticking immediatley --- .../appeng/parts/misc/ItemHandlerAdapter.java | 317 ++++++++++-------- .../appeng/parts/misc/PartStorageBus.java | 40 +-- 2 files changed, 192 insertions(+), 165 deletions(-) diff --git a/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java b/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java index 3f30482a..2f647279 100644 --- a/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java +++ b/src/main/java/appeng/parts/misc/ItemHandlerAdapter.java @@ -19,10 +19,10 @@ package appeng.parts.misc; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -36,11 +36,12 @@ 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.Platform; import appeng.util.item.AEItemStack; @@ -51,20 +52,17 @@ import appeng.util.item.AEItemStack; */ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor, ITickingMonitor { - private final Map, Object> listeners = new HashMap<>(); - private IActionSource mySource; - private final IItemHandler itemHandler; + private final IGridProxyable proxyable; + private final InventoryCache cache; - private ItemStack[] cachedStacks = new ItemStack[0]; - - private IAEItemStack[] cachedAeStacks = new IAEItemStack[0]; - - ItemHandlerAdapter( IItemHandler itemHandler ) + ItemHandlerAdapter( IItemHandler itemHandler, IGridProxyable proxy ) { this.itemHandler = itemHandler; + this.proxyable = proxy; + this.cache = new InventoryCache( this.itemHandler ); } @Override @@ -91,7 +89,14 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor, IBaseMonitor, IBaseMonitor this.cachedStacks.length ) - { - return ItemStack.EMPTY; - } - - if( this.cachedStacks[pos] == null ) - { - return ItemStack.EMPTY; - } - - return this.cachedStacks[pos]; - } - @Override public TickRateModulation onTick() { - LinkedList changes = new LinkedList<>(); - - int slots = this.itemHandler.getSlots(); - - // Make room for new slots - if( slots > this.cachedStacks.length ) - { - this.cachedStacks = Arrays.copyOf( this.cachedStacks, slots ); - this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots ); - } - - for( int slot = 0; slot < slots; slot++ ) - { - // Save the old stuff - ItemStack oldIS = this.getItemStackInCachedSlot( slot ); - IAEItemStack oldAeIS = this.cachedAeStacks[slot]; - - ItemStack newIS = this.itemHandler.getStackInSlot( slot ); - - if( this.isDifferent( newIS, oldIS ) ) - { - this.addItemChange( slot, oldAeIS, newIS, changes ); - } - else if( !newIS.isEmpty() && !oldIS.isEmpty() ) - { - this.addPossibleStackSizeChange( slot, oldAeIS, newIS, changes ); - } - } - - // Handle cases where the number of slots actually is lower now than before - if( slots < this.cachedStacks.length ) - { - for( int slot = slots; slot < this.cachedStacks.length; slot++ ) - { - IAEItemStack aeStack = this.cachedAeStacks[slot]; - if( aeStack != null ) - { - IAEItemStack a = aeStack.copy(); - a.setStackSize( -a.getStackSize() ); - changes.add( a ); - } - } - - // Reduce the cache size - this.cachedStacks = Arrays.copyOf( this.cachedStacks, slots ); - this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots ); - } - + List changes = this.cache.update(); if( !changes.isEmpty() ) { this.postDifference( changes ); @@ -253,73 +203,6 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor changes ) - { - // Completely different item - this.cachedStacks[slot] = newIS; - this.cachedAeStacks[slot] = AEItemStack.fromItemStack( newIS ); - - // If we had a stack previously in this slot, notify the newtork 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] ); - } - } - - private void addPossibleStackSizeChange( int slot, IAEItemStack oldAeIS, ItemStack newIS, List changes ) - { - // Still the same item, but amount might have changed - long diff = newIS.getCount() - oldAeIS.getStackSize(); - - if( diff != 0 ) - { - IAEItemStack stack = oldAeIS.copy(); - stack.setStackSize( newIS.getCount() ); - - this.cachedStacks[slot] = newIS; - this.cachedAeStacks[slot] = stack; - - final IAEItemStack a = stack.copy(); - a.setStackSize( diff ); - changes.add( a ); - } - } - - private boolean isDifferent( final ItemStack a, final ItemStack b ) - { - if( a == b && b.isEmpty() ) - { - return false; - } - - return a.isEmpty() || b.isEmpty() || !Platform.itemComparisons().isSameItem( a, b ); - } - - 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 void setActionSource( final IActionSource mySource ) { @@ -339,7 +222,7 @@ class ItemHandlerAdapter implements IMEInventory, IBaseMonitor, IBaseMonitor 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 static class InventoryCache + { + private ItemStack[] cachedStacks = new ItemStack[0]; + private IAEItemStack[] cachedAeStacks = new IAEItemStack[0]; + private final IItemHandler itemHandler; + + public InventoryCache( IItemHandler itemHandler ) + { + this.itemHandler = itemHandler; + } + + public List update() + { + List changes = new ArrayList<>(); + + int slots = this.itemHandler.getSlots(); + + // Make room for new slots + if( slots > this.cachedStacks.length ) + { + this.cachedStacks = Arrays.copyOf( this.cachedStacks, slots ); + this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots ); + } + + for( int slot = 0; slot < slots; slot++ ) + { + // Save the old stuff + ItemStack oldIS = this.getItemStackInCachedSlot( slot ); + IAEItemStack oldAeIS = this.cachedAeStacks[slot]; + + ItemStack newIS = this.itemHandler.getStackInSlot( slot ); + + if( isDifferent( newIS, oldIS ) ) + { + this.addItemChange( slot, oldAeIS, newIS, changes ); + } + else if( !newIS.isEmpty() && !oldIS.isEmpty() ) + { + this.addPossibleStackSizeChange( slot, oldAeIS, newIS, changes ); + } + } + + // Handle cases where the number of slots actually is lower now than before + if( slots < this.cachedStacks.length ) + { + for( int slot = slots; slot < this.cachedStacks.length; slot++ ) + { + IAEItemStack aeStack = this.cachedAeStacks[slot]; + if( aeStack != null ) + { + IAEItemStack a = aeStack.copy(); + a.setStackSize( -a.getStackSize() ); + changes.add( a ); + } + } + + // Reduce the cache size + this.cachedStacks = Arrays.copyOf( this.cachedStacks, slots ); + this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots ); + } + + return changes; + } + + private void addPossibleStackSizeChange( int slot, IAEItemStack oldAeIS, ItemStack newIS, List changes ) + { + // Still the same item, but amount might have changed + long diff = newIS.getCount() - oldAeIS.getStackSize(); + + if( diff != 0 ) + { + IAEItemStack stack = oldAeIS.copy(); + stack.setStackSize( newIS.getCount() ); + + this.cachedStacks[slot] = newIS; + this.cachedAeStacks[slot] = stack; + + final IAEItemStack a = stack.copy(); + a.setStackSize( diff ); + changes.add( a ); + } + } + + private ItemStack getItemStackInCachedSlot( int pos ) + { + if( pos > this.cachedStacks.length ) + { + return ItemStack.EMPTY; + } + + if( this.cachedStacks[pos] == null ) + { + return ItemStack.EMPTY; + } + + return this.cachedStacks[pos]; + } + + private void addItemChange( int slot, IAEItemStack oldAeIS, ItemStack newIS, List changes ) + { + // Completely different item + this.cachedStacks[slot] = newIS; + this.cachedAeStacks[slot] = AEItemStack.fromItemStack( newIS ); + + // If we had a stack previously in this slot, notify the newtork 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] ); + } + } + + private static boolean isDifferent( final ItemStack a, final ItemStack b ) + { + if( a == b && b.isEmpty() ) + { + return false; + } + + return a.isEmpty() || b.isEmpty() || !Platform.itemComparisons().isSameItem( a, b ); + } + } + } diff --git a/src/main/java/appeng/parts/misc/PartStorageBus.java b/src/main/java/appeng/parts/misc/PartStorageBus.java index dc4ddb84..7992af4d 100644 --- a/src/main/java/appeng/parts/misc/PartStorageBus.java +++ b/src/main/java/appeng/parts/misc/PartStorageBus.java @@ -66,7 +66,6 @@ import appeng.api.storage.IStorageMonitorable; import appeng.api.storage.IStorageMonitorableAccessor; import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.data.IAEItemStack; -import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IItemList; import appeng.api.util.AECableType; import appeng.api.util.AEPartLocation; @@ -112,7 +111,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC private int priority = 0; private boolean cached = false; private ITickingMonitor monitor = null; - private MEInventoryHandler handler = null; + private MEInventoryHandler handler = null; private int handlerHash = 0; private boolean wasActive = false; private byte resetCacheLogic = 0; @@ -355,22 +354,18 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC final IMEInventory out = this.getInternalHandler(); - if( this.monitor != null ) + if( in != out ) { - this.monitor.onTick(); + IItemList after = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + if( out != null ) + { + after = out.getAvailableItems( after ); + } + Platform.postListChanges( before, after, this, this.mySrc ); } - - IItemList after = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); - if( out != null ) - { - after = out.getAvailableItems( after ); - } - - Platform.postListChanges( before, after, this, this.mySrc ); } - @SuppressWarnings( "unchecked" ) - private IMEInventory getInventoryWrapper( TileEntity target ) + private IMEInventory getInventoryWrapper( TileEntity target ) { EnumFacing targetSide = this.getSide().getFacing().getOpposite(); @@ -397,7 +392,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC IItemHandler handlerExt = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide ); if( handlerExt != null ) { - return new ItemHandlerAdapter( handlerExt ); + return new ItemHandlerAdapter( handlerExt, this ); } return null; @@ -428,7 +423,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC return 0; } - public MEInventoryHandler getInternalHandler() + public MEInventoryHandler getInternalHandler() { if( this.cached ) { @@ -452,7 +447,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC this.monitor = null; if( target != null ) { - IMEInventory inv = this.getInventoryWrapper( target ); + IMEInventory inv = this.getInventoryWrapper( target ); if( inv instanceof MEMonitorIInventory ) { @@ -470,7 +465,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC { this.checkInterfaceVsStorageBus( target, this.getSide().getOpposite() ); - this.handler = new MEInventoryHandler( inv, AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); + this.handler = new MEInventoryHandler( inv, AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); this.handler.setBaseAccess( (AccessRestriction) this.getConfigManager().getSetting( Settings.ACCESS ) ); this.handler.setWhitelist( this.getInstalledUpgrades( Upgrades.INVERTER ) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST ); @@ -491,16 +486,17 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) { this.handler - .setPartitionList( new FuzzyPriorityList( priorityList, (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ) ) ); + .setPartitionList( new FuzzyPriorityList( priorityList, (FuzzyMode) this.getConfigManager() + .getSetting( Settings.FUZZY_MODE ) ) ); } else { - this.handler.setPartitionList( new PrecisePriorityList( priorityList ) ); + this.handler.setPartitionList( new PrecisePriorityList( priorityList ) ); } if( inv instanceof IBaseMonitor ) { - ( (IBaseMonitor) inv ).addListener( this, this.handler ); + ( (IBaseMonitor) inv ).addListener( this, this.handler ); } } } @@ -570,7 +566,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC { if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) { - final IMEInventoryHandler out = this.getProxy().isActive() ? this.getInternalHandler() : null; + final IMEInventoryHandler out = this.getProxy().isActive() ? this.getInternalHandler() : null; if( out != null ) { return Collections.singletonList( out );