diff --git a/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java index c9f5b38a8..fa7b3e10c 100644 --- a/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java @@ -4,15 +4,13 @@ import com.seibel.lod.core.dataObjects.fullData.sources.ChunkSizedFullDataSource import com.seibel.lod.core.dataObjects.fullData.sources.FullDataSource; import com.seibel.lod.core.dataObjects.transformers.ChunkToLodBuilder; import com.seibel.lod.core.file.fullDatafile.IFullDataSourceProvider; -import com.seibel.lod.core.file.renderfile.RenderSourceFileHandler; import com.seibel.lod.core.level.states.ClientRenderState; +import com.seibel.lod.core.logging.f3.F3Screen; import com.seibel.lod.core.pos.DhLodPos; import com.seibel.lod.core.pos.DhSectionPos; -import com.seibel.lod.core.render.LodQuadTree; import com.seibel.lod.core.util.FileScanUtil; import com.seibel.lod.core.file.fullDatafile.RemoteFullDataFileHandler; import com.seibel.lod.core.pos.DhBlockPos2D; -import com.seibel.lod.core.render.RenderBufferHandler; import com.seibel.lod.core.file.structure.ClientOnlySaveStructure; import com.seibel.lod.core.config.Config; import com.seibel.lod.core.dependencyInjection.SingletonInjector; @@ -20,7 +18,6 @@ import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.pos.DhBlockPos; import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.math.Mat4f; -import com.seibel.lod.core.render.renderer.LodRenderer; import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; @@ -37,36 +34,69 @@ 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 saveStructure; - public final RemoteFullDataFileHandler dataFileHandler; - public final ChunkToLodBuilder chunkToLodBuilder = new ChunkToLodBuilder();; - public final IClientLevelWrapper level; + public final RemoteFullDataFileHandler fullDataFileHandler; + public final ChunkToLodBuilder chunkToLodBuilder; + public final IClientLevelWrapper clientLevel; + public F3Screen.NestedMessage f3Message; public final AtomicReference ClientRenderStateRef = new AtomicReference<>(); - public DhClientLevel(ClientOnlySaveStructure saveStructure, IClientLevelWrapper level) + public DhClientLevel(ClientOnlySaveStructure saveStructure, IClientLevelWrapper clientLevel) { + this.clientLevel = clientLevel; + this.saveStructure = saveStructure; + saveStructure.getDataFolder(clientLevel).mkdirs(); + saveStructure.getRenderCacheFolder(clientLevel).mkdirs(); - saveStructure.getDataFolder(level).mkdirs(); - saveStructure.getRenderCacheFolder(level).mkdirs(); - this.dataFileHandler = new RemoteFullDataFileHandler(this, saveStructure.getDataFolder(level)); + this.fullDataFileHandler = new RemoteFullDataFileHandler(this, saveStructure.getDataFolder(clientLevel)); + FileScanUtil.scanFiles(saveStructure, clientLevel, this.fullDataFileHandler, null); - this.level = level; - FileScanUtil.scanFiles(saveStructure, level, this.dataFileHandler, null); - LOGGER.info("Started DHLevel for "+level+" with saves at "+ saveStructure); + this.f3Message = new F3Screen.NestedMessage(this::f3Log); + this.chunkToLodBuilder = new ChunkToLodBuilder(); + + + LOGGER.info("Started DHLevel for "+clientLevel+" with saves at "+saveStructure); } + //=======================// + // misc helper functions // + //=======================// + + /** Returns what should be displayed in Minecraft's F3 debug menu */ + private String[] f3Log() + { + ClientRenderState rs = this.ClientRenderStateRef.get(); + if (rs == null) + { + return new String[] { LodUtil.formatLog("level @ {}: Inactive", this.clientLevel.getDimensionType().getDimensionName()) }; + } + else + { + return new String[] { + LodUtil.formatLog("level @ {}: Active", this.clientLevel.getDimensionType().getDimensionName()) + }; + } + } + @Override public void dumpRamUsage() { //TODO } + + + //==============// + // tick methods // + //==============// + @Override public void clientTick() { @@ -102,6 +132,11 @@ public class DhClientLevel implements IDhClientLevel } + + //========// + // render // + //========// + public void startRenderer(IClientLevelWrapper clientLevel) { LOGGER.info("Starting renderer for "+this); @@ -148,28 +183,45 @@ public class DhClientLevel implements IDhClientLevel } - @Override - public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) { return 0; /* TODO */ } + + + //================// + // level handling // + //================// @Override - public IClientLevelWrapper getClientLevelWrapper() { return this.level; } - - @Override - public ILevelWrapper getLevelWrapper() { return this.level; } - - @Override - public IFullDataSourceProvider getFileHandler() { return this.dataFileHandler; } - - @Override - public void clearRenderDataCache() + public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) { - ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); - if (ClientRenderState != null && ClientRenderState.quadtree != null) + IClientLevelWrapper clientLevel = this.getClientLevelWrapper(); + if (clientLevel == null) { - ClientRenderState.quadtree.clearRenderDataCache(); + return 0; + } + else + { + return clientLevel.computeBaseColor(pos, biome, block); } } + @Override + public IClientLevelWrapper getClientLevelWrapper() + { + ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); + return ClientRenderState == null ? null : ClientRenderState.clientLevel; + } + + @Override + public ILevelWrapper getLevelWrapper() { return this.clientLevel; } + + @Override + public int getMinY() { return this.clientLevel.getMinHeight(); } + + + + //===============// + // data handling // + //===============// + @Override public void updateChunkAsync(IChunkWrapper chunk) { @@ -189,27 +241,26 @@ public class DhClientLevel implements IDhClientLevel } else { - this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); + this.fullDataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); } } - @Override - public int getMinY() { return this.level.getMinHeight(); } - @Override public CompletableFuture saveAsync() { ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); if (ClientRenderState != null) { - return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.dataFileHandler.flushAndSave(), (voidA, voidB) -> null); + return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.fullDataFileHandler.flushAndSave(), (voidA, voidB) -> null); } else { - return this.dataFileHandler.flushAndSave(); + return this.fullDataFileHandler.flushAndSave(); } } + + @Override public void close() { @@ -227,7 +278,22 @@ public class DhClientLevel implements IDhClientLevel ClientRenderState.closeAsync().join(); //TODO: Make this async. } - LOGGER.info("Closed DHLevel for "+this.level); + LOGGER.info("Closed DHLevel for "+this.clientLevel); } + + @Override + public IFullDataSourceProvider getFileHandler() { return this.fullDataFileHandler; } + + @Override + public void clearRenderDataCache() + { + ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); + if (ClientRenderState != null && ClientRenderState.quadtree != null) + { + ClientRenderState.quadtree.clearRenderDataCache(); + } + } + + } diff --git a/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java index 4b3ef1358..53ee8ff90 100644 --- a/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java +++ b/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java @@ -43,10 +43,10 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); public final LocalSaveStructure saveStructure; - public final GeneratedFullDataFileHandler dataFileHandler; + public final GeneratedFullDataFileHandler fullDataFileHandler; public final ChunkToLodBuilder chunkToLodBuilder; public final IServerLevelWrapper serverLevel; - private final AppliedConfigState generatorEnabled; + private final AppliedConfigState worldGeneratorEnabledConfig; public F3Screen.NestedMessage f3Message; private final AtomicReference ClientRenderStateRef = new AtomicReference<>(); @@ -54,25 +54,32 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel - public DhClientServerLevel(LocalSaveStructure saveStructure, IServerLevelWrapper level) + public DhClientServerLevel(LocalSaveStructure saveStructure, IServerLevelWrapper serverLevel) { - this.serverLevel = level; + this.serverLevel = serverLevel; this.saveStructure = saveStructure; - saveStructure.getDataFolder(level).mkdirs(); - saveStructure.getRenderCacheFolder(level).mkdirs(); + saveStructure.getDataFolder(serverLevel).mkdirs(); + saveStructure.getRenderCacheFolder(serverLevel).mkdirs(); - this.dataFileHandler = new GeneratedFullDataFileHandler(this, saveStructure.getDataFolder(level)); - FileScanUtil.scanFiles(saveStructure, this.serverLevel, this.dataFileHandler, null); + this.fullDataFileHandler = new GeneratedFullDataFileHandler(this, saveStructure.getDataFolder(serverLevel)); + FileScanUtil.scanFiles(saveStructure, this.serverLevel, this.fullDataFileHandler, null); - LOGGER.info("Started DHLevel for "+level+" with saves at "+saveStructure); this.f3Message = new F3Screen.NestedMessage(this::f3Log); this.chunkToLodBuilder = new ChunkToLodBuilder(); - this.generatorEnabled = new AppliedConfigState<>(Config.Client.WorldGenerator.enableDistantGeneration); + + this.worldGeneratorEnabledConfig = new AppliedConfigState<>(Config.Client.WorldGenerator.enableDistantGeneration); + + + LOGGER.info("Started DHLevel for "+serverLevel+" with saves at "+saveStructure); } + //=======================// + // misc helper functions // + //=======================// + /** Returns what should be displayed in Minecraft's F3 debug menu */ private String[] f3Log() { @@ -89,6 +96,18 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel } } + @Override + public void dumpRamUsage() + { + //TODO + } + + + + //==============// + // tick methods // + //==============// + @Override public void clientTick() { @@ -124,6 +143,55 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel @Override public void serverTick() { this.chunkToLodBuilder.tick(); } + @Override + public void doWorldGen() + { + WorldGenState wgs = this.worldGenStateRef.get(); + + // if the world generator config changes, add/remove the world generator + if (this.worldGeneratorEnabledConfig.pollNewValue()) + { + boolean shouldDoWorldGen = this.worldGeneratorEnabledConfig.get() && this.ClientRenderStateRef.get() != null; + if (shouldDoWorldGen && wgs == null) + { + // create the new world generator + WorldGenState newWgs = new WorldGenState(this); + if (!this.worldGenStateRef.compareAndSet(null, newWgs)) + { + LOGGER.warn("Failed to start world gen due to concurrency"); + newWgs.closeAsync(false); + } + } + else if (!shouldDoWorldGen && wgs != null) + { + // shut down the world generator + while (!this.worldGenStateRef.compareAndSet(wgs, null)) + { + wgs = this.worldGenStateRef.get(); + if (wgs == null) + { + return; + } + } + wgs.closeAsync(true).join(); //TODO: Make it async. + } + } + + + if (wgs != null) + { + // queue new world generation requests + wgs.chunkGenerator.preGeneratorTaskStart(); + wgs.worldGenerationQueue.runCurrentGenTasksUntilBusy(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos())); + } + } + + + + //========// + // render // + //========// + public void startRenderer(IClientLevelWrapper clientLevel) { LOGGER.info("Starting renderer for "+this); @@ -135,8 +203,8 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel } else { - this.generatorEnabled.pollNewValue(); - if (this.generatorEnabled.get() && this.worldGenStateRef.get() == null) + this.worldGeneratorEnabledConfig.pollNewValue(); + if (this.worldGeneratorEnabledConfig.get() && this.worldGenStateRef.get() == null) { WorldGenState worldGenState = new WorldGenState(this); if (!this.worldGenStateRef.compareAndSet(null, worldGenState)) @@ -198,7 +266,13 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel } } - @Override //FIXME + + + //================// + // level handling // + //================// + + @Override //FIXME // why is this labeled "fixme"? public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) { IClientLevelWrapper clientLevel = this.getClientLevelWrapper(); @@ -218,10 +292,21 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); return ClientRenderState == null ? null : ClientRenderState.clientLevel; } + @Override + public IServerLevelWrapper getServerLevelWrapper() { return this.serverLevel; } @Override public ILevelWrapper getLevelWrapper() { return this.serverLevel; } + @Override + public int getMinY() { return this.serverLevel.getMinHeight(); } + + + + //===============// + // data handling // + //===============// + @Override public void updateChunkAsync(IChunkWrapper chunk) { @@ -241,30 +326,21 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel } else { - this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); + this.fullDataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); } } - @Override - public void dumpRamUsage() - { - //TODO - } - - @Override - public int getMinY() { return this.serverLevel.getMinHeight(); } - @Override public CompletableFuture saveAsync() { ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); if (ClientRenderState != null) { - return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.dataFileHandler.flushAndSave(), (voidA, voidB) -> null); + return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.fullDataFileHandler.flushAndSave(), (voidA, voidB) -> null); } else { - return this.dataFileHandler.flushAndSave(); + return this.fullDataFileHandler.flushAndSave(); } } @@ -304,53 +380,7 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel @Override - public void doWorldGen() - { - WorldGenState wgs = this.worldGenStateRef.get(); - - // if the world generator config changes, add/remove the world generator - if (this.generatorEnabled.pollNewValue()) - { - boolean shouldDoWorldGen = this.generatorEnabled.get() && this.ClientRenderStateRef.get() != null; - if (shouldDoWorldGen && wgs == null) - { - // create the new world generator - WorldGenState newWgs = new WorldGenState(this); - if (!this.worldGenStateRef.compareAndSet(null, newWgs)) - { - LOGGER.warn("Failed to start world gen due to concurrency"); - newWgs.closeAsync(false); - } - } - else if (!shouldDoWorldGen && wgs != null) - { - // shut down the world generator - while (!this.worldGenStateRef.compareAndSet(wgs, null)) - { - wgs = this.worldGenStateRef.get(); - if (wgs == null) - { - return; - } - } - wgs.closeAsync(true).join(); //TODO: Make it async. - } - } - - - if (wgs != null) - { - // queue new world generation requests - wgs.chunkGenerator.preGeneratorTaskStart(); - wgs.worldGenerationQueue.runCurrentGenTasksUntilBusy(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos())); - } - } - - @Override - public IServerLevelWrapper getServerLevelWrapper() { return this.serverLevel; } - - @Override - public IFullDataSourceProvider getFileHandler() { return this.dataFileHandler; } + public IFullDataSourceProvider getFileHandler() { return this.fullDataFileHandler; } @Override public void clearRenderDataCache() @@ -390,14 +420,14 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel this.chunkGenerator = worldGenerator; this.worldGenerationQueue = new WorldGenerationQueue(this.chunkGenerator); - DhClientServerLevel.this.dataFileHandler.setGenerationQueue(this.worldGenerationQueue); + DhClientServerLevel.this.fullDataFileHandler.setGenerationQueue(this.worldGenerationQueue); } CompletableFuture closeAsync(boolean doInterrupt) { - DhClientServerLevel.this.dataFileHandler.clearGenerationQueue(); + DhClientServerLevel.this.fullDataFileHandler.clearGenerationQueue(); return this.worldGenerationQueue.startClosing(true, doInterrupt) .exceptionally(ex -> { diff --git a/core/src/main/java/com/seibel/lod/core/level/states/ClientRenderState.java b/core/src/main/java/com/seibel/lod/core/level/states/ClientRenderState.java index e2246b403..3a921fb82 100644 --- a/core/src/main/java/com/seibel/lod/core/level/states/ClientRenderState.java +++ b/core/src/main/java/com/seibel/lod/core/level/states/ClientRenderState.java @@ -32,7 +32,7 @@ public class ClientRenderState public ClientRenderState(DhClientServerLevel parent, IClientLevelWrapper clientLevel) { this.clientLevel = clientLevel; - this.renderSourceFileHandler = new RenderSourceFileHandler(parent.dataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.serverLevel)); + this.renderSourceFileHandler = new RenderSourceFileHandler(parent.fullDataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.serverLevel)); this.quadtree = new LodQuadTree(parent, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH, MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, this.renderSourceFileHandler); @@ -44,13 +44,13 @@ public class ClientRenderState public ClientRenderState(DhClientLevel parent, IClientLevelWrapper clientLevel) { this.clientLevel = clientLevel; - this.renderSourceFileHandler = new RenderSourceFileHandler(parent.dataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.level)); + this.renderSourceFileHandler = new RenderSourceFileHandler(parent.fullDataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.clientLevel)); this.quadtree = new LodQuadTree(parent, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH, MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, this.renderSourceFileHandler); RenderBufferHandler renderBufferHandler = new RenderBufferHandler(this.quadtree); - FileScanUtil.scanFiles(parent.saveStructure, parent.level, null, this.renderSourceFileHandler); + FileScanUtil.scanFiles(parent.saveStructure, parent.clientLevel, null, this.renderSourceFileHandler); this.renderer = new LodRenderer(renderBufferHandler); } diff --git a/core/src/main/java/com/seibel/lod/core/world/DhClientServerWorld.java b/core/src/main/java/com/seibel/lod/core/world/DhClientServerWorld.java index 18dfa9feb..b26da0712 100644 --- a/core/src/main/java/com/seibel/lod/core/world/DhClientServerWorld.java +++ b/core/src/main/java/com/seibel/lod/core/world/DhClientServerWorld.java @@ -97,6 +97,7 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor } else { + // TODO why is this called here? this.levelObjMap.remove(wrapper).stopRenderer(); // Ignore resource warning. The level obj is referenced elsewhere. } } diff --git a/core/src/main/java/com/seibel/lod/core/world/DhClientWorld.java b/core/src/main/java/com/seibel/lod/core/world/DhClientWorld.java index 00dd7d5b3..1ed5a10df 100644 --- a/core/src/main/java/com/seibel/lod/core/world/DhClientWorld.java +++ b/core/src/main/java/com/seibel/lod/core/world/DhClientWorld.java @@ -121,7 +121,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld this.saveAndFlush().join(); for (DhClientLevel level : this.levels.values()) { - LOGGER.info("Unloading level " + level.level.getDimensionType().getDimensionName()); + LOGGER.info("Unloading level " + level.clientLevel.getDimensionType().getDimensionName()); level.close(); }