From 979c3788f1f4dfdfb65e7cf648343189ff68df7d Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:03:49 +0500 Subject: [PATCH] Prune world gen tasks above limit in multiplayer --- .../GeneratedFullDataSourceProvider.java | 23 ++++++-- .../RemoteFullDataSourceProvider.java | 3 ++ .../AbstractFullDataNetworkRequestQueue.java | 15 ++---- .../server/FullDataSourceRequestHandler.java | 4 +- .../core/render/LodRenderSection.java | 53 +++++++++---------- 5 files changed, 53 insertions(+), 45 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 97a4e0e79..f57f96b5b 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 @@ -45,6 +45,7 @@ import java.awt.*; import java.io.File; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.IntStream; @@ -174,7 +175,8 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im } @Override - public boolean canQueueRetrieval() + public boolean canQueueRetrieval() { return this.canQueueRetrieval(false); } + public boolean canQueueRetrieval(boolean pruneWaitingTasksAboveLimit) { if (!super.canQueueRetrieval()) { @@ -220,9 +222,22 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im return false; } + int availableTaskSlots = maxQueueCount - worldGenQueue.getWaitingTaskCount(); + if (availableTaskSlots <= 0) + { + if (pruneWaitingTasksAboveLimit) + { + AtomicInteger tasksToCancel = new AtomicInteger(-availableTaskSlots + 1); + worldGenQueue.removeRetrievalRequestIf(x -> tasksToCancel.getAndDecrement() > 0); + } + else + { + // don't queue additional world gen requests beyond the max allotted count + return false; + } + } - // don't queue additional world gen requests beyond the max allotted count - return worldGenQueue.getWaitingTaskCount() < maxQueueCount; + return true; } @Override @@ -238,7 +253,7 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im CompletableFuture worldGenFuture = worldGenQueue.submitRetrievalTask(genPos, (byte) (DhSectionPos.getDetailLevel(genPos) - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL), genTaskTracker); worldGenFuture.whenComplete((genTaskResult, ex) -> { - LOGGER.info("gen task complete ["+DhSectionPos.toString(genPos)+"]"); + //LOGGER.info("gen task complete ["+DhSectionPos.toString(genPos)+"]"); //this.onWorldGenTaskComplete(genTaskResult, ex); }); 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 1311e0fc0..82b08c54b 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 @@ -66,6 +66,9 @@ public class RemoteFullDataSourceProvider extends GeneratedFullDataSourceProvide // override methods // //==================// + @Override + public boolean canQueueRetrieval() { return this.canQueueRetrieval(true); } + @Override @Nullable public FullDataSourceV2 get(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 3f0196eef..df6dac86a 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 @@ -180,7 +180,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende { Map.Entry mapEntry = this.waitingTasksBySectionPos.entrySet().stream() .filter(task -> task.getValue().networkDataSourceFuture == null) - .min(Comparator.comparingInt(x -> posDistanceSquared(targetPos, x.getKey()))) + .min(Comparator.comparingInt(x -> DhSectionPos.getChebyshevSignedBlockDistance(x.getKey(), targetPos))) .orElse(null); if (mapEntry == null) @@ -310,7 +310,9 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende public void removeRetrievalRequestIf(DhSectionPos.ICancelablePrimitiveLongConsumer removeIf) { - for (Map.Entry mapEntry : this.waitingTasksBySectionPos.entrySet()) + for (Map.Entry mapEntry : (Iterable>) this.waitingTasksBySectionPos.entrySet().stream() + .sorted(Comparator.comparingInt((Map.Entry entry) -> DhSectionPos.getChebyshevSignedBlockDistance(entry.getKey(), Objects.requireNonNull(this.level.getTargetPosForGeneration()))).reversed()) + ::iterator) { long pos = mapEntry.getKey(); RequestQueueEntry entry = mapEntry.getValue(); @@ -401,15 +403,6 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende - //================// - // helper methods // - //================// - - protected static int posDistanceSquared(DhBlockPos2D targetPos, long pos) - { return (int) DhSectionPos.getCenterBlockPos(pos).distSquared(targetPos); } - - - //================// // helper classes // //================// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/FullDataSourceRequestHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/FullDataSourceRequestHandler.java index 35599c519..836c676ad 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/FullDataSourceRequestHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/FullDataSourceRequestHandler.java @@ -239,12 +239,12 @@ public class FullDataSourceRequestHandler } else if (requestGroup.isWorldGenTaskComplete()) { - LOGGER.info("sending - retry [" + DhSectionPos.toString(pos) + "]"); + //LOGGER.info("sending - retry [" + DhSectionPos.toString(pos) + "]"); this.tryFulfillDataSourceRequestGroup(requestGroup, pos); } else { - LOGGER.info("sending - queueing [" + DhSectionPos.toString(pos) + "]"); + //LOGGER.info("sending - queueing [" + DhSectionPos.toString(pos) + "]"); this.fullDataSourceProvider().queuePositionForRetrieval(pos); } }); 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 f58eb02c1..4bac8ddb0 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 @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core.render; +import com.google.common.base.Suppliers; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; @@ -43,6 +44,7 @@ import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import it.unimi.dsi.fastutil.longs.LongArrayList; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; import javax.annotation.WillNotClose; import java.awt.*; @@ -50,8 +52,10 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; /** * A render section represents an area that could be rendered. @@ -100,9 +104,9 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable /** Stored as a class variable so we can reuse it's result across multiple LOD loads if necessary */ private ReferencedRenderSourceFutureWrapper renderSourceLoadingRefFuture = null; - private boolean missingPositionsCalculated = false; /** should be an empty array if no positions need to be generated */ - private LongArrayList missingGenerationPos = null; + @Nullable + private Supplier missingGenerationPos; private boolean checkedIfFullDataSourceExists = false; private boolean fullDataSourceExists = false; @@ -429,7 +433,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable // full data retrieval (world gen) // //=================================// - public boolean isFullyGenerated() { return this.missingPositionsCalculated && this.missingGenerationPos.isEmpty(); } + public boolean isFullyGenerated() { return this.missingGenerationPos != null && this.missingGenerationPos.get().isEmpty(); } /** Returns true if an LOD exists, regardless of what data is in it */ public boolean getFullDataSourceExists() { @@ -452,42 +456,35 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable } } - public boolean missingPositionsCalculated() { return this.missingPositionsCalculated; } - public int ungeneratedPositionCount() { return (this.missingGenerationPos != null) ? this.missingGenerationPos.size() : 0; } + public boolean missingPositionsCalculated() { return this.missingGenerationPos != null; } + public int ungeneratedPositionCount() { return (this.missingGenerationPos != null) ? this.missingGenerationPos.get().size() : 0; } public void tryQueuingMissingLodRetrieval() { if (this.fullDataSourceProvider.canRetrieveMissingDataSources() && this.fullDataSourceProvider.canQueueRetrieval()) { // calculate the missing positions if not already done - if (!this.missingPositionsCalculated) + if (this.missingGenerationPos == null) { - this.missingGenerationPos = this.fullDataSourceProvider.getPositionsToRetrieve(this.pos); - if (this.missingGenerationPos != null) - { - this.missingPositionsCalculated = true; - } + //this.missingGenerationPos = Suppliers.memoize(() -> this.fullDataSourceProvider.getPositionsToRetrieve(this.pos)); + this.missingGenerationPos = Suppliers.memoizeWithExpiration(() -> this.fullDataSourceProvider.getPositionsToRetrieve(this.pos), 1, TimeUnit.MINUTES); } - // if the missing positions were found, queue them - if (this.missingGenerationPos != null) + // queue from last to first to prevent shifting the array unnecessarily + for (int i = this.missingGenerationPos.get().size() - 1; i >= 0; i--) { - // queue from last to first to prevent shifting the array unnecessarily - for (int i = this.missingGenerationPos.size() - 1; i >= 0; i--) + if (!this.fullDataSourceProvider.canQueueRetrieval()) { - if (!this.fullDataSourceProvider.canQueueRetrieval()) - { - // the data source provider isn't accepting any more jobs - break; - } - - long pos = this.missingGenerationPos.removeLong(i); - boolean positionQueued = (this.fullDataSourceProvider.queuePositionForRetrieval(pos) != null); - if (!positionQueued) - { - // shouldn't normally happen, but just in case - this.missingGenerationPos.add(pos); - } + // the data source provider isn't accepting any more jobs + break; + } + + long pos = this.missingGenerationPos.get().removeLong(i); + boolean positionQueued = (this.fullDataSourceProvider.queuePositionForRetrieval(pos) != null); + if (!positionQueued) + { + // shouldn't normally happen, but just in case + this.missingGenerationPos.get().add(pos); } } }