From 2ab48e0a8b3dd001e36202962228eb4abbefcaae Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Thu, 24 Aug 2023 21:09:39 +0500 Subject: [PATCH] Decouple world generation parts from DhLevel's --- .../core/api/internal/ClientApi.java | 4 + .../core/api/internal/ServerApi.java | 7 +- .../core/api/internal/SharedApi.java | 11 ++ .../GeneratedFullDataFileHandler.java | 16 +- .../generation/IWorldGenerationQueue.java | 26 ++++ .../core/generation/WorldGenerationQueue.java | 9 +- .../core/level/DhClientServerLevel.java | 12 +- .../core/level/DhServerLevel.java | 10 +- .../core/level/IDhServerLevel.java | 8 +- .../core/level/IDhWorldGenLevel.java | 9 ++ .../core/level/ServerLevelModule.java | 130 +--------------- .../core/level/WorldGenModule.java | 145 ++++++++++++++++++ .../core/world/DhClientWorld.java | 8 +- .../core/world/IDhClientWorld.java | 2 + 14 files changed, 239 insertions(+), 158 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/IDhWorldGenLevel.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java index 6b8d683eb..6934834b1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java @@ -319,6 +319,10 @@ public class ClientApi if (clientWorld != null) { clientWorld.clientTick(); + + // Ignore local world gen, as it's managed by server ticking + if (!(clientWorld instanceof DhClientServerWorld)) + SharedApi.worldGenTick(clientWorld::doWorldGen); } profiler.pop(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java index 455d8d68d..afc363e1e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java @@ -78,12 +78,7 @@ public class ServerApi if (serverWorld != null) { serverWorld.serverTick(); - this.lastWorldGenTickDelta--; - if (this.lastWorldGenTickDelta <= 0) - { - serverWorld.doWorldGen(); - this.lastWorldGenTickDelta = 20; - } + SharedApi.worldGenTick(serverWorld::doWorldGen); } } catch (Exception e) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java index 5544c8811..8abbd0609 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java @@ -12,6 +12,7 @@ import com.seibel.distanthorizons.core.world.*; public class SharedApi { private static AbstractDhWorld currentWorld; + private static int lastWorldGenTickDelta = 0; @@ -52,6 +53,16 @@ public class SharedApi } } + public static void worldGenTick(Runnable worldGenRunnable) + { + lastWorldGenTickDelta--; + if (lastWorldGenTickDelta <= 0) + { + worldGenRunnable.run(); + lastWorldGenTickDelta = 20; + } + } + public static AbstractDhWorld getAbstractDhWorld() { return currentWorld; } /** returns null if the {@link SharedApi#currentWorld} isn't a {@link DhClientServerWorld} */ public static DhClientServerWorld getDhClientServerWorld() { return (currentWorld != null && DhClientServerWorld.class.isInstance(currentWorld)) ? (DhClientServerWorld) currentWorld : null; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 99e45dd5f..75b48d9cb 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -5,11 +5,11 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFull import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource; import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; -import com.seibel.distanthorizons.core.generation.WorldGenerationQueue; +import com.seibel.distanthorizons.core.generation.IWorldGenerationQueue; import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker; import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult; import com.seibel.distanthorizons.core.level.DhLevel; -import com.seibel.distanthorizons.core.level.IDhServerLevel; +import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; @@ -28,14 +28,14 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - private final AtomicReference worldGenQueueRef = new AtomicReference<>(null); + private final AtomicReference worldGenQueueRef = new AtomicReference<>(null); private final ArrayList onWorldGenTaskCompleteListeners = new ArrayList<>(); // Use to hold onto incomplete data sources that are waiting for generation, so that they don't get GC'd before they are generated private final ConcurrentHashMap incompleteDataSources = new ConcurrentHashMap<>(); - public GeneratedFullDataFileHandler(IDhServerLevel level, AbstractSaveStructure saveStructure) { super(level, saveStructure); } + public GeneratedFullDataFileHandler(IDhLevel level, AbstractSaveStructure saveStructure) { super(level, saveStructure); } @@ -56,7 +56,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler //==================// /** Assumes there isn't a pre-existing queue. */ - public void setGenerationQueue(WorldGenerationQueue newWorldGenQueue) + public void setGenerationQueue(IWorldGenerationQueue newWorldGenQueue) { boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue); LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!"); @@ -115,13 +115,13 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler @Nullable private CompletableFuture tryStartGenTask(FullDataMetaFile file, IIncompleteFullDataSource dataSource) { - WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); // breaks down the missing positions into the desired detail level that the gen queue could accept if (worldGenQueue != null && !file.genQueueChecked) { DhSectionPos pos = file.pos; file.genQueueChecked = true; - byte maxSectDataDetailLevel = worldGenQueue.largestDataDetail; + byte maxSectDataDetailLevel = worldGenQueue.largestDataDetail(); byte targetDataDetailLevel = dataSource.getDataDetailLevel(); if (targetDataDetailLevel > maxSectDataDetailLevel) @@ -222,7 +222,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler if (source instanceof IIncompleteFullDataSource && !file.genQueueChecked) { - WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); if (worldGenQueue != null) { CompletableFuture future = this.updateFromExistingDataSources(file, (IIncompleteFullDataSource) source); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java new file mode 100644 index 000000000..e1aa2e376 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java @@ -0,0 +1,26 @@ +package com.seibel.distanthorizons.core.generation; + +import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker; +import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult; +import com.seibel.distanthorizons.core.pos.DhBlockPos2D; +import com.seibel.distanthorizons.core.pos.DhLodPos; +import com.seibel.distanthorizons.core.pos.DhSectionPos; + +import java.io.Closeable; +import java.util.concurrent.CompletableFuture; + +public interface IWorldGenerationQueue extends Closeable +{ + byte largestDataDetail(); + + CompletableFuture submitGenTask(DhLodPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker); + void cancelGenTasks(Iterable positions); + + void runCurrentGenTasksUntilBusy(DhBlockPos2D targetPos); + + int getWaitingTaskCount(); + int getInProgressTaskCount(); + + CompletableFuture startClosing(boolean cancelCurrentGeneration, boolean alsoInterruptRunning); + void close(); +} 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 20338b160..0a3c8477f 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 @@ -31,7 +31,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.function.Consumer; -public class WorldGenerationQueue implements Closeable, IDebugRenderable +public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRenderable { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -51,6 +51,8 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable /** largest numerical detail level allowed */ public final byte largestDataDetail; + @Override + public byte largestDataDetail() { return this.largestDataDetail; } /** lowest numerical detail level allowed */ public final byte smallestDataDetail; @@ -155,6 +157,11 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable //} } + @Override + public void cancelGenTasks(Iterable positions) + { + // TODO Should anything be here? + } //===============// // running tasks // diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java index 52e627541..acc6ce14a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java @@ -76,26 +76,26 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS { serverside.worldGeneratorEnabledConfig.pollNewValue(); boolean shouldDoWorldGen = serverside.worldGeneratorEnabledConfig.get() && clientside.isRendering(); - boolean isWorldGenRunning = serverside.isWorldGenRunning(); + boolean isWorldGenRunning = serverside.worldGenModule.isWorldGenRunning(); if (shouldDoWorldGen && !isWorldGenRunning) { // start world gen - serverside.startWorldGen(); + serverside.worldGenModule.startWorldGen(serverside.dataFileHandler, new ServerLevelModule.WorldGenState(this)); } else if (!shouldDoWorldGen && isWorldGenRunning) { // stop world gen - serverside.stopWorldGen(); + serverside.worldGenModule.stopWorldGen(serverside.dataFileHandler); } - - if (serverside.isWorldGenRunning()) + + if (serverside.worldGenModule.isWorldGenRunning()) { ClientLevelModule.ClientRenderState renderState = clientside.ClientRenderStateRef.get(); if (renderState != null && renderState.quadtree != null) { serverside.dataFileHandler.removeGenRequestIf(p -> !renderState.quadtree.isSectionPosInBounds(p)); } - serverside.worldGenTick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos())); + serverside.worldGenModule.worldGenTick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos())); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index 691193e95..907dac539 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -67,21 +67,21 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel public void doWorldGen() { boolean shouldDoWorldGen = true; //todo; - boolean isWorldGenRunning = serverside.isWorldGenRunning(); + boolean isWorldGenRunning = serverside.worldGenModule.isWorldGenRunning(); if (shouldDoWorldGen && !isWorldGenRunning) { // start world gen - serverside.startWorldGen(); + serverside.worldGenModule.startWorldGen(serverside.dataFileHandler, new ServerLevelModule.WorldGenState(this)); } else if (!shouldDoWorldGen && isWorldGenRunning) { // stop world gen - serverside.stopWorldGen(); + serverside.worldGenModule.stopWorldGen(serverside.dataFileHandler); } - if (serverside.isWorldGenRunning()) + if (serverside.worldGenModule.isWorldGenRunning()) { - serverside.worldGenTick(new DhBlockPos2D(0, 0)); // todo; + serverside.worldGenModule.worldGenTick(new DhBlockPos2D(0, 0)); // todo; } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java index 8ef80a7e5..b6ed06b04 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java @@ -3,11 +3,9 @@ package com.seibel.distanthorizons.core.level; import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataFileHandler; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; -public interface IDhServerLevel extends IDhLevel, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener +public interface IDhServerLevel extends IDhWorldGenLevel { - void serverTick(); - void doWorldGen(); - - IServerLevelWrapper getServerLevelWrapper(); + void serverTick(); + IServerLevelWrapper getServerLevelWrapper(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhWorldGenLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhWorldGenLevel.java new file mode 100644 index 000000000..a97faaadd --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhWorldGenLevel.java @@ -0,0 +1,9 @@ +package com.seibel.distanthorizons.core.level; + +import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataFileHandler; + +public interface IDhWorldGenLevel extends IDhLevel, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener +{ + void doWorldGen(); + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java index 420a66dee..adc85dcca 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java @@ -8,15 +8,10 @@ import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; import com.seibel.distanthorizons.core.generation.BatchGenerator; import com.seibel.distanthorizons.core.generation.WorldGenerationQueue; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.logging.f3.F3Screen; -import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.coreapi.DependencyInjection.WorldGeneratorInjector; import org.apache.logging.log4j.Logger; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; - public class ServerLevelModule { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -27,8 +22,7 @@ public class ServerLevelModule public final GeneratedFullDataFileHandler dataFileHandler; public final AppliedConfigState worldGeneratorEnabledConfig; - private final AtomicReference worldGenStateRef = new AtomicReference<>(); - private final F3Screen.DynamicMessage worldGenF3Message; + public final WorldGenModule worldGenModule; @@ -39,109 +33,17 @@ public class ServerLevelModule this.saveStructure = saveStructure; this.dataFileHandler = new GeneratedFullDataFileHandler(parent, saveStructure); this.worldGeneratorEnabledConfig = new AppliedConfigState<>(Config.Client.Advanced.WorldGenerator.enableDistantGeneration); - - this.worldGenF3Message = new F3Screen.DynamicMessage(() -> - { - WorldGenState worldGenState = this.worldGenStateRef.get(); - if (worldGenState != null) - { - int waiting = worldGenState.worldGenerationQueue.getWaitingTaskCount(); - int inProgress = worldGenState.worldGenerationQueue.getInProgressTaskCount(); - - return "World Gen Tasks: "+waiting+", (in progress: "+inProgress+")"; - } - else - { - return "World Gen Disabled"; - } - }); + this.worldGenModule = new WorldGenModule(this.dataFileHandler, this.parent); } - - - //==============// - // tick methods // - //==============// - - public void startWorldGen() - { - // create the new world generator - WorldGenState newWgs = new WorldGenState(parent); - if (!this.worldGenStateRef.compareAndSet(null, newWgs)) - { - LOGGER.warn("Failed to start world gen due to concurrency"); - newWgs.closeAsync(false); - } - dataFileHandler.addWorldGenCompleteListener(parent); - dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue); - } - - public void stopWorldGen() - { - WorldGenState worldGenState = this.worldGenStateRef.get(); - if (worldGenState == null) - { - LOGGER.warn("Attempted to stop world gen when it was not running"); - return; - } - - // shut down the world generator - while (!this.worldGenStateRef.compareAndSet(worldGenState, null)) - { - worldGenState = this.worldGenStateRef.get(); - if (worldGenState == null) - { - return; - } - } - dataFileHandler.clearGenerationQueue(); - worldGenState.closeAsync(true).join(); //TODO: Make it async. - dataFileHandler.removeWorldGenCompleteListener(parent); - } - - public boolean isWorldGenRunning() - { - return this.worldGenStateRef.get() != null; - } - - public void worldGenTick(DhBlockPos2D targetPosForGeneration) - { - WorldGenState worldGenState = this.worldGenStateRef.get(); - if (worldGenState != null) - { - // queue new world generation requests - worldGenState.tick(targetPosForGeneration); - } - } - - - //===============// // data handling // //===============// public void close() { // shutdown the world-gen - WorldGenState worldGenState = this.worldGenStateRef.get(); - if (worldGenState != null) - { - while (!this.worldGenStateRef.compareAndSet(worldGenState, null)) - { - worldGenState = this.worldGenStateRef.get(); - if (worldGenState == null) - { - break; - } - } - - if (worldGenState != null) - { - worldGenState.closeAsync(true).join(); //TODO: Make it async. - } - } - - this.dataFileHandler.close(); - this.worldGenF3Message.close(); + this.worldGenModule.close(); + dataFileHandler.close(); } @@ -150,9 +52,8 @@ public class ServerLevelModule // helper classes // //================// - private static class WorldGenState + public static class WorldGenState extends WorldGenModule.WorldGenState { - public final WorldGenerationQueue worldGenerationQueue; WorldGenState(IDhServerLevel level) { IDhApiWorldGenerator worldGenerator = WorldGeneratorInjector.INSTANCE.get(level.getLevelWrapper()); @@ -167,27 +68,6 @@ public class ServerLevelModule this.worldGenerationQueue = new WorldGenerationQueue(worldGenerator); } - CompletableFuture closeAsync(boolean doInterrupt) - { - return this.worldGenerationQueue.startClosing(true, doInterrupt) - .exceptionally(ex -> - { - LOGGER.error("Error closing generation queue", ex); - return null; - } - ).thenRun(this.worldGenerationQueue::close) - .exceptionally(ex -> - { - LOGGER.error("Error closing world gen", ex); - return null; - }); - } - - public void tick(DhBlockPos2D targetPosForGeneration) - { - worldGenerationQueue.runCurrentGenTasksUntilBusy(targetPosForGeneration); - } - } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java new file mode 100644 index 000000000..97b0c9232 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java @@ -0,0 +1,145 @@ +package com.seibel.distanthorizons.core.level; + +import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataFileHandler; +import com.seibel.distanthorizons.core.generation.IWorldGenerationQueue; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.logging.f3.F3Screen; +import com.seibel.distanthorizons.core.pos.DhBlockPos2D; +import org.apache.logging.log4j.Logger; + +import java.io.Closeable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; + +public class WorldGenModule implements Closeable +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + + private final GeneratedFullDataFileHandler dataFileHandler; + private final GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener; + + private final AtomicReference worldGenStateRef = new AtomicReference<>(); + private final F3Screen.DynamicMessage worldGenF3Message; + + public static abstract class WorldGenState + { + public IWorldGenerationQueue worldGenerationQueue; + + CompletableFuture closeAsync(boolean doInterrupt) + { + return this.worldGenerationQueue.startClosing(true, doInterrupt) + .exceptionally(ex -> + { + LOGGER.error("Error closing generation queue", ex); + return null; + } + ).thenRun(this.worldGenerationQueue::close) + .exceptionally(ex -> + { + LOGGER.error("Error closing world gen", ex); + return null; + }); + } + + public void tick(DhBlockPos2D targetPosForGeneration) + { + worldGenerationQueue.runCurrentGenTasksUntilBusy(targetPosForGeneration); + } + } + + public WorldGenModule(GeneratedFullDataFileHandler dataFileHandler, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener) + { + this.dataFileHandler = dataFileHandler; + this.onWorldGenCompleteListener = onWorldGenCompleteListener; + this.worldGenF3Message = new F3Screen.DynamicMessage(() -> + { + WorldGenState worldGenState = this.worldGenStateRef.get(); + if (worldGenState != null) + { + int waiting = worldGenState.worldGenerationQueue.getWaitingTaskCount(); + int inProgress = worldGenState.worldGenerationQueue.getInProgressTaskCount(); + + return "World Gen Tasks: "+waiting+", (in progress: "+inProgress+")"; + } + else + { + return "World Gen Disabled"; + } + }); + + } + + public void startWorldGen(GeneratedFullDataFileHandler dataFileHandler, WorldGenState newWgs) + { + // create the new world generator + if (!this.worldGenStateRef.compareAndSet(null, newWgs)) + { + LOGGER.warn("Failed to start world gen due to concurrency"); + newWgs.closeAsync(false); + } + dataFileHandler.addWorldGenCompleteListener(onWorldGenCompleteListener); + dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue); + } + + public void stopWorldGen(GeneratedFullDataFileHandler dataFileHandler) + { + WorldGenState worldGenState = this.worldGenStateRef.get(); + if (worldGenState == null) + { + LOGGER.warn("Attempted to stop world gen when it was not running"); + return; + } + + // shut down the world generator + while (!this.worldGenStateRef.compareAndSet(worldGenState, null)) + { + worldGenState = this.worldGenStateRef.get(); + if (worldGenState == null) + { + return; + } + } + dataFileHandler.clearGenerationQueue(); + worldGenState.closeAsync(true).join(); //TODO: Make it async. + dataFileHandler.removeWorldGenCompleteListener(onWorldGenCompleteListener); + } + + public boolean isWorldGenRunning() + { + return this.worldGenStateRef.get() != null; + } + + public void worldGenTick(DhBlockPos2D targetPosForGeneration) + { + WorldGenState worldGenState = this.worldGenStateRef.get(); + if (worldGenState != null) + { + // queue new world generation requests + worldGenState.tick(targetPosForGeneration); + } + } + + public void close() + { + // shutdown the world-gen + WorldGenState worldGenState = this.worldGenStateRef.get(); + if (worldGenState != null) + { + while (!this.worldGenStateRef.compareAndSet(worldGenState, null)) + { + worldGenState = this.worldGenStateRef.get(); + if (worldGenState == null) + { + break; + } + } + + if (worldGenState != null) + { + worldGenState.closeAsync(true).join(); //TODO: Make it async. + } + } + dataFileHandler.close(); + this.worldGenF3Message.close(); + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java index 2b39ff96c..0e284681f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java @@ -149,8 +149,12 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld public void clientTick() { this.eventLoop.tick(); } - @Override - public CompletableFuture saveAndFlush() + public void doWorldGen() { + // Not implemented + } + + @Override + public CompletableFuture saveAndFlush() { return CompletableFuture.allOf(this.levels.values().stream().map(DhClientLevel::saveAsync).toArray(CompletableFuture[]::new)); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/IDhClientWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/IDhClientWorld.java index ce5c72afd..486b90afa 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/IDhClientWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/IDhClientWorld.java @@ -7,6 +7,8 @@ public interface IDhClientWorld extends IDhWorld { void clientTick(); + void doWorldGen(); + default IDhClientLevel getOrLoadClientLevel(ILevelWrapper levelWrapper) { return (IDhClientLevel) this.getOrLoadLevel(levelWrapper); } }