From 2cb044f4b585582a901320c80f9453ff6014b9cd Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 4 May 2023 07:31:35 -0500 Subject: [PATCH] Create new world gen tasks when moving into new areas --- .../sources/interfaces/IFullDataSource.java | 2 + .../GeneratedFullDataFileHandler.java | 82 +++++++++++++++---- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java index c0ebf9db1..0d58bdc0c 100644 --- a/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java +++ b/core/src/main/java/com/seibel/lod/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java @@ -61,6 +61,8 @@ public interface IFullDataSource FullDataPointIdMap getMapping(); + /** @return true if every datapoint in this object has been generated, false otherwise. */ + default boolean isCompletelyGenerated() { return this.getUngeneratedPosList().size() == 0; } /** @return the list of {@link DhSectionPos} that aren't generated in this data source. */ ArrayList getUngeneratedPosList(); 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 d92be93cb..7c237a3bd 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 @@ -30,12 +30,32 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler private final ArrayList onWorldGenTaskCompleteListeners = new ArrayList<>(); + /** + * Keeps track of which partially generated {@link IFullDataSource} {@link DhSectionPos}' are waiting to be generated. + * This is done to prevent sending duplicate generation requests for the same position. + */ + private final HashSet incompleteSourceGenRequests = new HashSet<>(); + public GeneratedFullDataFileHandler(IDhServerLevel level, File saveRootDir) { super(level, saveRootDir); } + //======// + // data // + //======// + + public CompletableFuture read(DhSectionPos pos) + { + return super.read(pos).whenComplete((fullDataSource, ex) -> + { + this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource); + }); + } + + + //==================// // generation queue // //==================// @@ -55,15 +75,8 @@ 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); - } + public void addWorldGenCompleteListener(IOnWorldGenCompleteListener listener) { this.onWorldGenTaskCompleteListeners.add(listener); } + public void removeWorldGenCompleteListener(IOnWorldGenCompleteListener listener) { this.onWorldGenTaskCompleteListeners.remove(listener); } @@ -126,22 +139,26 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler } } - LOGGER.debug("Creating {} from sampling {} files: {}", pos, existingFiles.size(), existingFiles); +// LOGGER.debug("Creating "+pos+" from sampling "+existingFiles.size()+" files: "+existingFiles); // read in the existing data final ArrayList> loadDataFutures = new ArrayList<>(existingFiles.size()); for (FullDataMetaFile existingFile : existingFiles) { loadDataFutures.add(existingFile.loadOrGetCachedAsync() - .exceptionally((ex) -> /*Ignore file read errors*/null) - .thenAccept((data) -> + .exceptionally((ex) -> /*Ignore file read errors*/null) + .thenAccept((fullDataSource) -> + { + if (fullDataSource == null) { - if (data != null) - { - //LOGGER.info("Merging data from {} into {}", data.getSectionPos(), pos); - incompleteFullDataSource.sampleFrom(data); - } - }) + return; + } + + this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource); + + //LOGGER.info("Merging data from {} into {}", data.getSectionPos(), pos); + incompleteFullDataSource.sampleFrom(fullDataSource); + }) ); } @@ -150,6 +167,34 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler } } + /** + * Checks if the given {@link IFullDataSource} is fully generated and + * if it isn't, new world gen request(s) will be created. + */ + private void checkIfSectionNeedsAdditionalGeneration(DhSectionPos pos, IFullDataSource fullDataSource) + { + if (!fullDataSource.isCompletelyGenerated() && !incompleteSourceGenRequests.contains(pos)) + { + WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + if (worldGenQueue != null) + { + incompleteSourceGenRequests.add(pos); + //LOGGER.info("["+ungeneratedPosList.size()+"] missing sub positions for pos: ["+pos+"]. Number of gen requests queued: ["+queuedGenRequests.size()+"]."); + + // note: this will potentially re-generate terrain, however due to the generator setup this is currently unavoidable and probably not worth worrying about + GenTask genTask = new GenTask(pos, new WeakReference<>(fullDataSource)); + worldGenQueue.submitGenTask(fullDataSource.getSectionPos().getSectionBBoxPos(), fullDataSource.getDataDetailLevel(), genTask) + .whenComplete((genTaskResult, ex) -> + { + incompleteSourceGenRequests.remove(pos); + //LOGGER.info("Partial generation completed for pos: ["+pos+"]. Remaining gen requests queued: ["+queuedGenRequests.size()+"]."); + + this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos); + }); + } + } + } + private void onWorldGenTaskComplete(WorldGenResult genTaskResult, Throwable exception, GenTask genTask, DhSectionPos pos) { if (exception != null) @@ -164,6 +209,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler { // generation completed, update the files and listener(s) +// LOGGER.info("gen task completed for pos: ["+pos+"]."); this.files.get(genTask.pos).flushAndSaveAsync(); // fire the event listeners