start world gen refactoring
This commit is contained in:
+5
-5
@@ -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) ->
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+3
-4
@@ -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<WorldGenResult> queuePositionForRetrieval(Long genPos) { return null; }
|
||||
|
||||
|
||||
+36
-33
@@ -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<CompletableFuture<WorldGenResult>> 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<CompletableFuture<WorldGenResult>> 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
|
||||
|
||||
+8
-2
@@ -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<Void> startClosingAsync(boolean cancelCurrentGeneration, boolean alsoInterruptRunning)
|
||||
@Override
|
||||
public CompletableFuture<Void> startClosingAsync(boolean cancelCurrentGeneration, boolean alsoInterruptRunning)
|
||||
{
|
||||
LOGGER.info("Closing world gen queue");
|
||||
this.queueingThread.shutdownNow();
|
||||
|
||||
-1
@@ -31,7 +31,6 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public interface IWorldGenTaskTracker
|
||||
{
|
||||
@Nullable
|
||||
Consumer<FullDataSourceV2> getDataSourceConsumer();
|
||||
|
||||
CompletableFuture<Boolean> shouldGenerateSplitChild(long pos);
|
||||
|
||||
+24
-33
@@ -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<ERequestResult> submitRequest(long sectionPos, Consumer<FullDataSourceV2> dataSourceConsumer)
|
||||
{ return this.submitRequest(sectionPos, null, dataSourceConsumer); }
|
||||
public CompletableFuture<ERequestResult> submitRequest(long sectionPos, @Nullable Long clientTimestamp, Consumer<FullDataSourceV2> 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<FullDataSourceResponseMessage> dataSourceFuture = this.networkState.getSession().sendRequest(
|
||||
CompletableFuture<FullDataSourceResponseMessage> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<LodRenderSection> implements IDebugRen
|
||||
* This is a {@link ConcurrentLinkedQueue} because new sections can be added to this list via the world generator threads.
|
||||
*/
|
||||
private final ConcurrentLinkedQueue<Long> 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<LodRenderSection> implements IDebugRen
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region constructor
|
||||
|
||||
public LodQuadTree(
|
||||
IDhClientLevel level, int viewDiameterInBlocks,
|
||||
@@ -128,11 +126,14 @@ public class LodQuadTree extends QuadTree<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> implements IDebugRen
|
||||
}
|
||||
|
||||
QuadNode<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> implements IDebugRen
|
||||
}
|
||||
}
|
||||
|
||||
//endregion external render requests
|
||||
|
||||
|
||||
|
||||
//=================================//
|
||||
// full data retrieval (world gen) //
|
||||
//=================================//
|
||||
//region world gen
|
||||
|
||||
private void queueFullDataRetrievalTasks(DhBlockPos2D playerPos, HashSet<LodRenderSection> nodesNeedingRetrieval)
|
||||
{
|
||||
try
|
||||
{
|
||||
// sort the nodes from nearest to farthest
|
||||
ArrayList<LodRenderSection> nodeList = new ArrayList<>(nodesNeedingRetrieval);
|
||||
nodeList.sort((a, b) ->
|
||||
ArrayList<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> implements IDebugRen
|
||||
}
|
||||
}
|
||||
|
||||
//endregion world gen
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// debugging //
|
||||
//===========//
|
||||
//region debugging
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer debugRenderer)
|
||||
@@ -739,11 +755,14 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
}
|
||||
}
|
||||
|
||||
//endregion debugging
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// base methods //
|
||||
//==============//
|
||||
//region base methods
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
@@ -783,6 +802,8 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
LOGGER.info("Finished shutting down LodQuadTree");
|
||||
}
|
||||
|
||||
//endregion base methods
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user