From 08d0ef617f810abd70583e9db3a2d549830cdde8 Mon Sep 17 00:00:00 2001 From: Raven Szewczyk Date: Thu, 1 Sep 2022 11:58:42 +0100 Subject: [PATCH] Fix potential missed updates in the level emitter. (#173) * Fix potential missed updates in the level emitter. This makes the emitter tickable, but sleeping most of the time so the performance impact should be minimal. If an update is ignored due to the configured delay, ticking is scheduled to make sure that the update happens if no further network updates happen until the next delay period. * Attempt #2: Delay the first tick of the level emitter on load * Revert "NetworkMonitor optimization - do not rebuild cache more than once per tick" This reverts commit 09b253109c87aa8dc56ad8d36fc8f63c493e6db7. * spaces->tabs to match existing code --- .../java/appeng/me/cache/NetworkMonitor.java | 5 +- .../parts/automation/PartLevelEmitter.java | 64 +++++++++++++++++-- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/main/java/appeng/me/cache/NetworkMonitor.java b/src/main/java/appeng/me/cache/NetworkMonitor.java index e5bc9e42192..6b33d5e9ade 100644 --- a/src/main/java/appeng/me/cache/NetworkMonitor.java +++ b/src/main/java/appeng/me/cache/NetworkMonitor.java @@ -56,7 +56,6 @@ public class NetworkMonitor> implements IMEMonitor private boolean sendEvent = false; private boolean hasChanged = false; - private boolean ticked = true; @Nonnegative private int localDepthSemaphore = 0; @@ -134,10 +133,9 @@ public int getSlot() @Override public IItemList getStorageList() { - if( hasChanged && ticked ) + if( this.hasChanged ) { this.hasChanged = false; - ticked = false; this.cachedList.resetStatus(); return this.getAvailableItems( this.cachedList ); } @@ -331,7 +329,6 @@ void forceUpdate() void onTick() { - ticked = true; if( this.sendEvent ) { this.sendEvent = false; diff --git a/src/main/java/appeng/parts/automation/PartLevelEmitter.java b/src/main/java/appeng/parts/automation/PartLevelEmitter.java index 846f84816b9..9192723887c 100644 --- a/src/main/java/appeng/parts/automation/PartLevelEmitter.java +++ b/src/main/java/appeng/parts/automation/PartLevelEmitter.java @@ -20,6 +20,7 @@ import appeng.api.config.*; +import appeng.api.networking.IGridNode; import appeng.api.networking.crafting.*; import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.energy.IEnergyWatcher; @@ -32,6 +33,9 @@ import appeng.api.networking.storage.IBaseMonitor; import appeng.api.networking.storage.IStackWatcher; import appeng.api.networking.storage.IStackWatcherHost; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; import appeng.api.parts.IPartCollisionHelper; import appeng.api.parts.IPartRenderHelper; import appeng.api.storage.IMEMonitor; @@ -44,6 +48,7 @@ import appeng.api.util.IConfigManager; import appeng.client.texture.CableBusTextures; import appeng.core.AEConfig; +import appeng.core.AELog; import appeng.core.sync.GuiBridge; import appeng.helpers.Reflected; import appeng.me.GridAccessException; @@ -71,7 +76,7 @@ public class PartLevelEmitter extends PartUpgradeable - implements IEnergyWatcherHost, IStackWatcherHost, ICraftingWatcherHost, IMEMonitorHandlerReceiver, ICraftingProvider + implements IEnergyWatcherHost, IStackWatcherHost, ICraftingWatcherHost, IMEMonitorHandlerReceiver, ICraftingProvider, IGridTickable { private static final int FLAG_ON = 8; @@ -91,6 +96,7 @@ public class PartLevelEmitter extends PartUpgradeable private double centerZ; private int lastWorkingTick = 0; + private boolean delayedUpdatesQueued = false; @Reflected public PartLevelEmitter( final ItemStack is ) @@ -101,6 +107,10 @@ public PartLevelEmitter( final ItemStack is ) this.getConfigManager().registerSetting( Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL ); this.getConfigManager().registerSetting( Settings.LEVEL_TYPE, LevelType.ITEM_LEVEL ); this.getConfigManager().registerSetting( Settings.CRAFT_VIA_REDSTONE, YesNo.NO ); + + // Workaround the emitter randomly breaking on world load + delayedUpdatesQueued = true; + lastWorkingTick = MinecraftServer.getServer().getTickCounter(); } public long getReportingValue() @@ -371,13 +381,57 @@ public boolean isValid( final Object effectiveGrid ) } @Override - public void postChange( final IBaseMonitor monitor, final Iterable change, final BaseActionSource actionSource ) + public TickingRequest getTickingRequest( IGridNode node ) + { + return new TickingRequest( AEConfig.instance.levelEmitterDelay / 2, AEConfig.instance.levelEmitterDelay, !delayedUpdatesQueued, true ); + } + + private boolean canDoWork() { int currentTick = MinecraftServer.getServer().getTickCounter(); - if (currentTick - lastWorkingTick > AEConfig.instance.levelEmitterDelay) + return ( currentTick - lastWorkingTick ) > AEConfig.instance.levelEmitterDelay; + } + + @Override + public TickRateModulation tickingRequest( IGridNode node, int TicksSinceLastCall ) + { + if( delayedUpdatesQueued && canDoWork() ) + { + delayedUpdatesQueued = false; + lastWorkingTick = MinecraftServer.getServer().getTickCounter(); + this.onListUpdate(); + } + return delayedUpdatesQueued ? TickRateModulation.IDLE : TickRateModulation.SLEEP; + } + + @Override + public void postChange( final IBaseMonitor monitor, final Iterable change, final BaseActionSource actionSource ) + { + if( canDoWork() ) { - this.updateReportingValue((IMEMonitor) monitor); - lastWorkingTick = currentTick; + if ( delayedUpdatesQueued ) + { + delayedUpdatesQueued = false; + try + { + this.getProxy().getTick().sleepDevice( this.getProxy().getNode() ); + } catch( GridAccessException e ) + { + AELog.error( e, "Couldn't put level emitter to sleep after cancelling delayed updates" ); + } + } + lastWorkingTick = MinecraftServer.getServer().getTickCounter(); + this.updateReportingValue( (IMEMonitor) monitor ); + } else if( !delayedUpdatesQueued ) + { + delayedUpdatesQueued = true; + try + { + this.getProxy().getTick().alertDevice( this.getProxy().getNode() ); + } catch( GridAccessException e ) + { + AELog.error( e, "Couldn't wake up level emitter for delayed updates" ); + } } }