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