From 4b5bfe6799eaaf4627d7ad812584bab8ce0a3d5c Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 11 Mar 2023 12:02:22 -0600 Subject: [PATCH] Fix the QuadTree not updating when new LODs are generated --- .../GeneratedFullDataFileHandler.java | 50 +++++++++++++++++-- .../lod/core/level/DhClientServerLevel.java | 17 ++++++- .../seibel/lod/core/render/LodQuadTree.java | 22 +++++--- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 3ffe4dc68..559fad90e 100644 --- a/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/lod/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -27,12 +27,18 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler private final AtomicReference worldGenQueueRef = new AtomicReference<>(null); + private final ArrayList onWorldGenTaskCompleteListeners = new ArrayList<>(); + public GeneratedFullDataFileHandler(IDhServerLevel level, File saveRootDir) { super(level, saveRootDir); } + //==================// + // generation queue // + //==================// + /** Assumes there isn't a pre-existing queue. */ public void setGenerationQueue(WorldGenerationQueue newWorldGenQueue) { @@ -44,6 +50,26 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler + //=================// + // event listeners // + //=================// + + public void addWorldGenCompleteListener(IOnWorldGenCompleteListener listener) + { + this.onWorldGenTaskCompleteListeners.add(listener); + } + + public void removeWorldGenCompleteListener(IOnWorldGenCompleteListener listener) + { + this.onWorldGenTaskCompleteListeners.remove(listener); + } + + + + //========// + // events // + //========// + @Override public CompletableFuture onCreateDataFile(FullDataMetaFile file) { @@ -115,8 +141,6 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler } } - - private void onWorldGenTaskComplete(Boolean genTaskCompleted, Throwable exception, GenTask genTask, DhSectionPos pos) { if (exception != null) @@ -131,6 +155,12 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler { this.files.get(genTask.pos).flushAndSave(); + // fire the event listeners + for (IOnWorldGenCompleteListener listener : this.onWorldGenTaskCompleteListeners) + { + listener.onWorldGenTaskComplete(genTask.pos); + } + // this.files.get(genTask.pos).metaData.dataVersion.incrementAndGet(); return; } @@ -140,9 +170,9 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler - //==============// - // helper class // - //==============// + //================// + // helper classes // + //================// private class GenTask implements IWorldGenTaskTracker { @@ -191,5 +221,15 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler } + /** + * used by external event listeners
+ * TODO may or may not be best to have this in a separate file + */ + @FunctionalInterface + public interface IOnWorldGenCompleteListener + { + /** Fired whenever a section has completed generating */ + void onWorldGenTaskComplete(DhSectionPos pos); + } } 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 65d8db9da..e12a8ff5a 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 @@ -11,6 +11,7 @@ import com.seibel.lod.core.generation.WorldGenerationQueue; import com.seibel.lod.core.file.fullDatafile.GeneratedFullDataFileHandler; import com.seibel.lod.core.level.states.ClientRenderState; import com.seibel.lod.core.logging.f3.F3Screen; +import com.seibel.lod.core.pos.DhSectionPos; import com.seibel.lod.core.util.FileScanUtil; import com.seibel.lod.core.pos.DhBlockPos2D; import com.seibel.lod.core.config.Config; @@ -28,7 +29,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; /** The level used on a singleplayer world */ -public class DhClientServerLevel extends AbstractDhClientLevel implements IDhClientLevel, IDhServerLevel +public class DhClientServerLevel extends AbstractDhClientLevel implements IDhClientLevel, IDhServerLevel, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); @@ -242,6 +243,17 @@ public class DhClientServerLevel extends AbstractDhClientLevel implements IDhCli } + @Override + public void onWorldGenTaskComplete(DhSectionPos pos) + { + ClientRenderState clientRenderState = this.ClientRenderStateRef.get(); + if (clientRenderState != null && clientRenderState.quadtree != null) + { + clientRenderState.quadtree.reloadPos(pos); + } + } + + //================// @@ -255,7 +267,7 @@ public class DhClientServerLevel extends AbstractDhClientLevel implements IDhCli - WorldGenState(IDhLevel level) + WorldGenState(DhClientServerLevel level) { IDhApiWorldGenerator worldGenerator = WorldGeneratorInjector.INSTANCE.get(level.getLevelWrapper()); if (worldGenerator == null) @@ -270,6 +282,7 @@ public class DhClientServerLevel extends AbstractDhClientLevel implements IDhCli this.worldGenerationQueue = new WorldGenerationQueue(this.chunkGenerator); DhClientServerLevel.this.generatedFullDataFileHandler.setGenerationQueue(this.worldGenerationQueue); + DhClientServerLevel.this.generatedFullDataFileHandler.addWorldGenCompleteListener(level); } diff --git a/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java index aaef7bcb8..d66dbbf00 100644 --- a/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java @@ -601,12 +601,6 @@ public class LodQuadTree implements AutoCloseable // load in the new section section.setRenderSourceProvider(this.renderSourceProvider); } - // unimplemented, would be needed for dedicated server support -// else if (section.isOutdated()) -// { -// // replace the out of date data -// section.reload(this.renderSourceProvider); -// } // enable rendering if this section is a leaf node in the tree, otherwise disable rendering @@ -728,6 +722,10 @@ public class LodQuadTree implements AutoCloseable + //=============// + // render data // + //=============// + /** * Re-creates the color, render data. * This method should be called after resource packs are changed or LOD settings are modified. @@ -754,6 +752,18 @@ public class LodQuadTree implements AutoCloseable LOGGER.info("Render cache invalidated"); } + /** + * Can be called whenever a render section's data needs to be refreshed.
+ * This should be called whenever a world generation task is completed or if the connected server has new data to show. + */ + public void reloadPos(DhSectionPos pos) + { + LodRenderSection renderSection = this.getSection(pos); + if (renderSection != null) + { + renderSection.reload(this.renderSourceProvider); + } + }