From 6d98c9cb84a88dc12767cc522c3cd202cd368d16 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 17 Dec 2025 22:39:23 -0600 Subject: [PATCH] start world gen refactoring --- .../GeneratedFullDataSourceProvider.java | 10 +- .../RemoteFullDataSourceProvider.java | 2 +- .../V2/FullDataSourceProviderV2.java | 7 +- .../generation/RemoteWorldRetrievalQueue.java | 69 +++++++------- .../core/generation/WorldGenerationQueue.java | 10 +- .../tasks/IWorldGenTaskTracker.java | 1 - .../AbstractFullDataNetworkRequestQueue.java | 57 +++++------- .../core/render/LodQuadTree.java | 93 ++++++++++++------- .../core/render/LodRenderSection.java | 2 +- 9 files changed, 135 insertions(+), 116 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java index cd71c9451..c6fc3785b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java @@ -207,10 +207,10 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im } @Override - public boolean canQueueRetrieval() { return this.canQueueRetrieval(false); } - public boolean canQueueRetrieval(boolean pruneWaitingTasksAboveLimit) + public boolean canQueueRetrievalNow() { return this.canQueueRetrievalNow(false); } + public boolean canQueueRetrievalNow(boolean pruneWaitingTasksAboveLimit) { - if (!super.canQueueRetrieval()) + if (!super.canQueueRetrievalNow()) { return false; } @@ -275,7 +275,7 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im if (pruneWaitingTasksAboveLimit) { AtomicInteger tasksToCancel = new AtomicInteger(-availableTaskSlots + 1); - worldGenQueue.removeRetrievalRequestIf(x -> tasksToCancel.getAndDecrement() > 0); + worldGenQueue.removeRetrievalRequestIf(taskPos -> tasksToCancel.getAndDecrement() > 0); } else { @@ -382,7 +382,7 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im LongArrayList generationList = new LongArrayList(); byte lowestGeneratorDetailLevel = (byte) Math.min( - worldGenQueue.lowestDataDetail() + DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL, + worldGenQueue.lowestDataDetail() + DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL, DhSectionPos.getDetailLevel(pos)); DhSectionPos.forEachChildAtDetailLevel(pos, lowestGeneratorDetailLevel, (genPos) -> diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataSourceProvider.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataSourceProvider.java index 80bae225c..93fa2711e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataSourceProvider.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataSourceProvider.java @@ -74,7 +74,7 @@ public class RemoteFullDataSourceProvider extends GeneratedFullDataSourceProvide //==================// @Override - public boolean canQueueRetrieval() { return this.canQueueRetrieval(true); } + public boolean canQueueRetrievalNow() { return this.canQueueRetrievalNow(true); } @Override @Nullable diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/V2/FullDataSourceProviderV2.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/V2/FullDataSourceProviderV2.java index c95e01c32..06bb0df00 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/V2/FullDataSourceProviderV2.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/V2/FullDataSourceProviderV2.java @@ -48,7 +48,6 @@ import java.sql.SQLException; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; /** * Handles reading/writing {@link FullDataSourceV2} @@ -360,7 +359,7 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable * to the beginning of your override. * Otherwise, parent retrieval limits will be ignored. */ - public boolean canQueueRetrieval() + public boolean canQueueRetrievalNow() { // Retrieval shouldn't happen while an unknown number of // legacy data sources are present. @@ -369,13 +368,13 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable } /** - * @return null if this provider can't generate any positions and + * @return null if this provider can't generate any positions or * an empty array if all positions were generated */ @Nullable public LongArrayList getPositionsToRetrieve(Long pos) { return null; } - /** @return true if the position was queued, false if not */ + /** @return null if the position couldn't be queued */ @Nullable public CompletableFuture queuePositionForRetrieval(Long genPos) { return null; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java index 1034b618b..49db5ae3b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java @@ -12,6 +12,7 @@ import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D; import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.WorldGenUtil; +import com.seibel.distanthorizons.core.util.objects.Pair; import com.seibel.distanthorizons.core.util.objects.RollingAverage; import com.seibel.distanthorizons.core.logging.DhLogger; @@ -59,41 +60,43 @@ public class RemoteWorldRetrievalQueue extends AbstractFullDataNetworkRequestQue long generationStartMsTime = System.currentTimeMillis(); - return super.submitRequest(sectionPos, fullDataSource -> { - Objects.requireNonNull(tracker.getDataSourceConsumer()).accept(fullDataSource); - fullDataSource.close(); - }) - .thenApply(requestResult -> + return super.submitRequest(sectionPos, /* client timestamp */null, + (fullDataSource) -> + { + tracker.getDataSourceConsumer().accept(fullDataSource); + fullDataSource.close(); // TODO can cause issues if the above is async + }) + .thenApply((ERequestResult requestResult) -> + { + long totalGenTimeInMs = System.currentTimeMillis() - generationStartMsTime; + + int chunkWidth = DhSectionPos.getChunkWidth(sectionPos); + int chunkCount = chunkWidth * chunkWidth; + double timePerChunk = (double) totalGenTimeInMs / (double) chunkCount; + this.rollingAverageChunkGenTimeInMs.add(timePerChunk); + + switch (requestResult) { - long totalGenTimeInMs = System.currentTimeMillis() - generationStartMsTime; - - int chunkWidth = DhSectionPos.getChunkWidth(sectionPos); - int chunkCount = chunkWidth * chunkWidth; - double timePerChunk = (double)totalGenTimeInMs / (double)chunkCount; - this.rollingAverageChunkGenTimeInMs.add(timePerChunk); - - switch (requestResult) - { - case SUCCEEDED: - return WorldGenResult.CreateSuccess(sectionPos); - case FAILED: - return WorldGenResult.CreateFail(); - case REQUIRES_SPLITTING: - List> childFutures = new ArrayList<>(4); - DhSectionPos.forEachChild(sectionPos, childPos -> { - tracker.shouldGenerateSplitChild(childPos).thenAccept(shouldGenerate -> { - if (shouldGenerate) - { - childFutures.add(this.submitRetrievalTask(childPos, requiredDataDetail, tracker)); - } - }); + case SUCCEEDED: + return WorldGenResult.CreateSuccess(sectionPos); + case FAILED: + return WorldGenResult.CreateFail(); + case REQUIRES_SPLITTING: + List> childFutures = new ArrayList<>(4); + DhSectionPos.forEachChild(sectionPos, childPos -> { + tracker.shouldGenerateSplitChild(childPos).thenAccept(shouldGenerate -> { + if (shouldGenerate) + { + childFutures.add(this.submitRetrievalTask(childPos, requiredDataDetail, tracker)); + } }); - return WorldGenResult.CreateSplit(childFutures); - } - - LodUtil.assertNotReach("Unexpected and unhandled request response result: ["+requestResult+"]"); - return WorldGenResult.CreateFail(); - }); + }); + return WorldGenResult.CreateSplit(childFutures); + } + + LodUtil.assertNotReach("Unexpected and unhandled request response result: [" + requestResult + "]"); + return WorldGenResult.CreateFail(); + }); } @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java index f1bc52d26..a11d81798 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java @@ -161,7 +161,12 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb { if (removeIf.accept(genPos)) { - this.waitingTasks.remove(genPos); + WorldGenTask removedTask = this.waitingTasks.remove(genPos); + if (removedTask != null) + { + // cancel tasks so any waiting future steps can be triggered + removedTask.future.cancel(true); + } } }); } @@ -556,7 +561,8 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb // shutdown // //==========// - @Override public CompletableFuture startClosingAsync(boolean cancelCurrentGeneration, boolean alsoInterruptRunning) + @Override + public CompletableFuture startClosingAsync(boolean cancelCurrentGeneration, boolean alsoInterruptRunning) { LOGGER.info("Closing world gen queue"); this.queueingThread.shutdownNow(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/IWorldGenTaskTracker.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/IWorldGenTaskTracker.java index 1d8ec7f52..cf962e521 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/IWorldGenTaskTracker.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/IWorldGenTaskTracker.java @@ -31,7 +31,6 @@ import java.util.function.Consumer; */ public interface IWorldGenTaskTracker { - @Nullable Consumer getDataSourceConsumer(); CompletableFuture shouldGenerateSplitChild(long pos); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java index b9608e566..dc69d2627 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java @@ -33,7 +33,6 @@ import java.awt.*; import java.util.*; import java.util.List; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -119,8 +118,6 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende // request submitting // //====================// - public CompletableFuture submitRequest(long sectionPos, Consumer dataSourceConsumer) - { return this.submitRequest(sectionPos, null, dataSourceConsumer); } public CompletableFuture submitRequest(long sectionPos, @Nullable Long clientTimestamp, Consumer dataSourceConsumer) { if (this.succeededPositions.contains(sectionPos)) @@ -133,14 +130,15 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende return CompletableFuture.completedFuture(ERequestResult.REQUIRES_SPLITTING); } - AtomicBoolean added = new AtomicBoolean(false); RequestQueueEntry entry = this.waitingTasksBySectionPos.compute(sectionPos, (pos, existingQueueEntry) -> { + // ignore already queued tasks if (existingQueueEntry != null) { return existingQueueEntry; } + RequestQueueEntry newEntry = new RequestQueueEntry(dataSourceConsumer, clientTimestamp); newEntry.future.whenComplete((requestResult, throwable) -> { @@ -167,15 +165,9 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende } }); - added.set(true); return newEntry; }); - if (!added.get()) - { - return CompletableFuture.completedFuture(ERequestResult.FAILED); - } - return entry.future; } @@ -221,31 +213,31 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende } long sectionPos = mapEntry.getKey(); - RequestQueueEntry entry = mapEntry.getValue(); + RequestQueueEntry requestEntry = mapEntry.getValue(); if (!this.isSectionAllowedToGenerate(sectionPos, targetPos)) { - entry.future.cancel(false); + requestEntry.future.cancel(false); this.pendingTasksSemaphore.release(); return; } - if (!this.onBeforeRequest(sectionPos, entry.future)) + if (!this.onBeforeRequest(sectionPos, requestEntry.future)) { this.pendingTasksSemaphore.release(); return; } - Long offsetEntryTimestamp = entry.updateTimestamp != null - ? entry.updateTimestamp + this.networkState.getServerTimeOffset() + Long offsetEntryTimestamp = requestEntry.updateTimestamp != null + ? requestEntry.updateTimestamp + this.networkState.getServerTimeOffset() : null; - CompletableFuture dataSourceFuture = this.networkState.getSession().sendRequest( + CompletableFuture dataSourceNetworkFuture = this.networkState.getSession().sendRequest( new FullDataSourceRequestMessage(this.level.getLevelWrapper(), sectionPos, offsetEntryTimestamp), FullDataSourceResponseMessage.class ); - entry.networkDataSourceFuture = dataSourceFuture; - dataSourceFuture.handle((response, throwable) -> + requestEntry.networkDataSourceFuture = dataSourceNetworkFuture; + dataSourceNetworkFuture.handle((response, throwable) -> { this.pendingTasksSemaphore.release(); @@ -265,6 +257,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende dataSourceDto.applyToChildren = DhSectionPos.getDetailLevel(dataSourceDto.pos) > DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL; dataSourceDto.applyToParent = DhSectionPos.getDetailLevel(dataSourceDto.pos) < DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL + 12; + // TODO what thread is this currently running on? Does saving need to be run async? AbstractExecutorService executor = ThreadPoolUtil.getNetworkCompressionExecutor(); if (executor == null) { @@ -280,7 +273,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende this.level.updateBeaconBeamsForSectionPos(dataSourceDto.pos, response.payload.beaconBeams); FullDataSourceV2 fullDataSource = dataSourceDto.createDataSource(this.level.getLevelWrapper(), null); - entry.dataSourceConsumer.accept(fullDataSource); + requestEntry.dataSourceConsumer.accept(fullDataSource); } catch (Exception e) { @@ -299,16 +292,16 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende } catch (SectionRequiresSplittingException ignored) { - return entry.future.complete(ERequestResult.REQUIRES_SPLITTING); + return requestEntry.future.complete(ERequestResult.REQUIRES_SPLITTING); } catch (SessionClosedException | CancellationException ignored) { - return entry.future.cancel(false); + return requestEntry.future.cancel(false); } catch (RequestRejectedException e) { LOGGER.info("Request rejected by the server: " + e.getMessage()); - return entry.future.complete(ERequestResult.FAILED); + return requestEntry.future.complete(ERequestResult.FAILED); } catch (RateLimitedException e) { @@ -317,34 +310,34 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende // Skip all requests for 1 second this.rateLimiter.acquireAll(); - entry.networkDataSourceFuture = null; + requestEntry.networkDataSourceFuture = null; return null; } catch (RequestOutOfRangeException e) { LOGGER.debug("Out of range, re-queueing task [" + DhSectionPos.toString(sectionPos) + "]: " + e.getMessage()); - entry.networkDataSourceFuture = null; + requestEntry.networkDataSourceFuture = null; return null; } catch (Throwable e) { - entry.retryAttempts--; - LOGGER.error("Error while fetching full data source, attempts left: {} / {}", entry.retryAttempts, MAX_RETRY_ATTEMPTS, e); + requestEntry.retryAttempts--; + LOGGER.error("Unexpected error ["+e.getMessage()+"] while fetching full data source, attempts left: ["+requestEntry.retryAttempts+"] / ["+MAX_RETRY_ATTEMPTS+"]", e); // Retry logic - if (entry.retryAttempts > 0) + if (requestEntry.retryAttempts > 0) { - entry.networkDataSourceFuture = null; + requestEntry.networkDataSourceFuture = null; return null; } else { - return entry.future.complete(ERequestResult.FAILED); + return requestEntry.future.complete(ERequestResult.FAILED); } } - return entry.future.complete(ERequestResult.SUCCEEDED); + return requestEntry.future.complete(ERequestResult.SUCCEEDED); }); } @@ -366,13 +359,11 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende if (removeIf.accept(pos)) { - LOGGER.debug("Removing request [" + mapEntry.getKey() + "]..."); - - entry.future.cancel(false); if (entry.networkDataSourceFuture != null) { entry.networkDataSourceFuture.cancel(false); } + entry.future.cancel(false); } } } 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 fbd01d09e..00469c452 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 @@ -20,7 +20,6 @@ package com.seibel.distanthorizons.core.render; import com.seibel.distanthorizons.core.config.Config; -import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer; import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataSourceProviderV2; @@ -34,7 +33,6 @@ import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable; import com.seibel.distanthorizons.core.render.renderer.generic.BeaconRenderHandler; import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer; import com.seibel.distanthorizons.core.util.LodUtil; -import com.seibel.distanthorizons.core.util.PerfRecorder; import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode; import com.seibel.distanthorizons.core.util.objects.quadTree.QuadTree; @@ -46,7 +44,6 @@ import org.jetbrains.annotations.Nullable; import javax.annotation.WillNotClose; import java.awt.*; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; @@ -73,7 +70,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen * This is a {@link ConcurrentLinkedQueue} because new sections can be added to this list via the world generator threads. */ private final ConcurrentLinkedQueue sectionsToReload = new ConcurrentLinkedQueue<>(); - private final IDhClientLevel level; //FIXME: Proper hierarchy to remove this reference! + private final IDhClientLevel level; private final ReentrantLock treeReadWriteLock = new ReentrantLock(); private final AtomicBoolean fullDataRetrievalQueueRunning = new AtomicBoolean(false); @@ -106,9 +103,10 @@ public class LodQuadTree extends QuadTree implements IDebugRen - //==============// - // constructors // - //==============// + //=============// + // constructor // + //=============// + //region constructor public LodQuadTree( IDhClientLevel level, int viewDiameterInBlocks, @@ -128,11 +126,14 @@ public class LodQuadTree extends QuadTree implements IDebugRen } + //endregion constructor + //=============// // tick update // //=============// + //region tick update /** * This function updates the quadTree based on the playerPos and the current game configs (static and global) @@ -143,19 +144,18 @@ public class LodQuadTree extends QuadTree implements IDebugRen { if (this.level == null) { - // the level hasn't finished loading yet - // TODO sometimes null pointers still happen, when logging back into a world (maybe the old level isn't null but isn't valid either?) + // the quad tree was created before a level reference was created return; } - // this shouldn't be updated while the tree is being iterated through - this.updateDetailLevelVariables(); - // don't traverse the tree if it is being modified if (this.treeReadWriteLock.tryLock()) { + // this shouldn't be updated while the tree is being iterated through + this.updateDetailLevelVariables(); + try { // recenter if necessary, removing out of bounds sections @@ -210,6 +210,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen } QuadNode rootNode = this.getNode(rootPos); + LodUtil.assertTrue(rootNode != null, "All root nodes should have been created by this point."); this.recursivelyUpdateRenderSectionNode(playerPos, rootNode, rootNode, rootNode.sectionPos, false, nodesNeedingRetrieval, nodesNeedingLoading); } @@ -217,7 +218,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen // queue full data retrieval (world gen) requests if needed if (nodesNeedingRetrieval.size() != 0 && !this.fullDataRetrievalQueueRunning.get() - && this.fullDataSourceProvider.canQueueRetrieval()) + && this.fullDataSourceProvider.canQueueRetrievalNow()) { this.fullDataRetrievalQueueRunning.set(true); FULL_DATA_RETRIEVAL_QUEUE_THREAD.execute(() -> this.queueFullDataRetrievalTasks(playerPos, nodesNeedingRetrieval)); @@ -368,13 +369,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen // prepare this section for rendering if (!renderSection.gpuUploadInProgress() - && renderSection.bufferContainer == null - // TODO this is commented out since some users reported LODs refusing to - // load at their expected higher-detail levels - // this check is specifically for N-sized world generators where the higher quality - // data source may not exist yet, this is done to prevent holes while waiting for said generator - //&& renderSection.getFullDataSourceExists() - ) + && renderSection.bufferContainer == null) { nodesNeedingLoading.add(renderSection); } @@ -453,9 +448,6 @@ public class LodQuadTree extends QuadTree implements IDebugRen LodRenderSection renderSection = this.getValue(pos); if (renderSection != null) { - // this data source may now exist - renderSection.updateFullDataSourceExists(); - if (renderSection.canRender()) { if (renderSection.gpuUploadInProgress() @@ -495,11 +487,14 @@ public class LodQuadTree extends QuadTree implements IDebugRen } } + //endregion tick update + //====================// // detail level logic // //====================// + //region detail level logic /** * This method will compute the detail level based on player position and section pos @@ -553,11 +548,14 @@ public class LodQuadTree extends QuadTree implements IDebugRen this.minRootRenderDetailLevel = (byte) Math.max(minSectionDetailLevel, this.maxLeafRenderDetailLevel); // respect the user's selected max resolution if it is lower detail (IE they want 2x2 block, but minSectionDetailLevel is specifically for 1x1 block render resolution) } + //endregion detail level logic - //=============// - // render data // - //=============// + + //==========================// + // external render requests // + //==========================// + //region external render requests /** * Re-creates the color, render data. @@ -620,29 +618,38 @@ public class LodQuadTree extends QuadTree implements IDebugRen } } + //endregion external render requests + + //=================================// // full data retrieval (world gen) // //=================================// + //region world gen private void queueFullDataRetrievalTasks(DhBlockPos2D playerPos, HashSet nodesNeedingRetrieval) { try { // sort the nodes from nearest to farthest - ArrayList nodeList = new ArrayList<>(nodesNeedingRetrieval); - nodeList.sort((a, b) -> + ArrayList renderSectionList = new ArrayList<>(nodesNeedingRetrieval); + renderSectionList.sort((renderSectionA, renderSectionB) -> { - int aDist = DhSectionPos.getManhattanBlockDistance(a.pos, playerPos); - int bDist = DhSectionPos.getManhattanBlockDistance(b.pos, playerPos); + int aDist = DhSectionPos.getManhattanBlockDistance(renderSectionA.pos, playerPos); + int bDist = DhSectionPos.getManhattanBlockDistance(renderSectionB.pos, playerPos); return Integer.compare(aDist, bDist); }); - // add retrieval tasks to the queue - for (int i = 0; i < nodeList.size(); i++) + + + //==================================// + // add retrieval tasks to the queue // + //==================================// + + for (int i = 0; i < renderSectionList.size(); i++) { - LodRenderSection renderSection = nodeList.get(i); - if (!this.fullDataSourceProvider.canQueueRetrieval()) + LodRenderSection renderSection = renderSectionList.get(i); + if (!this.fullDataSourceProvider.canQueueRetrievalNow()) { break; } @@ -650,12 +657,18 @@ public class LodQuadTree extends QuadTree implements IDebugRen renderSection.tryQueuingMissingLodRetrieval(); } + + + //==========================// + // calc task count estimate // + //==========================// + // calculate an estimate for the max number of chunks for the queue int totalWorldGenChunkCount = 0; int totalWorldGenTaskCount = 0; - for (int i = 0; i < nodeList.size(); i++) + for (int i = 0; i < renderSectionList.size(); i++) { - LodRenderSection renderSection = nodeList.get(i); + LodRenderSection renderSection = renderSectionList.get(i); if (!renderSection.missingPositionsCalculated()) { // chunk count @@ -688,11 +701,14 @@ public class LodQuadTree extends QuadTree implements IDebugRen } } + //endregion world gen + //===========// // debugging // //===========// + //region debugging @Override public void debugRender(DebugRenderer debugRenderer) @@ -739,11 +755,14 @@ public class LodQuadTree extends QuadTree implements IDebugRen } } + //endregion debugging + //==============// // base methods // //==============// + //region base methods @Override public void close() @@ -783,6 +802,8 @@ public class LodQuadTree extends QuadTree implements IDebugRen LOGGER.info("Finished shutting down LodQuadTree"); } + //endregion base methods + } 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 2d5a9ccc0..5053a945d 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 @@ -42,7 +42,7 @@ import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.render.renderer.generic.BeaconRenderHandler; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; -import com.seibel.distanthorizons.core.util.WorldGenUtil; +import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;