only run world gen for rendering levels
Also fix world gen progress getting stuck on a single level
This commit is contained in:
+1
-1
@@ -27,7 +27,7 @@ import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataSourceProvid
|
||||
import com.seibel.distanthorizons.core.util.delayedSaveCache.DelayedDataSourceSaveCache;
|
||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||
import com.seibel.distanthorizons.core.generation.IFullDataSourceRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.IFullDataSourceRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalResult;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.ERetrievalResultState;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
|
||||
+2
-2
@@ -22,10 +22,10 @@ package com.seibel.distanthorizons.core.file.fullDatafile;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.RemoteWorldRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalResult;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.level.LodRequestModule;
|
||||
import com.seibel.distanthorizons.core.generation.queues.LodRequestModule;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.ERetrievalResultState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
|
||||
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
package com.seibel.distanthorizons.core.generation.queues;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorProgressDisplayLocation;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.util.FormatUtil;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.RollingAverage;
|
||||
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* Handles the {@link IFullDataSourceRetrievalQueue} and any other necessary world gen information.
|
||||
*
|
||||
* @see LodRequestModule
|
||||
* @see IFullDataSourceRetrievalQueue
|
||||
*/
|
||||
public abstract class AbstractLodRequestState
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
/** static so we only send the disable message once per session */
|
||||
private static long firstProgressMessageSentMs = 0;
|
||||
|
||||
|
||||
|
||||
public final IDhLevel dhLevel;
|
||||
public final IFullDataSourceRetrievalQueue retrievalQueue;
|
||||
|
||||
private final ThreadPoolExecutor progressUpdaterThread = ThreadUtil.makeSingleDaemonThreadPool("World Gen Progress Updater");
|
||||
private boolean progressUpdateThreadRunning = false;
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// request queue and logging //
|
||||
//===========================//
|
||||
//region
|
||||
|
||||
public AbstractLodRequestState(IDhLevel dhLevel, IFullDataSourceRetrievalQueue retrievalQueue)
|
||||
{
|
||||
this.dhLevel = dhLevel;
|
||||
this.retrievalQueue = retrievalQueue;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// request queue and logging //
|
||||
//===========================//
|
||||
//region
|
||||
|
||||
/** @param targetPosForRequest the position that world generation should be centered around */
|
||||
public void startRequestQueueAndSetTargetPos(DhBlockPos2D targetPosForRequest)
|
||||
{
|
||||
this.retrievalQueue.startAndSetTargetPos(targetPosForRequest);
|
||||
this.startProgressUpdateThread();
|
||||
}
|
||||
private void startProgressUpdateThread()
|
||||
{
|
||||
// only start the thread once
|
||||
if (!this.progressUpdateThreadRunning)
|
||||
{
|
||||
this.progressUpdateThreadRunning = true;
|
||||
|
||||
progressUpdaterThread.execute(() ->
|
||||
{
|
||||
while (this.progressUpdateThreadRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.sendRetrievalProgress();
|
||||
|
||||
// sleep so we only see an update once in a while
|
||||
int sleepTimeInSec = Config.Common.WorldGenerator.generationProgressDisplayIntervalInSeconds.get();
|
||||
Thread.sleep(sleepTimeInSec * 1_000L);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected issue displaying chunk retrieval progress [" + e.getMessage() + "].", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
private void sendRetrievalProgress()
|
||||
{
|
||||
// format the remaining chunks
|
||||
int remainingChunkCount = this.retrievalQueue.getRetrievalEstimatedRemainingChunkCount();
|
||||
remainingChunkCount += this.retrievalQueue.getQueuedChunkCount();
|
||||
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
|
||||
|
||||
String message = "DH is generating chunks. ";
|
||||
if (this.dhLevel.getClass() == DhServerLevel.class)
|
||||
{
|
||||
// server levels can have multiple world generators running at once,
|
||||
// this helps us track of which queue is which
|
||||
message += "For " + this.dhLevel.getLevelWrapper().getDimensionName() + " ";
|
||||
}
|
||||
message += remainingChunkCountStr + " left.";
|
||||
|
||||
// show a message about how to disable progress logging if requested
|
||||
int msToShowDisableInstructions = Config.Common.WorldGenerator.generationProgressDisableMessageDisplayTimeInSeconds.get() * 1_000;
|
||||
if (msToShowDisableInstructions > 0)
|
||||
{
|
||||
long timeSinceFirstMessageInMs = (System.currentTimeMillis() - firstProgressMessageSentMs);
|
||||
// always show this message for the first tick
|
||||
if (firstProgressMessageSentMs == 0
|
||||
// show this message if there is still time
|
||||
|| timeSinceFirstMessageInMs < msToShowDisableInstructions)
|
||||
{
|
||||
// append to the current message
|
||||
message += " This message can be hidden in the DH config.";
|
||||
}
|
||||
}
|
||||
|
||||
// add the remaining time estimate if available
|
||||
double chunksPerSec = this.getEstimatedChunksPerSecond();
|
||||
if (chunksPerSec > 0)
|
||||
{
|
||||
long estimatedRemainingTime = (long) (remainingChunkCount / chunksPerSec);
|
||||
message += " ETA: " + FormatUtil.formatEta(Duration.ofSeconds(estimatedRemainingTime));
|
||||
|
||||
if (Config.Common.WorldGenerator.generationProgressIncludeChunksPerSecond.get())
|
||||
{
|
||||
message += " at " + F3Screen.NUMBER_FORMAT.format(chunksPerSec) + " chunks/sec";
|
||||
}
|
||||
}
|
||||
|
||||
// only log if there are chunks needing to be generated
|
||||
if (remainingChunkCount != 0)
|
||||
{
|
||||
// determine where to log
|
||||
EDhApiDistantGeneratorProgressDisplayLocation displayLocation = Config.Common.WorldGenerator.showGenerationProgress.get();
|
||||
if (displayLocation == EDhApiDistantGeneratorProgressDisplayLocation.OVERLAY)
|
||||
{
|
||||
ClientApi.INSTANCE.showOverlayMessageNextFrame(message);
|
||||
}
|
||||
else if (displayLocation == EDhApiDistantGeneratorProgressDisplayLocation.CHAT)
|
||||
{
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
else if (displayLocation == EDhApiDistantGeneratorProgressDisplayLocation.LOG)
|
||||
{
|
||||
LOGGER.info(message);
|
||||
}
|
||||
|
||||
|
||||
// mark when the first message was sent
|
||||
if (firstProgressMessageSentMs == 0)
|
||||
{
|
||||
firstProgressMessageSentMs = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return -1 if this method isn't supported or available */
|
||||
public double getEstimatedChunksPerSecond()
|
||||
{
|
||||
RollingAverage avg = this.retrievalQueue.getRollingAverageChunkGenTimeInMs();
|
||||
if (avg == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PriorityTaskPicker.Executor executor = ThreadPoolUtil.getWorldGenExecutor();
|
||||
int threadCount = 1;
|
||||
if (executor != null)
|
||||
{
|
||||
threadCount = executor.getPoolSize();
|
||||
}
|
||||
|
||||
// convert chunk generation time in milliseconds to chunks per second
|
||||
double chunksPerSecond = (1 / avg.getAverage()) * 1_000;
|
||||
// estimate the number of chunks that can be processed per second by all threads
|
||||
// Note: this is probably higher than the actual number, we might want to drop this by 1 or 2 to give a more realistic estimate
|
||||
chunksPerSecond = threadCount * chunksPerSecond;
|
||||
|
||||
return chunksPerSecond;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
public CompletableFuture<Void> closeAsync(boolean doInterrupt)
|
||||
{
|
||||
// this should stop the updater thread
|
||||
this.progressUpdateThreadRunning = false;
|
||||
|
||||
return this.retrievalQueue.startClosingAsync(true, doInterrupt)
|
||||
.exceptionally(e ->
|
||||
{
|
||||
LOGGER.error("Error during first stage of generation queue shutdown, Error: [" + e.getMessage() + "].", e);
|
||||
return null;
|
||||
}
|
||||
).thenRun(this.retrievalQueue::close)
|
||||
.exceptionally(e ->
|
||||
{
|
||||
LOGGER.error("Error during second stage of generation queue shutdown, Error: [" + e.getMessage() + "].", e);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+3
-1
@@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.generation;
|
||||
package com.seibel.distanthorizons.core.generation.queues;
|
||||
|
||||
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalResult;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
@@ -42,6 +42,8 @@ import java.util.concurrent.CompletableFuture;
|
||||
* Used by both world gen and server networking.
|
||||
*
|
||||
* @see LodQuadTree
|
||||
* @see AbstractLodRequestState
|
||||
* @see LodRequestModule
|
||||
*/
|
||||
public interface IFullDataSourceRetrievalQueue extends Closeable
|
||||
{
|
||||
+37
-176
@@ -17,39 +17,35 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.level;
|
||||
package com.seibel.distanthorizons.core.generation.queues;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorProgressDisplayLocation;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataSourceProvider;
|
||||
import com.seibel.distanthorizons.core.generation.IFullDataSourceRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.level.*;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.util.FormatUtil;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.RollingAverage;
|
||||
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.world.DhApiWorldProxy;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Handles both single-player/server-side world gen and client side LOD requests.
|
||||
*
|
||||
* @see AbstractLodRequestState
|
||||
* @see IFullDataSourceRetrievalQueue
|
||||
*/
|
||||
public class LodRequestModule implements Closeable
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
|
||||
private final IDhLevel level;
|
||||
private final GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener;
|
||||
private final ThreadPoolExecutor tickerThread;
|
||||
|
||||
@@ -63,6 +59,7 @@ public class LodRequestModule implements Closeable
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public LodRequestModule(
|
||||
IDhLevel level,
|
||||
@@ -71,20 +68,24 @@ public class LodRequestModule implements Closeable
|
||||
Supplier<? extends AbstractLodRequestState> worldGenStateSupplier
|
||||
)
|
||||
{
|
||||
this.level = level;
|
||||
this.onWorldGenCompleteListener = onWorldGenCompleteListener;
|
||||
this.dataSourceProvider = dataSourceProvider;
|
||||
this.worldGenStateSupplier = worldGenStateSupplier;
|
||||
|
||||
String levelId = level.getLevelWrapper().getDhIdentifier();
|
||||
String levelId = this.level.getLevelWrapper().getDhIdentifier();
|
||||
this.tickerThread = ThreadUtil.makeSingleDaemonThreadPool("Request Module Ticker ["+levelId+"]");
|
||||
this.tickerThread.execute(this::tickLoop);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// ticking //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
private void tickLoop()
|
||||
{
|
||||
@@ -101,9 +102,23 @@ public class LodRequestModule implements Closeable
|
||||
private void tick()
|
||||
{
|
||||
boolean shouldDoWorldGen = this.onWorldGenCompleteListener.shouldDoWorldGen();
|
||||
|
||||
// if the world is read only don't generate anything
|
||||
shouldDoWorldGen &= !DhApiWorldProxy.INSTANCE.getReadOnly();
|
||||
|
||||
// don't generate chunks for client levels that aren't being rendered
|
||||
// (this can happen when moving between dimensions)
|
||||
if (this.level instanceof IDhClientLevel)
|
||||
{
|
||||
boolean isRendering = ((IDhClientLevel) this.level).isRendering();
|
||||
if (!isRendering)
|
||||
{
|
||||
shouldDoWorldGen = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean isWorldGenRunning = this.isWorldGenRunning();
|
||||
if (shouldDoWorldGen && !isWorldGenRunning)
|
||||
{
|
||||
@@ -130,11 +145,14 @@ public class LodRequestModule implements Closeable
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// world gen control //
|
||||
//===================//
|
||||
//region
|
||||
|
||||
public void startWorldGen(GeneratedFullDataSourceProvider dataFileHandler, AbstractLodRequestState newWgs)
|
||||
{
|
||||
@@ -173,11 +191,14 @@ public class LodRequestModule implements Closeable
|
||||
dataFileHandler.removeWorldGenCompleteListener(this.onWorldGenCompleteListener);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=======================//
|
||||
// base method overrides //
|
||||
//=======================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
@@ -205,11 +226,14 @@ public class LodRequestModule implements Closeable
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
public boolean isWorldGenRunning() { return this.lodRequestStateRef.get() != null; }
|
||||
|
||||
@@ -241,170 +265,7 @@ public class LodRequestModule implements Closeable
|
||||
worldGenState.retrievalQueue.addDebugMenuStringsToList(messageList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
/** Handles the {@link IFullDataSourceRetrievalQueue} and any other necessary world gen information. */
|
||||
public static abstract class AbstractLodRequestState
|
||||
{
|
||||
/** static so we only send the disable message once per session */
|
||||
private static long firstProgressMessageSentMs = 0;
|
||||
|
||||
public IFullDataSourceRetrievalQueue retrievalQueue;
|
||||
|
||||
private static final ThreadPoolExecutor PROGRESS_UPDATER_THREAD = ThreadUtil.makeSingleDaemonThreadPool("World Gen Progress Updater");
|
||||
private boolean progressUpdateThreadRunning = false;
|
||||
|
||||
|
||||
|
||||
/** @param targetPosForRequest the position that world generation should be centered around */
|
||||
public void startRequestQueueAndSetTargetPos(DhBlockPos2D targetPosForRequest)
|
||||
{
|
||||
this.retrievalQueue.startAndSetTargetPos(targetPosForRequest);
|
||||
this.startProgressUpdateThread();
|
||||
}
|
||||
private void startProgressUpdateThread()
|
||||
{
|
||||
// only start the thread once
|
||||
if (!this.progressUpdateThreadRunning)
|
||||
{
|
||||
this.progressUpdateThreadRunning = true;
|
||||
|
||||
PROGRESS_UPDATER_THREAD.execute(() ->
|
||||
{
|
||||
while (this.progressUpdateThreadRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.sendRetrievalProgress();
|
||||
|
||||
// sleep so we only see an update once in a while
|
||||
int sleepTimeInSec = Config.Common.WorldGenerator.generationProgressDisplayIntervalInSeconds.get();
|
||||
Thread.sleep(sleepTimeInSec * 1_000L);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected issue displaying chunk retrieval progress [" + e.getMessage() + "].", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
private void sendRetrievalProgress()
|
||||
{
|
||||
// format the remaining chunks
|
||||
int remainingChunkCount = this.retrievalQueue.getRetrievalEstimatedRemainingChunkCount();
|
||||
remainingChunkCount += this.retrievalQueue.getQueuedChunkCount();
|
||||
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
|
||||
|
||||
String message = "DH is generating chunks. " + remainingChunkCountStr + " left."; // TODO getting stuck at 32 chunks remaining
|
||||
|
||||
// show a message about how to disable progress logging if requested
|
||||
int msToShowDisableInstructions = Config.Common.WorldGenerator.generationProgressDisableMessageDisplayTimeInSeconds.get() * 1_000;
|
||||
if (msToShowDisableInstructions > 0)
|
||||
{
|
||||
long timeSinceFirstMessageInMs = (System.currentTimeMillis() - firstProgressMessageSentMs);
|
||||
// always show this message for the first tick
|
||||
if (firstProgressMessageSentMs == 0
|
||||
// show this message if there is still time
|
||||
|| timeSinceFirstMessageInMs < msToShowDisableInstructions)
|
||||
{
|
||||
// append to the current message
|
||||
message += " This message can be hidden in the DH config.";
|
||||
}
|
||||
}
|
||||
|
||||
// add the remaining time estimate if available
|
||||
double chunksPerSec = this.getEstimatedChunksPerSecond();
|
||||
if (chunksPerSec > 0)
|
||||
{
|
||||
long estimatedRemainingTime = (long) (remainingChunkCount / chunksPerSec);
|
||||
message += " ETA: " + FormatUtil.formatEta(Duration.ofSeconds(estimatedRemainingTime));
|
||||
|
||||
if (Config.Common.WorldGenerator.generationProgressIncludeChunksPerSecond.get())
|
||||
{
|
||||
message += " at " + F3Screen.NUMBER_FORMAT.format(chunksPerSec) + " chunks/sec";
|
||||
}
|
||||
}
|
||||
|
||||
// only log if there are chunks needing to be generated
|
||||
if (remainingChunkCount != 0)
|
||||
{
|
||||
// determine where to log
|
||||
EDhApiDistantGeneratorProgressDisplayLocation displayLocation = Config.Common.WorldGenerator.showGenerationProgress.get();
|
||||
if (displayLocation == EDhApiDistantGeneratorProgressDisplayLocation.OVERLAY)
|
||||
{
|
||||
ClientApi.INSTANCE.showOverlayMessageNextFrame(message);
|
||||
}
|
||||
else if (displayLocation == EDhApiDistantGeneratorProgressDisplayLocation.CHAT)
|
||||
{
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
else if (displayLocation == EDhApiDistantGeneratorProgressDisplayLocation.LOG)
|
||||
{
|
||||
LOGGER.info(message);
|
||||
}
|
||||
|
||||
|
||||
// mark when the first message was sent
|
||||
if (firstProgressMessageSentMs == 0)
|
||||
{
|
||||
firstProgressMessageSentMs = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return -1 if this method isn't supported or available */
|
||||
public double getEstimatedChunksPerSecond()
|
||||
{
|
||||
RollingAverage avg = this.retrievalQueue.getRollingAverageChunkGenTimeInMs();
|
||||
if (avg == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PriorityTaskPicker.Executor executor = ThreadPoolUtil.getWorldGenExecutor();
|
||||
int threadCount = 1;
|
||||
if (executor != null)
|
||||
{
|
||||
threadCount = executor.getPoolSize();
|
||||
}
|
||||
|
||||
// convert chunk generation time in milliseconds to chunks per second
|
||||
double chunksPerSecond = (1 / avg.getAverage()) * 1_000;
|
||||
// estimate the number of chunks that can be processed per second by all threads
|
||||
// Note: this is probably higher than the actual number, we might want to drop this by 1 or 2 to give a more realistic estimate
|
||||
chunksPerSecond = threadCount * chunksPerSecond;
|
||||
|
||||
return chunksPerSecond;
|
||||
}
|
||||
|
||||
|
||||
CompletableFuture<Void> closeAsync(boolean doInterrupt)
|
||||
{
|
||||
// this should stop the updater thread
|
||||
this.progressUpdateThreadRunning = false;
|
||||
|
||||
return this.retrievalQueue.startClosingAsync(true, doInterrupt)
|
||||
.exceptionally(e ->
|
||||
{
|
||||
LOGGER.error("Error during first stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
|
||||
return null;
|
||||
}
|
||||
).thenRun(this.retrievalQueue::close)
|
||||
.exceptionally(e ->
|
||||
{
|
||||
LOGGER.error("Error during second stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
package com.seibel.distanthorizons.core.generation;
|
||||
package com.seibel.distanthorizons.core.generation.queues;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataSourceProviderV2;
|
||||
@@ -15,7 +15,6 @@ import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.WorldGenUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.RollingAverage;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
+2
-1
@@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.generation;
|
||||
package com.seibel.distanthorizons.core.generation.queues;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
|
||||
@@ -27,6 +27,7 @@ import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataSourceProviderV2;
|
||||
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalResult;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalTask;
|
||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||
@@ -27,7 +27,9 @@ import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataSourceProviderV2;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataSourceProvider;
|
||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.RemoteWorldRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.AbstractLodRequestState;
|
||||
import com.seibel.distanthorizons.core.generation.queues.LodRequestModule;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
@@ -396,12 +398,10 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
//================//
|
||||
//region
|
||||
|
||||
private static class LodRequestState extends LodRequestModule.AbstractLodRequestState
|
||||
private static class LodRequestState extends AbstractLodRequestState
|
||||
{
|
||||
LodRequestState(DhClientLevel clientLevel, ClientNetworkState networkState)
|
||||
{
|
||||
this.retrievalQueue = new RemoteWorldRetrievalQueue(networkState, clientLevel);
|
||||
}
|
||||
{ super(clientLevel, new RemoteWorldRetrievalQueue(networkState, clientLevel)); }
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -23,7 +23,10 @@ import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiW
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataSourceProvider;
|
||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||
import com.seibel.distanthorizons.core.generation.BatchGenerator;
|
||||
import com.seibel.distanthorizons.core.generation.WorldGenerationQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.IFullDataSourceRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.WorldGenerationQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.AbstractLodRequestState;
|
||||
import com.seibel.distanthorizons.core.generation.queues.LodRequestModule;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.WorldGeneratorInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
@@ -75,9 +78,11 @@ public class ServerLevelModule implements AutoCloseable
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
public static class LodRequestState extends LodRequestModule.AbstractLodRequestState
|
||||
public static class LodRequestState extends AbstractLodRequestState
|
||||
{
|
||||
LodRequestState(IDhServerLevel level)
|
||||
{ super(level, createRetrievalQueue(level)); }
|
||||
private static IFullDataSourceRetrievalQueue createRetrievalQueue(IDhServerLevel level)
|
||||
{
|
||||
IDhApiWorldGenerator worldGenerator = WorldGeneratorInjector.INSTANCE.get(level.getLevelWrapper());
|
||||
if (worldGenerator == null)
|
||||
@@ -88,9 +93,11 @@ public class ServerLevelModule implements AutoCloseable
|
||||
// since core world generator's should have the lowest override priority
|
||||
WorldGeneratorInjector.INSTANCE.bind(level.getLevelWrapper(), worldGenerator);
|
||||
}
|
||||
this.retrievalQueue = new WorldGenerationQueue(worldGenerator, level);
|
||||
return new WorldGenerationQueue(worldGenerator, level);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.client;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.queues.RemoteWorldRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalResult;
|
||||
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
|
||||
Reference in New Issue
Block a user