duct tape fix to reduce chance of LOD uploading requiring MC reboot

This commit is contained in:
James Seibel
2025-02-25 07:25:46 -06:00
parent 69a4e6b27e
commit 53011a13be
2 changed files with 22 additions and 17 deletions
@@ -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<LodRenderSection> implements IDebugRen
// That way we don't have to worry about accidentally closing an in-use object.
.<Long, CachedColumnRenderSource>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<LodRenderSection> 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<LodRenderSection> rootNode = this.getNode(rootPos);
@@ -265,7 +276,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> 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<LodRenderSection> 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);
}
@@ -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<Long> renderLoadLockContainer;
private final Cache<Long, CachedColumnRenderSource> 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<Long, CachedColumnRenderSource> cachedRenderSourceByPos, KeyedLockContainer<Long> 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<Void> 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;
});