From 53011a13be6c3d4e913ff7d738be8c93c9effe80 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 25 Feb 2025 07:25:46 -0600 Subject: [PATCH] duct tape fix to reduce chance of LOD uploading requiring MC reboot --- .../core/render/LodQuadTree.java | 17 +++++++++++--- .../core/render/LodRenderSection.java | 22 +++++++------------ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index c65155b03..f9ce4deb6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -55,6 +55,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; /** @@ -110,6 +111,16 @@ public class LodQuadTree extends QuadTree implements IDebugRen // That way we don't have to worry about accidentally closing an in-use object. .build(); + /** + * Used to limit how many upload tasks are queued at once. + * If all the upload tasks are queued at once, they will start uploading nearest + * to the player, however if the player moves, that order is no longer valid and holes may appear + * as further sections are loaded before closer ones. + * Only queuing a few of the sections at a time solves this problem. + */ + public final AtomicInteger uploadTaskCountRef = new AtomicInteger(0); + + @Nullable public final BeaconRenderHandler beaconRenderHandler; @@ -226,7 +237,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen long rootPos = rootPosIterator.nextLong(); if (this.getNode(rootPos) == null) { - this.setValue(rootPos, new LodRenderSection(rootPos, this, this.level, this.fullDataSourceProvider, this.cachedRenderSourceByPos, this.renderLoadLockContainer)); + this.setValue(rootPos, new LodRenderSection(rootPos, this, this.level, this.fullDataSourceProvider, this.uploadTaskCountRef, this.cachedRenderSourceByPos, this.renderLoadLockContainer)); } QuadNode rootNode = this.getNode(rootPos); @@ -265,7 +276,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen // create the node if (quadNode == null && this.isSectionPosInBounds(sectionPos)) // the position bounds should only fail when at the edge of the user's render distance { - rootNode.setValue(sectionPos, new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider, this.cachedRenderSourceByPos, this.renderLoadLockContainer)); + rootNode.setValue(sectionPos, new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider, this.uploadTaskCountRef, this.cachedRenderSourceByPos, this.renderLoadLockContainer)); quadNode = rootNode.getNode(sectionPos); } if (quadNode == null) @@ -278,7 +289,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen LodRenderSection renderSection = quadNode.value; if (renderSection == null) { - renderSection = new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider, this.cachedRenderSourceByPos, this.renderLoadLockContainer); + renderSection = new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider, this.uploadTaskCountRef, this.cachedRenderSourceByPos, this.renderLoadLockContainer); quadNode.setValue(sectionPos, renderSection); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index e0cb0c5b1..f183c39ab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -68,15 +68,6 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); - /** - * Used to limit how many upload tasks are queued at once. - * If all the upload tasks are queued at once, they will start uploading nearest - * to the player, however if the player moves, that order is no longer valid and holes may appear - * as further sections are loaded before closer ones. - * Only queuing a few of the sections at a time solves this problem. - */ - public static final AtomicInteger GLOBAL_UPLOAD_TASKS_COUNT_REF = new AtomicInteger(0); - public final long pos; @@ -87,6 +78,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable private final LodQuadTree quadTree; private final KeyedLockContainer renderLoadLockContainer; private final Cache cachedRenderSourceByPos; + private final AtomicInteger uploadTaskCountRef; /** * contains the list of beacons currently being rendered in this section @@ -148,7 +140,8 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable public LodRenderSection( long pos, LodQuadTree quadTree, - IDhClientLevel level, FullDataSourceProviderV2 fullDataSourceProvider, + IDhClientLevel level, FullDataSourceProviderV2 fullDataSourceProvider, + AtomicInteger uploadTaskCountRef, Cache cachedRenderSourceByPos, KeyedLockContainer renderLoadLockContainer) { this.pos = pos; @@ -157,6 +150,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable this.renderLoadLockContainer = renderLoadLockContainer; this.level = level; this.fullDataSourceProvider = fullDataSourceProvider; + this.uploadTaskCountRef = uploadTaskCountRef; this.beaconRenderHandler = this.quadTree.beaconRenderHandler; this.beaconBeamRepo = this.level.getBeaconBeamRepo(); @@ -196,20 +190,20 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable // this means the closer (higher priority) tasks will load first. // This also prevents issues where the nearby tasks are canceled due to // LOD detail level changing, and having holes in the world - if (GLOBAL_UPLOAD_TASKS_COUNT_REF.getAndIncrement() > executor.getPoolSize()) + if (this.uploadTaskCountRef.getAndIncrement() > executor.getPoolSize()) { - GLOBAL_UPLOAD_TASKS_COUNT_REF.decrementAndGet(); + this.uploadTaskCountRef.decrementAndGet(); return false; } try { CompletableFuture future = new CompletableFuture<>(); - this.getAndBuildRenderDataFuture = future; + this.getAndBuildRenderDataFuture = future; // TODO should use a setter/getter to guard against replacing an incomplete future future.handle((voidObj, throwable) -> { // this has to fire are the end of every added future, otherwise we'll lock up and nothing will load - GLOBAL_UPLOAD_TASKS_COUNT_REF.decrementAndGet(); // TODO there is an issue where this variable isn't decremented properly, preventing LODs from loading in, or loading much slower + this.uploadTaskCountRef.decrementAndGet(); // TODO there is an issue where this variable isn't decremented properly, preventing LODs from loading in, or loading much slower return null; });