From c7f8f4249ecbc32d5c2e4abd93601e3b69b23b59 Mon Sep 17 00:00:00 2001 From: talchas Date: Mon, 9 Dec 2019 22:39:38 -0800 Subject: [PATCH 1/3] Avoid quadratic behavior from rebuilding the entire crafting cache for each interface visited. Instead rebuild it at most once per tick, like cpu clusters. This is particularly important when channels are disabled, since in that case even adding a cable visits every grid node. --- .../java/appeng/me/cache/CraftingGridCache.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/appeng/me/cache/CraftingGridCache.java b/src/main/java/appeng/me/cache/CraftingGridCache.java index 7bd105ade..1ec8cbc39 100644 --- a/src/main/java/appeng/me/cache/CraftingGridCache.java +++ b/src/main/java/appeng/me/cache/CraftingGridCache.java @@ -114,6 +114,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper private IStorageGrid storageGrid; private IEnergyGrid energyGrid; private boolean updateList = false; + private boolean updatePatterns = false; public CraftingGridCache( final IGrid grid ) { @@ -138,6 +139,12 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper this.updateCPUClusters(); } + if( this.updatePatterns ) + { + this.updatePatterns = false; + this.updatePatterns(); + } + final Iterator craftingLinkIterator = this.craftingLinks.values().iterator(); while( craftingLinkIterator.hasNext() ) { @@ -185,7 +192,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper if( machine instanceof ICraftingProvider ) { this.craftingProviders.remove( machine ); - this.updatePatterns(); + this.updatePatterns = true; } } @@ -219,7 +226,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper if( machine instanceof ICraftingProvider ) { this.craftingProviders.add( (ICraftingProvider) machine ); - this.updatePatterns(); + this.updatePatterns = true; } } @@ -337,7 +344,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper @MENetworkEventSubscribe public void updateCPUClusters( final MENetworkCraftingPatternChange c ) { - this.updatePatterns(); + this.updatePatterns = true; } @Override From dfe5b82bda78cfab0c52850fca98105c3958615e Mon Sep 17 00:00:00 2001 From: talchas Date: Mon, 9 Dec 2019 22:39:38 -0800 Subject: [PATCH 2/3] Safer implementation of CraftingGridCache updatePatterns coalescing --- src/main/java/appeng/me/Grid.java | 6 ++- src/main/java/appeng/me/GridNode.java | 4 ++ .../appeng/me/cache/CraftingGridCache.java | 41 ++++++++++++++----- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/main/java/appeng/me/Grid.java b/src/main/java/appeng/me/Grid.java index daab0dbd5..4762d4937 100644 --- a/src/main/java/appeng/me/Grid.java +++ b/src/main/java/appeng/me/Grid.java @@ -39,6 +39,7 @@ import appeng.api.util.IReadOnlyCollection; import appeng.core.worlddata.WorldData; import appeng.hooks.TickHandler; import appeng.util.ReadOnlyCollection; +import appeng.me.cache.CraftingGridCache; public class Grid implements IGrid @@ -219,7 +220,10 @@ public class Grid implements IGrid @Override public MENetworkEvent postEvent( final MENetworkEvent ev ) { - return this.eventBus.postEvent( this, ev ); + CraftingGridCache.pauseRebuilds(); + final MENetworkEvent ret = this.eventBus.postEvent( this, ev ); + CraftingGridCache.unpauseRebuilds(); + return ret; } @Override diff --git a/src/main/java/appeng/me/GridNode.java b/src/main/java/appeng/me/GridNode.java index 6dc863a48..958685b8f 100644 --- a/src/main/java/appeng/me/GridNode.java +++ b/src/main/java/appeng/me/GridNode.java @@ -55,6 +55,7 @@ import appeng.api.util.IReadOnlyCollection; import appeng.core.AELog; import appeng.core.worlddata.WorldData; import appeng.hooks.TickHandler; +import appeng.me.cache.CraftingGridCache; import appeng.me.pathfinding.IPathItem; import appeng.util.IWorldCallable; import appeng.util.ReadOnlyCollection; @@ -164,6 +165,8 @@ public class GridNode implements IGridNode, IPathItem { final Object tracker = new Object(); + CraftingGridCache.pauseRebuilds(); + Deque nextRun = new ArrayDeque<>(); nextRun.add( this ); @@ -203,6 +206,7 @@ public class GridNode implements IGridNode, IPathItem } } } + CraftingGridCache.unpauseRebuilds(); } @Override diff --git a/src/main/java/appeng/me/cache/CraftingGridCache.java b/src/main/java/appeng/me/cache/CraftingGridCache.java index 1ec8cbc39..30ecf13b0 100644 --- a/src/main/java/appeng/me/cache/CraftingGridCache.java +++ b/src/main/java/appeng/me/cache/CraftingGridCache.java @@ -114,7 +114,8 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper private IStorageGrid storageGrid; private IEnergyGrid energyGrid; private boolean updateList = false; - private boolean updatePatterns = false; + private static int pauseRebuilds = 0; + private static Set rebuildNeeded = new HashSet<>(); public CraftingGridCache( final IGrid grid ) { @@ -139,12 +140,6 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper this.updateCPUClusters(); } - if( this.updatePatterns ) - { - this.updatePatterns = false; - this.updatePatterns(); - } - final Iterator craftingLinkIterator = this.craftingLinks.values().iterator(); while( craftingLinkIterator.hasNext() ) { @@ -192,7 +187,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper if( machine instanceof ICraftingProvider ) { this.craftingProviders.remove( machine ); - this.updatePatterns = true; + this.updatePatterns(); } } @@ -226,7 +221,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper if( machine instanceof ICraftingProvider ) { this.craftingProviders.add( (ICraftingProvider) machine ); - this.updatePatterns = true; + this.updatePatterns(); } } @@ -247,8 +242,34 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper // nothing! } + public static void pauseRebuilds() + { + pauseRebuilds++; + } + + public static void unpauseRebuilds() + { + pauseRebuilds--; + if (pauseRebuilds == 0 && rebuildNeeded.size() > 0) + { + ImmutableSet needed = ImmutableSet.copyOf(rebuildNeeded); + rebuildNeeded.clear(); + for ( CraftingGridCache cache: needed ) + { + cache.updatePatterns(); + } + } + } + private void updatePatterns() { + // coalesce change events during a grid traversal to a single rebuild + if (pauseRebuilds != 0) + { + rebuildNeeded.add(this); + return; + } + final Map> oldItems = this.craftableItems; // erase list. @@ -344,7 +365,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper @MENetworkEventSubscribe public void updateCPUClusters( final MENetworkCraftingPatternChange c ) { - this.updatePatterns = true; + this.updatePatterns(); } @Override From 5ac8db41e7618d65b6c87a12489be865b476c3f2 Mon Sep 17 00:00:00 2001 From: talchas Date: Thu, 6 Feb 2020 18:08:08 -0800 Subject: [PATCH 3/3] option for a blocking mode that actually works --- src/main/java/appeng/core/features/AEFeature.java | 1 + src/main/java/appeng/helpers/DualityInterface.java | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/appeng/core/features/AEFeature.java b/src/main/java/appeng/core/features/AEFeature.java index f7e1e707c..edfe86917 100644 --- a/src/main/java/appeng/core/features/AEFeature.java +++ b/src/main/java/appeng/core/features/AEFeature.java @@ -164,6 +164,7 @@ public enum AEFeature PATTERNS( "Patterns", Constants.CATEGORY_CRAFTING_FEATURES ), CRAFTING_CPU( "CraftingCPU", Constants.CATEGORY_CRAFTING_FEATURES ), CRAFTING_MANAGER_FALLBACK( "CraftingManagerFallback", Constants.CATEGORY_CRAFTING_FEATURES, "Use CraftingManager to find an alternative recipe, after a pattern rejected an ingredient. Should be enabled to avoid issues, but can have a minor performance impact." ), + INSANE_BLOCKING_MODE( "InsaneBlockingMode", Constants.CATEGORY_CRAFTING_FEATURES, "Use the default AE2 blocking mode that doesn't work on any machines" ), BASIC_CARDS( "BasicCards", Constants.CATEGORY_UPGRADES ), ADVANCED_CARDS( "AdvancedCards", Constants.CATEGORY_UPGRADES ), diff --git a/src/main/java/appeng/helpers/DualityInterface.java b/src/main/java/appeng/helpers/DualityInterface.java index 3c1791bca..d0fc09735 100644 --- a/src/main/java/appeng/helpers/DualityInterface.java +++ b/src/main/java/appeng/helpers/DualityInterface.java @@ -88,6 +88,8 @@ import appeng.api.util.AEPartLocation; import appeng.api.util.DimensionalCoord; import appeng.api.util.IConfigManager; import appeng.capabilities.Capabilities; +import appeng.core.AEConfig; +import appeng.core.features.AEFeature; import appeng.core.settings.TickRates; import appeng.me.GridAccessException; import appeng.me.helpers.AENetworkProxy; @@ -893,6 +895,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn }; } + private static boolean invIsBlocked(InventoryAdaptor inv) { + if (AEConfig.instance().isFeatureEnabled(AEFeature.INSANE_BLOCKING_MODE)) + return !inv.simulateRemove( 1, ItemStack.EMPTY, null ).isEmpty(); + else + return inv.containsItems(); + } + @Override public boolean pushPattern( final ICraftingPatternDetails patternDetails, final InventoryCrafting table ) { @@ -941,7 +950,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn { if( this.isBlocking() ) { - if( !ad.simulateRemove( 1, ItemStack.EMPTY, null ).isEmpty() ) + if( invIsBlocked(ad) ) { continue; } @@ -992,7 +1001,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() ); if( ad != null ) { - if( ad.simulateRemove( 1, ItemStack.EMPTY, null ).isEmpty() ) + if( !invIsBlocked(ad) ) { allAreBusy = false; break;