From 2c6f2717f01612faad6d02705abcc931a3f2dba4 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 27 Sep 2023 07:53:32 -0500 Subject: [PATCH 1/5] Fix partially generated sections not queuing world gen tasks (Most of the time) --- .../fullDatafile/FullDataFileHandler.java | 2 +- .../GeneratedFullDataFileHandler.java | 175 +++++++++++------- .../fullDatafile/IFullDataSourceProvider.java | 3 + .../file/renderfile/RenderDataMetaFile.java | 3 + .../generation/IWorldGenerationQueue.java | 2 + .../core/generation/WorldGenerationQueue.java | 10 +- 6 files changed, 125 insertions(+), 70 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java index fd2236665..d580cc217 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java @@ -54,7 +54,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider protected static ExecutorService fileHandlerThreadPool; protected static ConfigChangeListener configListener; - private final ConcurrentHashMap loadedMetaFileBySectionPos = new ConcurrentHashMap<>(); + protected final ConcurrentHashMap loadedMetaFileBySectionPos = new ConcurrentHashMap<>(); protected final IDhLevel level; protected final File saveDir; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 28a343e33..291415cbc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -57,26 +57,78 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler + //===========// + // overrides // + //===========// + + @Override + public CompletableFuture readAsync(DhSectionPos pos) + { + CompletableFuture future = super.readAsync(pos); + return future.thenApply((dataSource) -> + { + // add world gen tasks for missing columns in the data source + IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + FullDataMetaFile metaFile = this.loadedMetaFileBySectionPos.get(pos); + if (worldGenQueue != null && metaFile != null) + { + this.queueWorldGenForMissingColumnsInDataSource(worldGenQueue, metaFile, dataSource); + } + + return dataSource; + }); + } + + @Override + public void onRenderDataFileLoaded(DhSectionPos pos) + { + // add world gen tasks for missing columns in the data source + IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + FullDataMetaFile metaFile = this.getLoadOrMakeFile(pos, false); + if (worldGenQueue != null && metaFile != null) + { + metaFile.getDataSourceWithoutCachingAsync().thenApply((fullDataSource) -> + { + this.queueWorldGenForMissingColumnsInDataSource(worldGenQueue, metaFile, fullDataSource); + return fullDataSource; + }); + } + } + + + //==================// // generation queue // //==================// - /** Assumes there isn't a pre-existing queue. */ - public void setGenerationQueue(IWorldGenerationQueue newWorldGenQueue) + /** + * Assigns the queue for handling world gen and does first time setup as well.
+ * Assumes there isn't a pre-existing queue. + */ { boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue); LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!"); - LOGGER.info("Set world gen queue for level {} to start.", this.level); - this.ForEachFile(metaFile -> { - IFullDataSource data = metaFile.getCachedDataSourceNowOrNull(); - if (data instanceof CompleteFullDataSource) return; - metaFile.genQueueChecked = false; // unset it so it can be checked again - if (data != null) + LOGGER.info("Set world gen queue for level "+this.level+" to start."); + + this.ForEachFile(metaFile -> + { + IFullDataSource dataSource = metaFile.getCachedDataSourceNowOrNull(); + if (dataSource == null) { - metaFile.markNeedsUpdate(); + return; } + + metaFile.genQueueChecked = false; // allow the system to check for missing positions again + this.queueWorldGenForMissingColumnsInDataSource(this.worldGenQueueRef.get(), metaFile, dataSource); + + if (dataSource instanceof CompleteFullDataSource) + { + return; + } + metaFile.markNeedsUpdate(); }); - flushAndSave(); // Trigger an update to the meta files + + this.flushAndSave(); // Trigger an update to the meta files } public void clearGenerationQueue() @@ -96,6 +148,8 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler }); } + + //=================// // event listeners // //=================// @@ -114,60 +168,12 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler return newSource; } + + //========// // events // //========// - @Nullable - private CompletableFuture tryStartGenTask(FullDataMetaFile file, IIncompleteFullDataSource dataSource) // TODO after generation is finished, save and free any full datasources that aren't in use (IE high detail ones below the top) - { - IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); - // breaks down the missing positions into the desired detail level that the gen queue could accept - if (worldGenQueue != null && !file.genQueueChecked) - { - DhSectionPos pos = file.pos; - file.genQueueChecked = true; - byte maxSectDataDetailLevel = worldGenQueue.largestDataDetail(); - byte targetDataDetailLevel = dataSource.getDataDetailLevel(); - - if (targetDataDetailLevel > maxSectDataDetailLevel) - { - ArrayList existingFiles = new ArrayList<>(); - byte sectDetailLevel = (byte) (DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL + maxSectDataDetailLevel); - pos.forEachChildAtLevel(sectDetailLevel, childPos -> existingFiles.add(this.getLoadOrMakeFile(childPos, true))); - return this.sampleFromFileArray(dataSource, existingFiles, true).thenApply(this::tryPromoteDataSource) - .exceptionally((ex) -> - { - FullDataMetaFile newMetaFile = this.removeCorruptedFile(pos, file, ex); - return null; - }); - } - else - { - this.incompleteDataSources.put(pos, dataSource); - // queue this section to be generated - GenTask genTask = new GenTask(pos, new WeakReference<>(dataSource)); - worldGenQueue.submitGenTask(pos, dataSource.getDataDetailLevel(), genTask) - .whenComplete((genTaskResult, ex) -> - { - if (genTaskResult.success) - { - this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos); - this.fireOnGenPosSuccessListeners(pos); - } - else - { - file.genQueueChecked = false; - } - this.incompleteDataSources.remove(pos); - }); - } - // return the empty dataSource (it will be populated later) - return CompletableFuture.completedFuture(dataSource); - } - return null; - } - // Try update the gen queue on this data source. If null, then nothing was done. @Nullable private CompletableFuture updateFromExistingDataSourcesAsync(FullDataMetaFile file, IIncompleteFullDataSource data, boolean usePooledDataSources) @@ -195,6 +201,17 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler }); } } + @Nullable + private CompletableFuture tryStartGenTask(FullDataMetaFile metaFile, IIncompleteFullDataSource dataSource) // TODO after generation is finished, save and free any full datasources that aren't in use (IE high detail ones below the top) + { + IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get(); + if (worldGenQueue != null) + { + this.queueWorldGenForMissingColumnsInDataSource(worldGenQueue, metaFile, dataSource); + return CompletableFuture.completedFuture(dataSource); + } + return null; + } @Override public CompletableFuture onDataFileCreatedAsync(FullDataMetaFile file) @@ -305,6 +322,38 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler + //================// + // helper methods // + //================// + + private void queueWorldGenForMissingColumnsInDataSource(IWorldGenerationQueue worldGenQueue, FullDataMetaFile metaFile, IFullDataSource dataSource) + { + // Due to a bug in the current system, some Complete data sources aren't actually complete + // and will need additional generation to finish + //if (dataSource instanceof CompleteFullDataSource) + //{ + // return; + //} + + if (metaFile.genQueueChecked) + { + // world gen has already been checked for this file + return; + } + metaFile.genQueueChecked = true; + + byte minGeneratorSectionDetailLevel = (byte) (worldGenQueue.smallestDataDetail() + DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); + ArrayList genPosList = dataSource.getUngeneratedPosList(minGeneratorSectionDetailLevel, true); + + for (DhSectionPos genPos : genPosList) + { + GenTask genTask = new GenTask(dataSource.getSectionPos(), new WeakReference<>(dataSource)); + worldGenQueue.submitGenTask(genPos, dataSource.getSectionPos().getDetailLevel(), genTask); + } + } + + + //================// // helper classes // //================// @@ -329,11 +378,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler @Override - public boolean isMemoryAddressValid() - { - IFullDataSource ref = this.targetFullDataSourceRef.get(); - return ref != null && !((IIncompleteFullDataSource) ref).hasBeenPromoted(); - } + public boolean isMemoryAddressValid() { return this.targetFullDataSourceRef.get() != null; } @Override public Consumer getChunkDataConsumer() diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/IFullDataSourceProvider.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/IFullDataSourceProvider.java index 679b6ed64..9d8c9f94d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/IFullDataSourceProvider.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/IFullDataSourceProvider.java @@ -41,6 +41,9 @@ public interface IFullDataSourceProvider extends AutoCloseable CompletableFuture onDataFileCreatedAsync(FullDataMetaFile file); default CompletableFuture onDataFileUpdateAsync(IFullDataSource fullDataSource, FullDataMetaFile file, boolean dataChanged) { return CompletableFuture.completedFuture(new DataFileUpdateResult(fullDataSource, dataChanged)); } + /** Can be used to update world gen queues or run any other data checking necessary when initially loading a file */ + default void onRenderDataFileLoaded(DhSectionPos pos) { } + File computeDataFilePath(DhSectionPos pos); ExecutorService getIOExecutor(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java index 71ab713a8..b374d7af2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java @@ -125,6 +125,9 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements LodUtil.assertTrue(this.baseMetaData != null); this.doesFileExist = this.file.exists(); DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showRenderDataFileStatus); + + // handles world gen queuing for missing columns + this.fullDataSourceProvider.onRenderDataFileLoaded(this.baseMetaData.pos); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java index 352082edd..c1df7c170 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java @@ -31,6 +31,8 @@ public interface IWorldGenerationQueue extends Closeable { /** the largest numerical detail level */ byte largestDataDetail(); + /** the smallest numerical detail level */ + byte smallestDataDetail(); CompletableFuture submitGenTask(DhSectionPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker); void cancelGenTasks(Iterable positions); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java index 6e67176b4..92b8f1947 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java @@ -70,8 +70,12 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender public final byte largestDataDetail; @Override public byte largestDataDetail() { return this.largestDataDetail; } + /** lowest numerical detail level allowed */ public final byte smallestDataDetail; + @Override + public byte smallestDataDetail() { return this.smallestDataDetail; } + /** If not null this generator is in the process of shutting down */ private volatile CompletableFuture generatorClosingFuture = null; @@ -302,7 +306,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender // the newly selected task, we cannot use it, // as some chunks may have already been written into. - LOGGER.warn("A task already exists for this position, todo: {}", closestTask.pos); + LOGGER.trace("A task already exists for this position, todo: "+closestTask.pos); } // a task has been started @@ -348,9 +352,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender if (this.alreadyGeneratedPosHashSet.containsKey(inProgressTaskGroup.group.pos)) { // temporary solution to prevent generating the same section multiple times - LOGGER.warn("Duplicate generation section " + taskPos + " with granularity [" + granularity + "] at " + chunkPosMin + ". Skipping..."); - - //StackTraceElement[] stackTrace = this.alreadyGeneratedPosHashSet.get(inProgressTaskGroup.group.pos); + LOGGER.trace("Duplicate generation section " + taskPos + " with granularity [" + granularity + "] at " + chunkPosMin + ". Skipping..."); // sending a success result is necessary to make sure the render sections are reloaded correctly inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos.getX(), taskPos.getZ())))); From 42d80cbe34684456b7a56e27bf4bfa5107320bf3 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 27 Sep 2023 07:54:05 -0500 Subject: [PATCH 2/5] minor world gen method renaming --- .../core/file/fullDatafile/GeneratedFullDataFileHandler.java | 1 + .../distanthorizons/core/generation/tasks/WorldGenTask.java | 5 +---- .../seibel/distanthorizons/core/level/WorldGenModule.java | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 291415cbc..65127c8ab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -105,6 +105,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler * Assigns the queue for handling world gen and does first time setup as well.
* Assumes there isn't a pre-existing queue. */ + public void setWorldGenerationQueue(IWorldGenerationQueue newWorldGenQueue) { boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue); LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!"); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/WorldGenTask.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/WorldGenTask.java index fbb12f4bc..c9f52c617 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/WorldGenTask.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/tasks/WorldGenTask.java @@ -45,9 +45,6 @@ public final class WorldGenTask this.future = future; } - public boolean StillValid() - { - return taskTracker.isMemoryAddressValid(); - } + public boolean StillValid() { return this.taskTracker.isMemoryAddressValid(); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java index 2a6e8ac71..5b274857f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java @@ -79,7 +79,7 @@ public class WorldGenModule implements Closeable newWgs.closeAsync(false); } dataFileHandler.addWorldGenCompleteListener(this.onWorldGenCompleteListener); - dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue); + dataFileHandler.setWorldGenerationQueue(newWgs.worldGenerationQueue); } public void stopWorldGen(GeneratedFullDataFileHandler dataFileHandler) From e6a5a65f211cb17e1d96091dcb50068862b1b39b Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 28 Sep 2023 07:11:24 -0500 Subject: [PATCH 3/5] minor world gen refactoring --- .../sources/interfaces/IFullDataSource.java | 206 +++++++++--------- .../file/fullDatafile/FullDataMetaFile.java | 2 +- .../core/generation/WorldGenerationQueue.java | 20 +- 3 files changed, 105 insertions(+), 123 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java index ebcb807e4..28e04c995 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java @@ -94,24 +94,31 @@ public interface IFullDataSource FullDataPointIdMap getMapping(); /** - * @param highestGeneratorDetailLevel the smallest numerical detail level that the un-generated positions should be split into + * @param generatorDetailLevel the detail level that the un-generated positions should be split into. + * @param onlyReturnPositionsTheGeneratorCanAccept + * If true this will only return positions with the same detail level as generatorDetailLevel.
+ * If false this will return the lowest detail level possible for totally empty sections.
+ * As of 2023-9-28 both have been tested and confirmed working with the Batch world generator, the only difference is that + * the task list will be deceptively small if this value is false. + * * @return the list of {@link DhSectionPos} that aren't generated in this data source. */ - default ArrayList getUngeneratedPosList(byte highestGeneratorDetailLevel, boolean onlyReturnPositionsTheGeneratorCanAccept) + default ArrayList getUngeneratedPosList(byte generatorDetailLevel, boolean onlyReturnPositionsTheGeneratorCanAccept) { - ArrayList posArray = this.getUngeneratedPosList(this.getSectionPos(), highestGeneratorDetailLevel); + ArrayList posArray = this.getUngeneratedPosListForQuadrant(this.getSectionPos(), generatorDetailLevel); if (onlyReturnPositionsTheGeneratorCanAccept) { LinkedList posList = new LinkedList<>(posArray); + // subdivide positions until they match the generatorDetailLevel ArrayList cleanedPosArray = new ArrayList<>(); while (posList.size() > 0) { DhSectionPos pos = posList.remove(); - if (pos.getDetailLevel() > highestGeneratorDetailLevel) + if (pos.getDetailLevel() > generatorDetailLevel) { - pos.forEachChild((childPos) -> { posList.push(childPos); }); + pos.forEachChild((childPos) -> posList.push(childPos)); } else { @@ -126,142 +133,131 @@ public interface IFullDataSource return posArray; } } - default ArrayList getUngeneratedPosList(DhSectionPos quadrantPos, byte highestGeneratorDetailLevel) + default ArrayList getUngeneratedPosListForQuadrant(DhSectionPos quadrantPos, byte generatorDetailLevel) { ArrayList ungeneratedPosList = new ArrayList<>(); - int sourceRelWidth = this.getWidthInDataPoints(); + int sourceRelWidthInDataPoints = this.getWidthInDataPoints(); - if (quadrantPos.getDetailLevel() < highestGeneratorDetailLevel) - { - throw new IllegalArgumentException("detail level lower than world generator can accept."); - } - else if (quadrantPos.getDetailLevel() == highestGeneratorDetailLevel) + if (quadrantPos.getDetailLevel() == generatorDetailLevel) { // we are at the highest detail level the world generator can accept, // we either need to generate this whole section, or not at all - // TODO combine duplicate code - - byte childDetailLevel = (byte) (quadrantPos.getDetailLevel()); - - int quadrantDetailLevelDiff = this.getSectionPos().getDetailLevel() - childDetailLevel; - int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); - int relWidthForSecPos = sourceRelWidth / widthInSecPos; - - DhSectionPos minSecPos = this.getSectionPos().convertNewToDetailLevel(childDetailLevel); - DhSectionPos inputPos = quadrantPos; - - - - int minRelX = inputPos.getX() - minSecPos.getX(); - int minRelZ = inputPos.getZ() - minSecPos.getZ(); - int maxRelX = minRelX + 1; - int maxRelZ = minRelZ + 1; - - minRelX = minRelX * relWidthForSecPos; - minRelZ = minRelZ * relWidthForSecPos; - maxRelX = maxRelX * relWidthForSecPos; - maxRelZ = maxRelZ * relWidthForSecPos; - - - boolean quadrantFullyGenerated = true; - for (int relX = minRelX; relX < maxRelX; relX++) - { - for (int relZ = minRelZ; relZ < maxRelZ; relZ++) - { - SingleColumnFullDataAccessor column = this.tryGet(relX, relZ); - if (column == null || !column.doesColumnExist()) - { - // no data for this relative position - quadrantFullyGenerated = false; - break; - } - } - } - - if (!quadrantFullyGenerated) + ESectionPopulationState populationState = this.getPopulationStateForPos(quadrantPos, sourceRelWidthInDataPoints); + if (populationState != ESectionPopulationState.COMPLETE) { // at least 1 data point is missing, - // this whole section must be regenerated + // this whole section must be generated ungeneratedPosList.add(quadrantPos); } } - else + else if (quadrantPos.getDetailLevel() > generatorDetailLevel) { - // TODO comment - // TODO combine duplicate code - - byte childDetailLevel = (byte) (quadrantPos.getDetailLevel() - 1); - + // detail level too low for world generator, check child positions for (int i = 0; i < 4; i++) { - int quadrantDetailLevelDiff = this.getSectionPos().getDetailLevel() - childDetailLevel; - int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); - int relWidthForSecPos = sourceRelWidth / widthInSecPos; - - DhSectionPos minSecPos = this.getSectionPos().convertNewToDetailLevel(childDetailLevel); DhSectionPos inputPos = quadrantPos.getChildByIndex(i); - - - int minRelX = inputPos.getX() - minSecPos.getX(); - int minRelZ = inputPos.getZ() - minSecPos.getZ(); - int maxRelX = minRelX + 1; - int maxRelZ = minRelZ + 1; - - minRelX = minRelX * relWidthForSecPos; - minRelZ = minRelZ * relWidthForSecPos; - maxRelX = maxRelX * relWidthForSecPos; - maxRelZ = maxRelZ * relWidthForSecPos; - - - - boolean quadrantFullyGenerated = true; - boolean quadrantEmpty = true; - for (int relX = minRelX; relX < maxRelX; relX++) - { - for (int relZ = minRelZ; relZ < maxRelZ; relZ++) - { - SingleColumnFullDataAccessor column = this.tryGet(relX, relZ); - if (column == null || !column.doesColumnExist()) - { - // no data for this relative position - quadrantFullyGenerated = false; - } - else - { - // data exists for this pos - quadrantEmpty = false; - } - } - } - - - if (quadrantFullyGenerated) + ESectionPopulationState populationState = this.getPopulationStateForPos(inputPos, sourceRelWidthInDataPoints); + if (populationState == ESectionPopulationState.COMPLETE) { // no generation necessary continue; } - else if (quadrantEmpty) + else if (populationState == ESectionPopulationState.EMPTY) { // nothing exists for this sub quadrant, add this sub-quadrant's position ungeneratedPosList.add(inputPos); } - else + else if (populationState == ESectionPopulationState.PARTIAL) { // some data exists in this quadrant, but not all that we need // recurse down to determine which sub-quadrant positions will need generation - - ungeneratedPosList.addAll(this.getUngeneratedPosList(inputPos, highestGeneratorDetailLevel)); + ungeneratedPosList.addAll(this.getUngeneratedPosListForQuadrant(inputPos, generatorDetailLevel)); } - } } + else + { + throw new IllegalArgumentException("detail level lower than world generator can accept."); + } return ungeneratedPosList; } + default ESectionPopulationState getPopulationStateForPos(DhSectionPos inputPos, int sourceRelWidthInDataPoints) + { + // TODO comment + + byte childDetailLevel = inputPos.getDetailLevel(); + + int quadrantDetailLevelDiff = this.getSectionPos().getDetailLevel() - childDetailLevel; + int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); + int relWidthForSecPos = sourceRelWidthInDataPoints / widthInSecPos; + + DhSectionPos minSecPos = this.getSectionPos().convertNewToDetailLevel(childDetailLevel); + + + + int minRelX = inputPos.getX() - minSecPos.getX(); + int maxRelX = minRelX + 1; + + int minRelZ = inputPos.getZ() - minSecPos.getZ(); + int maxRelZ = minRelZ + 1; + + minRelX = minRelX * relWidthForSecPos; + maxRelX = maxRelX * relWidthForSecPos; + + minRelZ = minRelZ * relWidthForSecPos; + maxRelZ = maxRelZ * relWidthForSecPos; + + + + boolean quadrantFullyGenerated = true; + boolean quadrantEmpty = true; + for (int relX = minRelX; relX < maxRelX; relX++) + { + for (int relZ = minRelZ; relZ < maxRelZ; relZ++) + { + SingleColumnFullDataAccessor column = this.tryGet(relX, relZ); + if (column == null || !column.doesColumnExist()) + { + // no data for this relative position + quadrantFullyGenerated = false; + } + else + { + // data exists for this pos + quadrantEmpty = false; + } + } + } + + + if (quadrantFullyGenerated) + { + // no generation necessary + return ESectionPopulationState.COMPLETE; + } + else if (quadrantEmpty) + { + // nothing exists for this sub quadrant, add this sub-quadrant's position + return ESectionPopulationState.EMPTY; + } + else + { + // some data exists in this quadrant, but not all that we need + // recurse down to determine which sub-quadrant positions will need generation + return ESectionPopulationState.PARTIAL; + } + } + enum ESectionPopulationState + { + COMPLETE, + EMPTY, + PARTIAL + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java index a0020773a..14ba81d37 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java @@ -67,7 +67,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I public boolean doesFileExist; - //TODO: Atm can't find a better way to store when genQueue is checked. + /** indicates if this file has been checked for missing sections to generate or not */ public boolean genQueueChecked = false; public AbstractFullDataSourceLoader fullDataSourceLoader; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java index 92b8f1947..0b48e5ce1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java @@ -57,7 +57,6 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender private final IDhApiWorldGenerator generator; /** contains the positions that need to be generated */ - //private final QuadTree waitingTaskQuadTree; private final ConcurrentHashMap waitingTasks = new ConcurrentHashMap<>(); private final ConcurrentHashMap inProgressGenTasksByLodPos = new ConcurrentHashMap<>(); @@ -115,11 +114,6 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender this.largestDataDetail = generator.getLargestDataDetailLevel(); this.smallestDataDetail = generator.getSmallestDataDetailLevel(); - //FIXME: Currently resizing view dist doesn't update this, causing some gen task to fail. - int treeWidth = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH * 2; // TODO the *2 is to allow for generation edge cases, and should probably be removed at some point - byte treeMinDetailLevel = LodUtil.CHUNK_DETAIL_LEVEL; // The min level should be at least fill in 1 ChunkSizedFullDataAccessor. - //this.waitingTaskQuadTree = new QuadTree<>(treeWidth, DhBlockPos2D.ZERO /*the quad tree will be re-centered later*/, treeMinDetailLevel); - if (this.minGranularity < LodUtil.CHUNK_DETAIL_LEVEL) { @@ -164,17 +158,9 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender LodUtil.assertTrue(pos.getDetailLevel() > requiredDataDetail + LodUtil.CHUNK_DETAIL_LEVEL); - //if (this.waitingTaskQuadTree.isSectionPosInBounds(requestPos)) - { - CompletableFuture future = new CompletableFuture<>(); - //this.waitingTaskQuadTree.setValue(requestPos, new WorldGenTask(pos, requiredDataDetail, tracker, future)); - waitingTasks.put(pos, new WorldGenTask(pos, requiredDataDetail, tracker, future)); - return future; - } - //else - //{ - //return CompletableFuture.completedFuture(WorldGenResult.CreateFail()); - //} + CompletableFuture future = new CompletableFuture<>(); + this.waitingTasks.put(pos, new WorldGenTask(pos, requiredDataDetail, tracker, future)); + return future; } @Override From 1be2d24f42d338d350aed888f1049161a9fe0b09 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 28 Sep 2023 07:23:20 -0500 Subject: [PATCH 4/5] Move IFullDataSource getUngeneratedPosList() into a separate class --- .../sources/interfaces/IFullDataSource.java | 166 -------------- .../GeneratedFullDataFileHandler.java | 3 +- .../MissingWorldGenPositionFinder.java | 213 ++++++++++++++++++ 3 files changed, 215 insertions(+), 167 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/generation/MissingWorldGenPositionFinder.java diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java index 28e04c995..f30c616a2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IFullDataSource.java @@ -93,172 +93,6 @@ public interface IFullDataSource FullDataPointIdMap getMapping(); - /** - * @param generatorDetailLevel the detail level that the un-generated positions should be split into. - * @param onlyReturnPositionsTheGeneratorCanAccept - * If true this will only return positions with the same detail level as generatorDetailLevel.
- * If false this will return the lowest detail level possible for totally empty sections.
- * As of 2023-9-28 both have been tested and confirmed working with the Batch world generator, the only difference is that - * the task list will be deceptively small if this value is false. - * - * @return the list of {@link DhSectionPos} that aren't generated in this data source. - */ - default ArrayList getUngeneratedPosList(byte generatorDetailLevel, boolean onlyReturnPositionsTheGeneratorCanAccept) - { - ArrayList posArray = this.getUngeneratedPosListForQuadrant(this.getSectionPos(), generatorDetailLevel); - - if (onlyReturnPositionsTheGeneratorCanAccept) - { - LinkedList posList = new LinkedList<>(posArray); - - // subdivide positions until they match the generatorDetailLevel - ArrayList cleanedPosArray = new ArrayList<>(); - while (posList.size() > 0) - { - DhSectionPos pos = posList.remove(); - if (pos.getDetailLevel() > generatorDetailLevel) - { - pos.forEachChild((childPos) -> posList.push(childPos)); - } - else - { - cleanedPosArray.add(pos); - } - } - - return cleanedPosArray; - } - else - { - return posArray; - } - } - default ArrayList getUngeneratedPosListForQuadrant(DhSectionPos quadrantPos, byte generatorDetailLevel) - { - ArrayList ungeneratedPosList = new ArrayList<>(); - - int sourceRelWidthInDataPoints = this.getWidthInDataPoints(); - - - if (quadrantPos.getDetailLevel() == generatorDetailLevel) - { - // we are at the highest detail level the world generator can accept, - // we either need to generate this whole section, or not at all - - ESectionPopulationState populationState = this.getPopulationStateForPos(quadrantPos, sourceRelWidthInDataPoints); - if (populationState != ESectionPopulationState.COMPLETE) - { - // at least 1 data point is missing, - // this whole section must be generated - ungeneratedPosList.add(quadrantPos); - } - } - else if (quadrantPos.getDetailLevel() > generatorDetailLevel) - { - // detail level too low for world generator, check child positions - for (int i = 0; i < 4; i++) - { - DhSectionPos inputPos = quadrantPos.getChildByIndex(i); - - ESectionPopulationState populationState = this.getPopulationStateForPos(inputPos, sourceRelWidthInDataPoints); - if (populationState == ESectionPopulationState.COMPLETE) - { - // no generation necessary - continue; - } - else if (populationState == ESectionPopulationState.EMPTY) - { - // nothing exists for this sub quadrant, add this sub-quadrant's position - ungeneratedPosList.add(inputPos); - } - else if (populationState == ESectionPopulationState.PARTIAL) - { - // some data exists in this quadrant, but not all that we need - // recurse down to determine which sub-quadrant positions will need generation - ungeneratedPosList.addAll(this.getUngeneratedPosListForQuadrant(inputPos, generatorDetailLevel)); - } - } - } - else - { - throw new IllegalArgumentException("detail level lower than world generator can accept."); - } - - return ungeneratedPosList; - } - default ESectionPopulationState getPopulationStateForPos(DhSectionPos inputPos, int sourceRelWidthInDataPoints) - { - // TODO comment - - byte childDetailLevel = inputPos.getDetailLevel(); - - int quadrantDetailLevelDiff = this.getSectionPos().getDetailLevel() - childDetailLevel; - int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); - int relWidthForSecPos = sourceRelWidthInDataPoints / widthInSecPos; - - DhSectionPos minSecPos = this.getSectionPos().convertNewToDetailLevel(childDetailLevel); - - - - int minRelX = inputPos.getX() - minSecPos.getX(); - int maxRelX = minRelX + 1; - - int minRelZ = inputPos.getZ() - minSecPos.getZ(); - int maxRelZ = minRelZ + 1; - - minRelX = minRelX * relWidthForSecPos; - maxRelX = maxRelX * relWidthForSecPos; - - minRelZ = minRelZ * relWidthForSecPos; - maxRelZ = maxRelZ * relWidthForSecPos; - - - - boolean quadrantFullyGenerated = true; - boolean quadrantEmpty = true; - for (int relX = minRelX; relX < maxRelX; relX++) - { - for (int relZ = minRelZ; relZ < maxRelZ; relZ++) - { - SingleColumnFullDataAccessor column = this.tryGet(relX, relZ); - if (column == null || !column.doesColumnExist()) - { - // no data for this relative position - quadrantFullyGenerated = false; - } - else - { - // data exists for this pos - quadrantEmpty = false; - } - } - } - - - if (quadrantFullyGenerated) - { - // no generation necessary - return ESectionPopulationState.COMPLETE; - } - else if (quadrantEmpty) - { - // nothing exists for this sub quadrant, add this sub-quadrant's position - return ESectionPopulationState.EMPTY; - } - else - { - // some data exists in this quadrant, but not all that we need - // recurse down to determine which sub-quadrant positions will need generation - return ESectionPopulationState.PARTIAL; - } - } - enum ESectionPopulationState - { - COMPLETE, - EMPTY, - PARTIAL - } - //=======================// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 65127c8ab..476ea1ffb 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFull import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource; import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; +import com.seibel.distanthorizons.core.generation.MissingWorldGenPositionFinder; import com.seibel.distanthorizons.core.generation.IWorldGenerationQueue; import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker; import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult; @@ -344,7 +345,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler metaFile.genQueueChecked = true; byte minGeneratorSectionDetailLevel = (byte) (worldGenQueue.smallestDataDetail() + DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); - ArrayList genPosList = dataSource.getUngeneratedPosList(minGeneratorSectionDetailLevel, true); + ArrayList genPosList = MissingWorldGenPositionFinder.getUngeneratedPosList(dataSource, minGeneratorSectionDetailLevel, true); for (DhSectionPos genPos : genPosList) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/MissingWorldGenPositionFinder.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/MissingWorldGenPositionFinder.java new file mode 100644 index 000000000..f6e554dd8 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/MissingWorldGenPositionFinder.java @@ -0,0 +1,213 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.generation; + +import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.SingleColumnFullDataAccessor; +import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhSectionPos; +import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.LinkedList; + +/** + * Handles finding any positions in a given {@link IFullDataSource} that + * aren't generated. + */ +public class MissingWorldGenPositionFinder +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + + + /** + * @param generatorDetailLevel the detail level that the un-generated positions should be split into. + * @param onlyReturnPositionsTheGeneratorCanAccept + * If true this will only return positions with the same detail level as generatorDetailLevel.
+ * If false this will return the lowest detail level possible for totally empty sections.
+ * As of 2023-9-28 both have been tested and confirmed working with the Batch world generator, the only difference is that + * the task list will be deceptively small if this value is false. + * + * @return the list of {@link DhSectionPos} that aren't generated in this data source. + */ + public static ArrayList getUngeneratedPosList(IFullDataSource dataSource, byte generatorDetailLevel, boolean onlyReturnPositionsTheGeneratorCanAccept) + { + ArrayList posArray = getUngeneratedPosListForQuadrant(dataSource, dataSource.getSectionPos(), generatorDetailLevel); + + if (onlyReturnPositionsTheGeneratorCanAccept) + { + LinkedList posList = new LinkedList<>(posArray); + + // subdivide positions until they match the generatorDetailLevel + ArrayList cleanedPosArray = new ArrayList<>(); + while (posList.size() > 0) + { + DhSectionPos pos = posList.remove(); + if (pos.getDetailLevel() > generatorDetailLevel) + { + pos.forEachChild((childPos) -> posList.push(childPos)); + } + else + { + cleanedPosArray.add(pos); + } + } + + return cleanedPosArray; + } + else + { + return posArray; + } + } + private static ArrayList getUngeneratedPosListForQuadrant(IFullDataSource dataSource, DhSectionPos quadrantPos, byte generatorDetailLevel) + { + ArrayList ungeneratedPosList = new ArrayList<>(); + + int sourceRelWidthInDataPoints = dataSource.getWidthInDataPoints(); + + + if (quadrantPos.getDetailLevel() == generatorDetailLevel) + { + // we are at the highest detail level the world generator can accept, + // we either need to generate this whole section, or not at all + + ESectionPopulationState populationState = getPopulationStateForPos(dataSource, quadrantPos, sourceRelWidthInDataPoints); + if (populationState != ESectionPopulationState.COMPLETE) + { + // at least 1 data point is missing, + // this whole section must be generated + ungeneratedPosList.add(quadrantPos); + } + } + else if (quadrantPos.getDetailLevel() > generatorDetailLevel) + { + // detail level too low for world generator, check child positions + for (int i = 0; i < 4; i++) + { + DhSectionPos inputPos = quadrantPos.getChildByIndex(i); + + ESectionPopulationState populationState = getPopulationStateForPos(dataSource, inputPos, sourceRelWidthInDataPoints); + if (populationState == ESectionPopulationState.COMPLETE) + { + // no generation necessary + continue; + } + else if (populationState == ESectionPopulationState.EMPTY) + { + // nothing exists for this sub quadrant, add this sub-quadrant's position + ungeneratedPosList.add(inputPos); + } + else if (populationState == ESectionPopulationState.PARTIAL) + { + // some data exists in this quadrant, but not all that we need + // recurse down to determine which sub-quadrant positions will need generation + ungeneratedPosList.addAll(getUngeneratedPosListForQuadrant(dataSource, inputPos, generatorDetailLevel)); + } + } + } + else + { + throw new IllegalArgumentException("detail level lower than world generator can accept."); + } + + return ungeneratedPosList; + } + private static ESectionPopulationState getPopulationStateForPos(IFullDataSource dataSource, DhSectionPos inputPos, int sourceRelWidthInDataPoints) + { + // TODO comment + + byte childDetailLevel = inputPos.getDetailLevel(); + + int quadrantDetailLevelDiff = dataSource.getSectionPos().getDetailLevel() - childDetailLevel; + int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff); + int relWidthForSecPos = sourceRelWidthInDataPoints / widthInSecPos; + + DhSectionPos minSecPos = dataSource.getSectionPos().convertNewToDetailLevel(childDetailLevel); + + + + int minRelX = inputPos.getX() - minSecPos.getX(); + int maxRelX = minRelX + 1; + + int minRelZ = inputPos.getZ() - minSecPos.getZ(); + int maxRelZ = minRelZ + 1; + + minRelX = minRelX * relWidthForSecPos; + maxRelX = maxRelX * relWidthForSecPos; + + minRelZ = minRelZ * relWidthForSecPos; + maxRelZ = maxRelZ * relWidthForSecPos; + + + + boolean quadrantFullyGenerated = true; + boolean quadrantEmpty = true; + for (int relX = minRelX; relX < maxRelX; relX++) + { + for (int relZ = minRelZ; relZ < maxRelZ; relZ++) + { + SingleColumnFullDataAccessor column = dataSource.tryGet(relX, relZ); + if (column == null || !column.doesColumnExist()) + { + // no data for this relative position + quadrantFullyGenerated = false; + } + else + { + // data exists for this pos + quadrantEmpty = false; + } + } + } + + + if (quadrantFullyGenerated) + { + // no generation necessary + return ESectionPopulationState.COMPLETE; + } + else if (quadrantEmpty) + { + // nothing exists for this sub quadrant, add this sub-quadrant's position + return ESectionPopulationState.EMPTY; + } + else + { + // some data exists in this quadrant, but not all that we need + // recurse down to determine which sub-quadrant positions will need generation + return ESectionPopulationState.PARTIAL; + } + } + + + + //================// + // helper classes // + //================// + + private enum ESectionPopulationState + { + COMPLETE, + EMPTY, + PARTIAL + } +} From ee24bd0881393be7647d6a721c6915a49ed82bd3 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 28 Sep 2023 07:24:25 -0500 Subject: [PATCH 5/5] minor worldGenQueue method rename --- .../GeneratedFullDataFileHandler.java | 2 +- .../generation/IWorldGenerationQueue.java | 4 ++-- .../core/generation/WorldGenerationQueue.java | 22 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 476ea1ffb..09f83dd6a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -344,7 +344,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler } metaFile.genQueueChecked = true; - byte minGeneratorSectionDetailLevel = (byte) (worldGenQueue.smallestDataDetail() + DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); + byte minGeneratorSectionDetailLevel = (byte) (worldGenQueue.highestDataDetail() + DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); ArrayList genPosList = MissingWorldGenPositionFinder.getUngeneratedPosList(dataSource, minGeneratorSectionDetailLevel, true); for (DhSectionPos genPos : genPosList) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java index c1df7c170..48754664a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java @@ -30,9 +30,9 @@ import java.util.concurrent.CompletableFuture; public interface IWorldGenerationQueue extends Closeable { /** the largest numerical detail level */ - byte largestDataDetail(); + byte lowestDataDetail(); /** the smallest numerical detail level */ - byte smallestDataDetail(); + byte highestDataDetail(); CompletableFuture submitGenTask(DhSectionPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker); void cancelGenTasks(Iterable positions); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java index 0b48e5ce1..011dd53e6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java @@ -66,14 +66,14 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender public final byte minGranularity; /** largest numerical detail level allowed */ - public final byte largestDataDetail; + public final byte lowestDataDetail; @Override - public byte largestDataDetail() { return this.largestDataDetail; } + public byte lowestDataDetail() { return this.lowestDataDetail; } - /** lowest numerical detail level allowed */ - public final byte smallestDataDetail; + /** smallest numerical detail level allowed */ + public final byte highestDataDetail; @Override - public byte smallestDataDetail() { return this.smallestDataDetail; } + public byte highestDataDetail() { return this.highestDataDetail; } /** If not null this generator is in the process of shutting down */ @@ -111,8 +111,8 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender this.generator = generator; this.maxGranularity = generator.getMaxGenerationGranularity(); this.minGranularity = generator.getMinGenerationGranularity(); - this.largestDataDetail = generator.getLargestDataDetailLevel(); - this.smallestDataDetail = generator.getSmallestDataDetailLevel(); + this.lowestDataDetail = generator.getLargestDataDetailLevel(); + this.highestDataDetail = generator.getSmallestDataDetailLevel(); if (this.minGranularity < LodUtil.CHUNK_DETAIL_LEVEL) @@ -145,13 +145,13 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender // make sure the generator can provide the requested position - if (requiredDataDetail < this.smallestDataDetail) + if (requiredDataDetail < this.highestDataDetail) { throw new UnsupportedOperationException("Current generator does not meet requiredDataDetail level"); } - if (requiredDataDetail > this.largestDataDetail) + if (requiredDataDetail > this.lowestDataDetail) { - requiredDataDetail = this.largestDataDetail; + requiredDataDetail = this.lowestDataDetail; } // Assert that the data at least can fill in 1 single ChunkSizedFullDataAccessor @@ -330,7 +330,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender DhSectionPos taskPos = inProgressTaskGroup.group.pos; byte granularity = (byte) (taskPos.getDetailLevel() - taskDetailLevel); LodUtil.assertTrue(granularity >= this.minGranularity && granularity <= this.maxGranularity); - LodUtil.assertTrue(taskDetailLevel >= this.smallestDataDetail && taskDetailLevel <= this.largestDataDetail); + LodUtil.assertTrue(taskDetailLevel >= this.highestDataDetail && taskDetailLevel <= this.lowestDataDetail); DhChunkPos chunkPosMin = new DhChunkPos(taskPos.getSectionBBoxPos().getCornerBlockPos());