From e1f51118cd222f9708de914dd57648b1305afc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 6 Feb 2022 20:48:08 +0100 Subject: [PATCH] Fixed chunk load/unload listeners only firing once. --- .../blockentity/BusCableBlockEntity.java | 8 +-- .../common/bus/BlockDeviceBusController.java | 8 +-- .../cil/oc2/common/util/ServerScheduler.java | 66 ++++++++++++------- 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java index 138704c2..efd83116 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java @@ -419,16 +419,16 @@ public final class BusCableBlockEntity extends ModBlockEntity { private void addListener() { if (level != null && !hasRegisteredListener) { - ServerScheduler.scheduleOnLoad(level, chunkPos, onChunkLoadedStateChanged); - ServerScheduler.scheduleOnUnload(level, chunkPos, onChunkLoadedStateChanged); + ServerScheduler.subscribeOnLoad(level, chunkPos, onChunkLoadedStateChanged); + ServerScheduler.subscribeOnUnload(level, chunkPos, onChunkLoadedStateChanged); } hasRegisteredListener = true; } private void removeListener() { if (level != null && hasRegisteredListener) { - ServerScheduler.cancelOnLoad(level, chunkPos, onChunkLoadedStateChanged); - ServerScheduler.cancelOnUnload(level, chunkPos, onChunkLoadedStateChanged); + ServerScheduler.unsubscribeOnLoad(level, chunkPos, onChunkLoadedStateChanged); + ServerScheduler.unsubscribeOnUnload(level, chunkPos, onChunkLoadedStateChanged); } hasRegisteredListener = false; } diff --git a/src/main/java/li/cil/oc2/common/bus/BlockDeviceBusController.java b/src/main/java/li/cil/oc2/common/bus/BlockDeviceBusController.java index 60c4d48d..9a6bfad4 100644 --- a/src/main/java/li/cil/oc2/common/bus/BlockDeviceBusController.java +++ b/src/main/java/li/cil/oc2/common/bus/BlockDeviceBusController.java @@ -117,8 +117,8 @@ public final class BlockDeviceBusController extends CommonDeviceBusController { private void addListeners(final Collection trackedChunks) { for (final ChunkLocation trackedChunk : trackedChunks) { trackedChunk.tryGetLevel().ifPresent(level -> { - ServerScheduler.scheduleOnLoad(level, trackedChunk.position(), onBusChunkLoadedStateChanged); - ServerScheduler.scheduleOnUnload(level, trackedChunk.position(), onBusChunkLoadedStateChanged); + ServerScheduler.subscribeOnLoad(level, trackedChunk.position(), onBusChunkLoadedStateChanged); + ServerScheduler.subscribeOnUnload(level, trackedChunk.position(), onBusChunkLoadedStateChanged); }); } } @@ -126,8 +126,8 @@ public final class BlockDeviceBusController extends CommonDeviceBusController { private void removeListeners(final Collection trackedChunks) { for (final ChunkLocation trackedChunk : trackedChunks) { trackedChunk.tryGetLevel().ifPresent(level -> { - ServerScheduler.cancelOnLoad(level, trackedChunk.position(), onBusChunkLoadedStateChanged); - ServerScheduler.cancelOnUnload(level, trackedChunk.position(), onBusChunkLoadedStateChanged); + ServerScheduler.unsubscribeOnLoad(level, trackedChunk.position(), onBusChunkLoadedStateChanged); + ServerScheduler.unsubscribeOnUnload(level, trackedChunk.position(), onBusChunkLoadedStateChanged); }); } } diff --git a/src/main/java/li/cil/oc2/common/util/ServerScheduler.java b/src/main/java/li/cil/oc2/common/util/ServerScheduler.java index d0272e8a..1761c81f 100644 --- a/src/main/java/li/cil/oc2/common/util/ServerScheduler.java +++ b/src/main/java/li/cil/oc2/common/util/ServerScheduler.java @@ -18,8 +18,8 @@ public final class ServerScheduler { private static final TickScheduler globalTickScheduler = new TickScheduler(); private static final WeakHashMap levelTickSchedulers = new WeakHashMap<>(); private static final WeakHashMap levelUnloadSchedulers = new WeakHashMap<>(); - private static final WeakHashMap> chunkLoadSchedulers = new WeakHashMap<>(); - private static final WeakHashMap> chunkUnloadSchedulers = new WeakHashMap<>(); + private static final WeakHashMap> chunkLoadSchedulers = new WeakHashMap<>(); + private static final WeakHashMap> chunkUnloadSchedulers = new WeakHashMap<>(); /////////////////////////////////////////////////////////////////// @@ -61,49 +61,49 @@ public final class ServerScheduler { } } - public static void scheduleOnLoad(final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { + public static void subscribeOnLoad(final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { chunkLoadSchedulers .computeIfAbsent(level, unused -> new HashMap<>()) - .computeIfAbsent(chunkPos, unused -> new SimpleScheduler()) + .computeIfAbsent(chunkPos, unused -> new ListenerCollection()) .add(listener); } - public static void cancelOnLoad(@Nullable final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { + public static void unsubscribeOnLoad(@Nullable final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { if (level == null) { return; } - final HashMap chunkMap = chunkLoadSchedulers.get(level); + final HashMap chunkMap = chunkLoadSchedulers.get(level); if (chunkMap == null) { return; } - final SimpleScheduler scheduler = chunkMap.get(chunkPos); - if (scheduler != null) { - scheduler.remove(listener); + final ListenerCollection listeners = chunkMap.get(chunkPos); + if (listeners != null) { + listeners.remove(listener); } } - public static void scheduleOnUnload(final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { + public static void subscribeOnUnload(final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { chunkUnloadSchedulers .computeIfAbsent(level, unused -> new HashMap<>()) - .computeIfAbsent(chunkPos, unused -> new SimpleScheduler()) + .computeIfAbsent(chunkPos, unused -> new ListenerCollection()) .add(listener); } - public static void cancelOnUnload(@Nullable final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { + public static void unsubscribeOnUnload(@Nullable final LevelAccessor level, final ChunkPos chunkPos, final Runnable listener) { if (level == null) { return; } - final HashMap chunkMap = chunkUnloadSchedulers.get(level); + final HashMap chunkMap = chunkUnloadSchedulers.get(level); if (chunkMap == null) { return; } - final SimpleScheduler scheduler = chunkMap.get(chunkPos); - if (scheduler != null) { - scheduler.remove(listener); + final ListenerCollection listeners = chunkMap.get(chunkPos); + if (listeners != null) { + listeners.remove(listener); } } @@ -135,27 +135,27 @@ public final class ServerScheduler { @SubscribeEvent public static void handleChunkLoad(final ChunkEvent.Load event) { - final HashMap chunkMap = chunkLoadSchedulers.get(event.getWorld()); + final HashMap chunkMap = chunkLoadSchedulers.get(event.getWorld()); if (chunkMap == null) { return; } - final SimpleScheduler scheduler = chunkMap.get(event.getChunk().getPos()); - if (scheduler != null) { - scheduler.run(); + final ListenerCollection listeners = chunkMap.get(event.getChunk().getPos()); + if (listeners != null) { + listeners.run(); } } @SubscribeEvent public static void handleChunkUnload(final ChunkEvent.Unload event) { - final HashMap chunkMap = chunkUnloadSchedulers.get(event.getWorld()); + final HashMap chunkMap = chunkUnloadSchedulers.get(event.getWorld()); if (chunkMap == null) { return; } - final SimpleScheduler scheduler = chunkMap.get(event.getChunk().getPos()); - if (scheduler != null) { - scheduler.run(); + final ListenerCollection listeners = chunkMap.get(event.getChunk().getPos()); + if (listeners != null) { + listeners.run(); } } @@ -235,4 +235,22 @@ public final class ServerScheduler { listeners.clear(); } } + + private static final class ListenerCollection { + private final Set listeners = Collections.newSetFromMap(new WeakHashMap<>()); + + public void add(final Runnable listener) { + listeners.add(listener); + } + + public void remove(final Runnable listener) { + listeners.remove(listener); + } + + public void run() { + for (final Runnable runnable : listeners) { + runnable.run(); + } + } + } }