Refactor Dh Client/Server/ClientServer Level objects

This commit is contained in:
James Seibel
2022-11-13 16:33:30 -06:00
parent 51601e710a
commit f11752da96
3 changed files with 487 additions and 397 deletions
@@ -26,75 +26,84 @@ import java.util.concurrent.CompletableFuture;
public class DhClientLevel implements IDhClientLevel
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final ClientOnlySaveStructure save;
public final RemoteDataFileHandler dataFileHandler;
public final RenderFileHandler renderFileHandler;
public final RenderBufferHandler renderBufferHandler; //TODO: Should this be owned by renderer?
public final IClientLevelWrapper level;
public LodRenderer renderer = null;
public LodQuadTree tree;
public DhClientLevel(ClientOnlySaveStructure save, IClientLevelWrapper level) {
this.save = save;
save.getDataFolder(level).mkdirs();
save.getRenderCacheFolder(level).mkdirs();
dataFileHandler = new RemoteDataFileHandler(this, save.getDataFolder(level));
renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level));
tree = new LodQuadTree(this, Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16,
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler);
renderBufferHandler = new RenderBufferHandler(tree);
this.level = level;
FileScanUtil.scanFile(save, level, dataFileHandler, renderFileHandler);
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
}
@Override
public void dumpRamUsage() {
//TODO
}
@Override
public void clientTick() {
tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
renderBufferHandler.update();
}
@Override
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
if (renderer == null) {
renderer = new LodRenderer(renderBufferHandler);
}
renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
}
@Override
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) {
return 0; //TODO
}
@Override
public IClientLevelWrapper getClientLevelWrapper() { return level; }
@Override
public ILevelWrapper getLevelWrapper() { return this.level; }
@Override
public void updateChunk(IChunkWrapper chunk) {
//TODO
}
@Override
public int getMinY() { return level.getMinHeight(); }
@Override
public CompletableFuture<Void> save() { return renderFileHandler.flushAndSave(); }
@Override
public void close() {
renderFileHandler.close();
LOGGER.info("Closed DHLevel for {}", level);
}
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final ClientOnlySaveStructure save;
public final RemoteDataFileHandler dataFileHandler;
public final RenderFileHandler renderFileHandler;
public final RenderBufferHandler renderBufferHandler; //TODO: Should this be owned by renderer?
public final IClientLevelWrapper level;
public LodRenderer renderer = null;
public LodQuadTree tree;
public DhClientLevel(ClientOnlySaveStructure save, IClientLevelWrapper level)
{
this.save = save;
save.getDataFolder(level).mkdirs();
save.getRenderCacheFolder(level).mkdirs();
this.dataFileHandler = new RemoteDataFileHandler(this, save.getDataFolder(level));
this.renderFileHandler = new RenderFileHandler(this.dataFileHandler, this, save.getRenderCacheFolder(level));
this.tree = new LodQuadTree(this, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16,
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, this.renderFileHandler);
this.renderBufferHandler = new RenderBufferHandler(this.tree);
this.level = level;
FileScanUtil.scanFile(save, level, this.dataFileHandler, this.renderFileHandler);
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
}
@Override
public void dumpRamUsage()
{
//TODO
}
@Override
public void clientTick()
{
this.tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
this.renderBufferHandler.update();
}
@Override
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
{
if (this.renderer == null)
{
this.renderer = new LodRenderer(this.renderBufferHandler);
}
this.renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
}
@Override
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) { return 0; /* TODO */ }
@Override
public IClientLevelWrapper getClientLevelWrapper() { return this.level; }
@Override
public ILevelWrapper getLevelWrapper() { return this.level; }
@Override
public void updateChunk(IChunkWrapper chunk)
{
//TODO
}
@Override
public int getMinY() { return this.level.getMinHeight(); }
@Override
public CompletableFuture<Void> save() { return this.renderFileHandler.flushAndSave(); }
@Override
public void close()
{
this.renderFileHandler.close();
LOGGER.info("Closed DHLevel for {}", this.level);
}
}
@@ -36,273 +36,355 @@ import org.apache.logging.log4j.Logger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
/** The level used on a singleplayer world */
public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
{
class RenderState {
final IClientLevelWrapper clientLevel;
final LodQuadTree tree;
final RenderFileHandler renderFileHandler;
final RenderBufferHandler renderBufferHandler; //TODO: Should this be owned by renderer?
final LodRenderer renderer;
RenderState(IClientLevelWrapper clientLevel) {
this.clientLevel = clientLevel;
renderFileHandler = new RenderFileHandler(dataFileHandler, DhClientServerLevel.this, save.getRenderCacheFolder(serverLevel));
tree = new LodQuadTree(DhClientServerLevel.this, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16,
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler);
renderBufferHandler = new RenderBufferHandler(tree);
FileScanUtil.scanFile(save, serverLevel, null, renderFileHandler);
renderer = new LodRenderer(renderBufferHandler);
}
CompletableFuture<Void> close() {
renderer.close();
renderBufferHandler.close();
tree.close();
return renderFileHandler.flushAndSave();
}
}
class WorldGenState {
final BatchGenerator batchGenerator;
final GenerationQueue generationQueue;
WorldGenState() {
batchGenerator = new BatchGenerator(DhClientServerLevel.this);
generationQueue = new GenerationQueue(batchGenerator);
dataFileHandler.setGenerationQueue(generationQueue);
}
CompletableFuture<Void> close(boolean doInterrupt) {
dataFileHandler.popGenerationQueue();
return generationQueue.startClosing(true, doInterrupt)
.exceptionally(ex -> {
LOGGER.error("Error closing generation queue", ex);
return null;
}).thenRun(batchGenerator::close)
.exceptionally(ex -> {
LOGGER.error("Error closing world gen", ex);
return null;
});
}
}
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final LocalSaveStructure save;
public final GeneratedDataFileHandler dataFileHandler;
public final ChunkToLodBuilder chunkToLodBuilder;
public final IServerLevelWrapper serverLevel;
private final AppliedConfigState<Boolean> generatorEnabled;
public F3Screen.NestedMessage f3Msg;
public final AtomicReference<RenderState> renderState = new AtomicReference<>();
public final AtomicReference<WorldGenState> worldGenState = new AtomicReference<>();
public DhClientServerLevel(LocalSaveStructure save, IServerLevelWrapper level) {
this.serverLevel = level;
this.save = save;
save.getDataFolder(level).mkdirs();
save.getRenderCacheFolder(level).mkdirs();
dataFileHandler = new GeneratedDataFileHandler(this, save.getDataFolder(level));
FileScanUtil.scanFile(save, serverLevel, dataFileHandler, null);
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
f3Msg = new F3Screen.NestedMessage(this::f3Log);
chunkToLodBuilder = new ChunkToLodBuilder();
generatorEnabled = new AppliedConfigState<>(Config.Client.WorldGenerator.enableDistantGeneration);
}
private String[] f3Log() {
RenderState rs = renderState.get();
if (rs == null) {
return new String[]{LodUtil.formatLog("level @ {}: Inactive", serverLevel.getDimensionType().getDimensionName())};
} else {
return new String[]{
LodUtil.formatLog("level @ {}: Active", serverLevel.getDimensionType().getDimensionName())
};
}
}
@Override
public void clientTick() {
RenderState rs = renderState.get();
if (rs == null) return;
if (rs.tree.viewDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16) {
if (!renderState.compareAndSet(rs, null)) return; //If we fail, we'll just wait for the next tick
IClientLevelWrapper levelWrapper = rs.clientLevel;
rs.close().join(); //TODO: Make it async.
rs = new RenderState(levelWrapper);
if (!renderState.compareAndSet(null, rs)) { //FIXME: How to handle this?
LOGGER.warn("Failed to set render state due to concurrency after changing view distance");
rs.close();
return;
}
}
rs.tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
rs.renderBufferHandler.update();
}
private void saveWrites(ChunkSizedData data) {
RenderState rs = renderState.get();
DhLodPos pos = data.getBBoxLodPos().convertUpwardsTo(FullDataSource.SECTION_SIZE_OFFSET);
if (rs != null) {
rs.renderFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
} else {
dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
}
}
@Override
public void serverTick() {
chunkToLodBuilder.tick();
}
public void startRenderer(IClientLevelWrapper clientLevel) {
LOGGER.info("Starting renderer for {}", this);
RenderState rs = new RenderState(clientLevel);
if (!renderState.compareAndSet(null, rs)) {
LOGGER.warn("Failed to start renderer due to concurrency");
rs.close();
} else {
generatorEnabled.pollNewValue();
if (generatorEnabled.get() && worldGenState.get() == null) {
WorldGenState wgs = new WorldGenState();
if (!worldGenState.compareAndSet(null, wgs)) {
LOGGER.warn("Failed to start world gen due to concurrency");
wgs.close(false);
}
}
}
}
@Override
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) {
RenderState rs = renderState.get();
if (rs == null) {
LOGGER.error("Tried to call render() on {} when renderer has not been started!", this);
return;
}
rs.renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
}
public void stopRenderer() {
LOGGER.info("Stopping renderer for {}", this);
RenderState rs = renderState.get();
if (rs == null) {
LOGGER.warn("Tried to stop renderer for {} when it was not started!", this);
return;
}
while (!renderState.compareAndSet(rs, null)) {
rs = renderState.get();
if (rs == null) return;
}
rs.close().join(); //TODO: Make it async.
WorldGenState wgs = worldGenState.get();
if (wgs != null) {
while (!worldGenState.compareAndSet(wgs, null)) {
wgs = worldGenState.get();
if (wgs == null) return;
}
wgs.close(true).join(); //TODO: Make it async.
}
}
@Override //FIXME
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) {
IClientLevelWrapper clientLevel = getClientLevelWrapper();
if (clientLevel == null) {
return 0;
} else {
return clientLevel.computeBaseColor(pos, biome, block);
}
}
@Override
public IClientLevelWrapper getClientLevelWrapper() {
RenderState rs = renderState.get();
return rs == null ? null : rs.clientLevel;
}
@Override
public ILevelWrapper getLevelWrapper()
{
return this.serverLevel;
}
@Override
public void updateChunk(IChunkWrapper chunk) {
CompletableFuture<ChunkSizedData> future = chunkToLodBuilder.tryGenerateData(chunk);
if (future != null) {
future.thenAccept(this::saveWrites);
}
}
@Override
public void dumpRamUsage() {
//TODO
}
@Override
public int getMinY() {
return serverLevel.getMinHeight();
}
@Override
public CompletableFuture<Void> save() {
RenderState rs = renderState.get();
if (rs != null) {
return rs.renderFileHandler.flushAndSave().thenCombine(dataFileHandler.flushAndSave(), (a, b) -> null);
} else {
return dataFileHandler.flushAndSave();
}
}
@Override
public void close() {
RenderState rs = renderState.get();
if (rs != null) {
while (!renderState.compareAndSet(rs, null)) {
rs = renderState.get();
if (rs == null) return;
}
rs.close().join(); //TODO: Make it async.
}
WorldGenState wgs = worldGenState.get();
if (wgs != null) {
while (!worldGenState.compareAndSet(wgs, null)) {
wgs = worldGenState.get();
if (wgs == null) return;
}
wgs.close(true).join(); //TODO: Make it async.
}
LOGGER.info("Closed {}", this);
}
@Override
public void doWorldGen() {
WorldGenState wgs = worldGenState.get();
if (generatorEnabled.pollNewValue()) {
boolean shouldDoWorldGen = generatorEnabled.get() && renderState.get() != null;
if (shouldDoWorldGen && wgs == null) {
WorldGenState newWgs = new WorldGenState();
if (!worldGenState.compareAndSet(null, newWgs)) {
LOGGER.warn("Failed to start world gen due to concurrency");
newWgs.close(false);
}
} else if (!shouldDoWorldGen && wgs != null) {
while (!worldGenState.compareAndSet(wgs, null)) {
wgs = worldGenState.get();
if (wgs == null) return;
}
wgs.close(true).join(); //TODO: Make it async.
}
}
if (wgs != null) {
wgs.batchGenerator.update();
wgs.generationQueue.pollAndStartClosest(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
}
}
@Override
public IServerLevelWrapper getServerLevelWrapper() {
return serverLevel;
}
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final LocalSaveStructure save;
public final GeneratedDataFileHandler dataFileHandler;
public final ChunkToLodBuilder chunkToLodBuilder;
public final IServerLevelWrapper serverLevel;
private final AppliedConfigState<Boolean> generatorEnabled;
public F3Screen.NestedMessage f3Msg;
public final AtomicReference<RenderState> renderState = new AtomicReference<>();
public final AtomicReference<WorldGenState> worldGenState = new AtomicReference<>();
public DhClientServerLevel(LocalSaveStructure save, IServerLevelWrapper level)
{
this.serverLevel = level;
this.save = save;
save.getDataFolder(level).mkdirs();
save.getRenderCacheFolder(level).mkdirs();
this.dataFileHandler = new GeneratedDataFileHandler(this, save.getDataFolder(level));
FileScanUtil.scanFile(save, this.serverLevel, this.dataFileHandler, null);
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
this.f3Msg = new F3Screen.NestedMessage(this::f3Log);
this.chunkToLodBuilder = new ChunkToLodBuilder();
this.generatorEnabled = new AppliedConfigState<>(Config.Client.WorldGenerator.enableDistantGeneration);
}
/** Returns what should be displayed in Minecraft's F3 debug menu */
private String[] f3Log()
{
RenderState rs = this.renderState.get();
if (rs == null)
{
return new String[] { LodUtil.formatLog("level @ {}: Inactive", this.serverLevel.getDimensionType().getDimensionName()) };
}
else
{
return new String[] {
LodUtil.formatLog("level @ {}: Active", this.serverLevel.getDimensionType().getDimensionName())
};
}
}
@Override
public void clientTick()
{
RenderState rs = this.renderState.get();
if (rs == null)
return;
if (rs.tree.viewDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
{
if (!this.renderState.compareAndSet(rs, null))
return; //If we fail, we'll just wait for the next tick
IClientLevelWrapper levelWrapper = rs.clientLevel;
rs.close().join(); //TODO: Make it async.
rs = new RenderState(levelWrapper);
if (!this.renderState.compareAndSet(null, rs))
{
//FIXME: How to handle this?
LOGGER.warn("Failed to set render state due to concurrency after changing view distance");
rs.close();
return;
}
}
rs.tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
rs.renderBufferHandler.update();
}
private void saveWrites(ChunkSizedData data)
{
RenderState rs = this.renderState.get();
DhLodPos pos = data.getBBoxLodPos().convertUpwardsTo(FullDataSource.SECTION_SIZE_OFFSET);
if (rs != null)
{
rs.renderFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
}
else
{
this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
}
}
@Override
public void serverTick() { this.chunkToLodBuilder.tick(); }
public void startRenderer(IClientLevelWrapper clientLevel)
{
LOGGER.info("Starting renderer for {}", this);
RenderState rs = new RenderState(clientLevel);
if (!this.renderState.compareAndSet(null, rs))
{
LOGGER.warn("Failed to start renderer due to concurrency");
rs.close();
}
else
{
this.generatorEnabled.pollNewValue();
if (this.generatorEnabled.get() && this.worldGenState.get() == null)
{
WorldGenState wgs = new WorldGenState();
if (!this.worldGenState.compareAndSet(null, wgs))
{
LOGGER.warn("Failed to start world gen due to concurrency");
wgs.close(false);
}
}
}
}
@Override
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
{
RenderState rs = this.renderState.get();
if (rs == null)
{
LOGGER.error("Tried to call render() on {} when renderer has not been started!", this);
return;
}
rs.renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
}
public void stopRenderer()
{
LOGGER.info("Stopping renderer for {}", this);
RenderState rs = this.renderState.get();
if (rs == null)
{
LOGGER.warn("Tried to stop renderer for {} when it was not started!", this);
return;
}
while (!this.renderState.compareAndSet(rs, null))
{
rs = this.renderState.get();
if (rs == null)
return;
}
rs.close().join(); //TODO: Make it async.
WorldGenState wgs = this.worldGenState.get();
if (wgs != null)
{
while (!this.worldGenState.compareAndSet(wgs, null))
{
wgs = this.worldGenState.get();
if (wgs == null)
return;
}
wgs.close(true).join(); //TODO: Make it async.
}
}
@Override //FIXME
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block)
{
IClientLevelWrapper clientLevel = this.getClientLevelWrapper();
if (clientLevel == null)
{
return 0;
}
else
{
return clientLevel.computeBaseColor(pos, biome, block);
}
}
@Override
public IClientLevelWrapper getClientLevelWrapper()
{
RenderState rs = this.renderState.get();
return rs == null ? null : rs.clientLevel;
}
@Override
public ILevelWrapper getLevelWrapper() { return this.serverLevel; }
@Override
public void updateChunk(IChunkWrapper chunk)
{
CompletableFuture<ChunkSizedData> future = this.chunkToLodBuilder.tryGenerateData(chunk);
if (future != null)
{
future.thenAccept(this::saveWrites);
}
}
@Override
public void dumpRamUsage()
{
//TODO
}
@Override
public int getMinY() { return this.serverLevel.getMinHeight(); }
@Override
public CompletableFuture<Void> save()
{
RenderState rs = this.renderState.get();
if (rs != null)
{
return rs.renderFileHandler.flushAndSave().thenCombine(this.dataFileHandler.flushAndSave(), (a, b) -> null);
}
else
{
return this.dataFileHandler.flushAndSave();
}
}
@Override
public void close()
{
RenderState rs = this.renderState.get();
if (rs != null)
{
while (!this.renderState.compareAndSet(rs, null))
{
rs = this.renderState.get();
if (rs == null)
return;
}
rs.close().join(); //TODO: Make it async.
}
WorldGenState wgs = this.worldGenState.get();
if (wgs != null)
{
while (!this.worldGenState.compareAndSet(wgs, null))
{
wgs = this.worldGenState.get();
if (wgs == null)
return;
}
wgs.close(true).join(); //TODO: Make it async.
}
LOGGER.info("Closed {}", this);
}
@Override
public void doWorldGen()
{
WorldGenState wgs = this.worldGenState.get();
if (this.generatorEnabled.pollNewValue())
{
boolean shouldDoWorldGen = this.generatorEnabled.get() && this.renderState.get() != null;
if (shouldDoWorldGen && wgs == null)
{
WorldGenState newWgs = new WorldGenState();
if (!this.worldGenState.compareAndSet(null, newWgs))
{
LOGGER.warn("Failed to start world gen due to concurrency");
newWgs.close(false);
}
}
else if (!shouldDoWorldGen && wgs != null)
{
while (!this.worldGenState.compareAndSet(wgs, null))
{
wgs = this.worldGenState.get();
if (wgs == null)
return;
}
wgs.close(true).join(); //TODO: Make it async.
}
}
if (wgs != null)
{
wgs.batchGenerator.update();
wgs.generationQueue.pollAndStartClosest(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
}
}
@Override
public IServerLevelWrapper getServerLevelWrapper() { return this.serverLevel; }
//================//
// helper classes //
//================//
class RenderState
{
final IClientLevelWrapper clientLevel;
final LodQuadTree tree;
final RenderFileHandler renderFileHandler;
final RenderBufferHandler renderBufferHandler; //TODO: Should this be owned by renderer?
final LodRenderer renderer;
RenderState(IClientLevelWrapper clientLevel)
{
this.clientLevel = clientLevel;
this.renderFileHandler = new RenderFileHandler(dataFileHandler, DhClientServerLevel.this, save.getRenderCacheFolder(serverLevel));
this.tree = new LodQuadTree(DhClientServerLevel.this, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16,
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, this.renderFileHandler);
this.renderBufferHandler = new RenderBufferHandler(tree);
FileScanUtil.scanFile(save, serverLevel, null, this.renderFileHandler);
this.renderer = new LodRenderer(this.renderBufferHandler);
}
CompletableFuture<Void> close()
{
this.renderer.close();
this.renderBufferHandler.close();
this.tree.close();
return this.renderFileHandler.flushAndSave();
}
}
class WorldGenState
{
final BatchGenerator batchGenerator;
final GenerationQueue generationQueue;
WorldGenState()
{
this.batchGenerator = new BatchGenerator(DhClientServerLevel.this);
this.generationQueue = new GenerationQueue(this.batchGenerator);
dataFileHandler.setGenerationQueue(this.generationQueue);
}
CompletableFuture<Void> close(boolean doInterrupt)
{
dataFileHandler.popGenerationQueue();
return this.generationQueue.startClosing(true, doInterrupt)
.exceptionally(ex ->
{
LOGGER.error("Error closing generation queue", ex);
return null;
}).thenRun(this.batchGenerator::close)
.exceptionally(ex ->
{
LOGGER.error("Error closing world gen", ex);
return null;
});
}
}
}
@@ -13,63 +13,62 @@ import java.util.concurrent.CompletableFuture;
public class DhServerLevel implements IDhServerLevel
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public final LocalSaveStructure save;
public final DataFileHandler dataFileHandler;
public final IServerLevelWrapper level;
public DhServerLevel(LocalSaveStructure save, IServerLevelWrapper level) {
this.save = save;
this.level = level;
save.getDataFolder(level).mkdirs();
dataFileHandler = new DataFileHandler(this, save.getDataFolder(level)); //FIXME: GenerationQueue
FileScanUtil.scanFile(save, level, dataFileHandler, null);
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
}
public void serverTick() {
//Nothing for now
}
@Override
public int getMinY() {
return level.getMinHeight();
}
@Override
public void dumpRamUsage() {
//TODO
}
@Override
public void close() {
dataFileHandler.close();
LOGGER.info("Closed DHLevel for {}", level);
}
@Override
public CompletableFuture<Void> save() {
return dataFileHandler.flushAndSave();
}
@Override
public void doWorldGen() {
// FIXME: No world gen for server side only for now
}
@Override
public IServerLevelWrapper getServerLevelWrapper() {
return level;
}
@Override
public ILevelWrapper getLevelWrapper()
{
return this.level;
}
@Override
public void updateChunk(IChunkWrapper chunk) {
//TODO
}
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public final LocalSaveStructure save;
public final DataFileHandler dataFileHandler;
public final IServerLevelWrapper level;
public DhServerLevel(LocalSaveStructure save, IServerLevelWrapper level)
{
this.save = save;
this.level = level;
save.getDataFolder(level).mkdirs();
this.dataFileHandler = new DataFileHandler(this, save.getDataFolder(level)); //FIXME: GenerationQueue
FileScanUtil.scanFile(save, level, this.dataFileHandler, null);
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
}
public void serverTick()
{
//Nothing for now
}
@Override
public int getMinY() { return this.level.getMinHeight(); }
@Override
public void dumpRamUsage()
{
//TODO
}
@Override
public void close()
{
this.dataFileHandler.close();
LOGGER.info("Closed DHLevel for {}", this.level);
}
@Override
public CompletableFuture<Void> save() { return this.dataFileHandler.flushAndSave(); }
@Override
public void doWorldGen()
{
// FIXME: No world gen for server side only for now
}
@Override
public IServerLevelWrapper getServerLevelWrapper() { return this.level; }
@Override
public ILevelWrapper getLevelWrapper() { return this.level; }
@Override
public void updateChunk(IChunkWrapper chunk)
{
//TODO
}
}