This commit is contained in:
James Seibel
2023-08-25 21:05:47 -05:00
parent 89724e4a74
commit cdc6635a76
7 changed files with 139 additions and 117 deletions
@@ -322,7 +322,9 @@ public class ClientApi
// Ignore local world gen, as it's managed by server ticking
if (!(clientWorld instanceof DhClientServerWorld))
{
SharedApi.worldGenTick(clientWorld::doWorldGen);
}
}
profiler.pop();
}
@@ -11,11 +11,13 @@ import java.util.concurrent.CompletableFuture;
public interface IWorldGenerationQueue extends Closeable
{
/** the largest numerical detail level */
byte largestDataDetail();
CompletableFuture<WorldGenResult> submitGenTask(DhLodPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker);
void cancelGenTasks(Iterable<DhSectionPos> positions);
/** @param targetPos the position that world generation should be centered around, generally this will be the player's position. */
void runCurrentGenTasksUntilBusy(DhBlockPos2D targetPos);
int getWaitingTaskCount();
@@ -23,4 +25,5 @@ public interface IWorldGenerationQueue extends Closeable
CompletableFuture<Void> startClosing(boolean cancelCurrentGeneration, boolean alsoInterruptRunning);
void close();
}
@@ -160,7 +160,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
@Override
public void cancelGenTasks(Iterable<DhSectionPos> positions)
{
// TODO Should anything be here?
// TODO Should we cancel generation of chunks that were loaded by the player?
}
//===============//
@@ -42,7 +42,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS
LOGGER.warn("unable to create data folder.");
}
this.serverLevelWrapper = serverLevelWrapper;
this.serverside = new ServerLevelModule(this, serverLevelWrapper, saveStructure);
this.serverside = new ServerLevelModule(this, saveStructure);
this.clientside = new ClientLevelModule(this);
LOGGER.info("Started " + DhClientServerLevel.class.getSimpleName() + " for " + serverLevelWrapper + " with saves at " + saveStructure);
}
@@ -129,7 +129,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS
}
@Override
public IClientLevelWrapper getClientLevelWrapper() { return serverside.levelWrapper.tryGetClientLevelWrapper(); }
public IClientLevelWrapper getClientLevelWrapper() { return this.serverLevelWrapper.tryGetClientLevelWrapper(); }
@Override
public void clearRenderCache()
@@ -27,7 +27,7 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
LOGGER.warn("unable to create data folder.");
}
this.serverLevelWrapper = serverLevelWrapper;
serverside = new ServerLevelModule(this, serverLevelWrapper, saveStructure);
this.serverside = new ServerLevelModule(this, saveStructure);
LOGGER.info("Started DHLevel for {} with saves at {}", serverLevelWrapper, saveStructure);
}
@@ -16,8 +16,7 @@ public class ServerLevelModule
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public final IServerLevelWrapper levelWrapper;
public final IDhServerLevel parent;
public final IDhServerLevel parentServerLevel;
public final AbstractSaveStructure saveStructure;
public final GeneratedFullDataFileHandler dataFileHandler;
public final AppliedConfigState<Boolean> worldGeneratorEnabledConfig;
@@ -26,24 +25,22 @@ public class ServerLevelModule
public ServerLevelModule(IDhServerLevel parent, IServerLevelWrapper levelWrapper, AbstractSaveStructure saveStructure)
public ServerLevelModule(IDhServerLevel parentServerLevel, AbstractSaveStructure saveStructure)
{
this.parent = parent;
this.levelWrapper = levelWrapper;
this.parentServerLevel = parentServerLevel;
this.saveStructure = saveStructure;
this.dataFileHandler = new GeneratedFullDataFileHandler(parent, saveStructure);
this.dataFileHandler = new GeneratedFullDataFileHandler(parentServerLevel, saveStructure);
this.worldGeneratorEnabledConfig = new AppliedConfigState<>(Config.Client.Advanced.WorldGenerator.enableDistantGeneration);
this.worldGenModule = new WorldGenModule(this.dataFileHandler, this.parent);
this.worldGenModule = new WorldGenModule(this.dataFileHandler, this.parentServerLevel);
}
//===============//
// data handling //
//===============//
public void close()
{
// shutdown the world-gen
this.worldGenModule.close();
dataFileHandler.close();
this.dataFileHandler.close();
}
@@ -52,7 +49,7 @@ public class ServerLevelModule
// helper classes //
//================//
public static class WorldGenState extends WorldGenModule.WorldGenState
public static class WorldGenState extends WorldGenModule.AbstractWorldGenState
{
WorldGenState(IDhServerLevel level)
{
@@ -18,10 +18,127 @@ public class WorldGenModule implements Closeable
private final GeneratedFullDataFileHandler dataFileHandler;
private final GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener;
private final AtomicReference<WorldGenState> worldGenStateRef = new AtomicReference<>();
private final AtomicReference<AbstractWorldGenState> worldGenStateRef = new AtomicReference<>();
private final F3Screen.DynamicMessage worldGenF3Message;
public static abstract class WorldGenState
public WorldGenModule(GeneratedFullDataFileHandler dataFileHandler, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener)
{
this.dataFileHandler = dataFileHandler;
this.onWorldGenCompleteListener = onWorldGenCompleteListener;
this.worldGenF3Message = new F3Screen.DynamicMessage(() ->
{
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
if (worldGenState != null)
{
int waitingCount = worldGenState.worldGenerationQueue.getWaitingTaskCount();
int inProgressCount = worldGenState.worldGenerationQueue.getInProgressTaskCount();
return "World Gen Tasks: "+waitingCount+", (in progress: "+inProgressCount+")";
}
else
{
return "World Gen Disabled";
}
});
}
//===================//
// world gen control //
//===================//
public void startWorldGen(GeneratedFullDataFileHandler dataFileHandler, AbstractWorldGenState 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(this.onWorldGenCompleteListener);
dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue);
}
public void stopWorldGen(GeneratedFullDataFileHandler dataFileHandler)
{
AbstractWorldGenState 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(this.onWorldGenCompleteListener);
}
/** @param targetPosForGeneration the position that world generation should be centered around */
public void worldGenTick(DhBlockPos2D targetPosForGeneration)
{
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
if (worldGenState != null)
{
// queue new world generation requests
worldGenState.tick(targetPosForGeneration);
}
}
@Override
public void close()
{
// shutdown the world-gen
AbstractWorldGenState 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();
}
//=========//
// getters //
//=========//
public boolean isWorldGenRunning() { return this.worldGenStateRef.get() != null; }
//================//
// helper classes //
//================//
/** Handles the {@link IWorldGenerationQueue} and any other necessary world gen information. */
public static abstract class AbstractWorldGenState
{
public IWorldGenerationQueue worldGenerationQueue;
@@ -41,105 +158,8 @@ public class WorldGenModule implements Closeable
});
}
public void tick(DhBlockPos2D targetPosForGeneration)
{
worldGenerationQueue.runCurrentGenTasksUntilBusy(targetPosForGeneration);
}
/** @param targetPosForGeneration the position that world generation should be centered around */
public void tick(DhBlockPos2D targetPosForGeneration) { this.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();
}
}