refactoring
This commit is contained in:
@@ -279,7 +279,8 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
public void write(DhSectionPos sectionPos, ChunkSizedFullDataSource chunkData)
|
||||
{
|
||||
DhLodPos chunkPos = new DhLodPos((byte) (chunkData.dataDetail+4), chunkData.x, chunkData.z);
|
||||
LodUtil.assertTrue(chunkPos.overlaps(sectionPos.getSectionBBoxPos()), "Chunk {} does not overlap section {}", chunkPos, sectionPos);
|
||||
LodUtil.assertTrue(chunkPos.overlaps(sectionPos.getSectionBBoxPos()), "Chunk "+chunkPos+" does not overlap section "+sectionPos);
|
||||
|
||||
chunkPos = chunkPos.convertToDetailLevel((byte) this.minDetailLevel);
|
||||
this.recursiveWrite(new DhSectionPos(chunkPos.detailLevel, chunkPos.x, chunkPos.z), chunkData);
|
||||
}
|
||||
|
||||
+25
-22
@@ -5,7 +5,7 @@ import com.seibel.lod.core.dataObjects.fullData.IIncompleteFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.ChunkSizedFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.SparseFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.SingleChunkFullDataSource;
|
||||
import com.seibel.lod.core.generation.tasks.AbstractWorldGenTaskTracker;
|
||||
import com.seibel.lod.core.generation.tasks.IWorldGenTaskTracker;
|
||||
import com.seibel.lod.core.generation.WorldGenerationQueue;
|
||||
import com.seibel.lod.core.level.IDhServerLevel;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
@@ -70,9 +70,9 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
if (worldGenQueue != null)
|
||||
{
|
||||
// queue this section to be generated
|
||||
GenTask task = new GenTask(pos, new WeakReference<>(dataSource));
|
||||
worldGenQueue.submitGenTask(dataSource.getSectionPos().getSectionBBoxPos(), dataSource.getDataDetail(), task)
|
||||
.whenComplete((genTaskCompleted, ex) -> this.onWorldGenTaskComplete(genTaskCompleted, ex, task, pos));
|
||||
GenTask genTask = new GenTask(pos, new WeakReference<>(dataSource));
|
||||
worldGenQueue.submitGenTask(dataSource.getSectionPos().getSectionBBoxPos(), dataSource.getDataDetail(), genTask)
|
||||
.whenComplete((genTaskCompleted, ex) -> this.onWorldGenTaskComplete(genTaskCompleted, ex, genTask, pos));
|
||||
}
|
||||
|
||||
// return the empty dataSource (it will be populated later)
|
||||
@@ -117,7 +117,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
|
||||
|
||||
|
||||
private void onWorldGenTaskComplete(Boolean genTaskCompleted, Throwable exception, GenTask task, DhSectionPos pos)
|
||||
private void onWorldGenTaskComplete(Boolean genTaskCompleted, Throwable exception, GenTask genTask, DhSectionPos pos)
|
||||
{
|
||||
if (exception != null)
|
||||
{
|
||||
@@ -127,13 +127,13 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
LOGGER.error("Uncaught Gen Task Exception at " + pos + ":", exception);
|
||||
}
|
||||
}
|
||||
|
||||
if (exception == null && genTaskCompleted)
|
||||
else if (genTaskCompleted)
|
||||
{
|
||||
// this.files.get(task.pos).metaData.dataVersion.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
task.releaseStrongReference();
|
||||
|
||||
genTask.releaseStrongReference();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,47 +142,50 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
// helper class //
|
||||
//==============//
|
||||
|
||||
class GenTask extends AbstractWorldGenTaskTracker
|
||||
private class GenTask implements IWorldGenTaskTracker
|
||||
{
|
||||
private final DhSectionPos pos;
|
||||
private final WeakReference<IFullDataSource> targetData;
|
||||
private IFullDataSource loadedTargetData = null;
|
||||
|
||||
// weak reference (probably) used to prevent overloading the GC when lots of gen tasks are created?
|
||||
private final WeakReference<IFullDataSource> targetFullDataSourceRef;
|
||||
// the target data source is where the generated chunk data will be put when completed
|
||||
private IFullDataSource loadedTargetFullDataSource = null;
|
||||
|
||||
|
||||
|
||||
GenTask(DhSectionPos pos, WeakReference<IFullDataSource> targetData)
|
||||
public GenTask(DhSectionPos pos, WeakReference<IFullDataSource> targetFullDataSourceRef)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.targetData = targetData;
|
||||
this.targetFullDataSourceRef = targetFullDataSourceRef;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isMemoryAddressValid() { return this.targetData.get() != null; }
|
||||
public boolean isMemoryAddressValid() { return this.targetFullDataSourceRef.get() != null; }
|
||||
|
||||
@Override
|
||||
public Consumer<ChunkSizedFullDataSource> getConsumer()
|
||||
public Consumer<ChunkSizedFullDataSource> getOnGenTaskCompleteConsumer()
|
||||
{
|
||||
if (this.loadedTargetData == null)
|
||||
if (this.loadedTargetFullDataSource == null)
|
||||
{
|
||||
this.loadedTargetData = this.targetData.get();
|
||||
if (this.loadedTargetData == null)
|
||||
this.loadedTargetFullDataSource = this.targetFullDataSourceRef.get();
|
||||
if (this.loadedTargetFullDataSource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return (chunk) ->
|
||||
return (chunkSizedFullDataSource) ->
|
||||
{
|
||||
if (chunk.getBBoxLodPos().overlaps(this.loadedTargetData.getSectionPos().getSectionBBoxPos()))
|
||||
if (chunkSizedFullDataSource.getBBoxLodPos().overlaps(this.loadedTargetFullDataSource.getSectionPos().getSectionBBoxPos()))
|
||||
{
|
||||
GeneratedFullDataFileHandler.this.write(this.loadedTargetData.getSectionPos(), chunk);
|
||||
GeneratedFullDataFileHandler.this.write(this.loadedTargetFullDataSource.getSectionPos(), chunkSizedFullDataSource);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void releaseStrongReference() { this.loadedTargetData = null; }
|
||||
public void releaseStrongReference() { this.loadedTargetFullDataSource = null; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
// task handling //
|
||||
//=================//
|
||||
|
||||
public CompletableFuture<Boolean> submitGenTask(DhLodPos pos, byte requiredDataDetail, AbstractWorldGenTaskTracker tracker)
|
||||
public CompletableFuture<Boolean> submitGenTask(DhLodPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker)
|
||||
{
|
||||
// if the generator is shutting down, don't add new tasks
|
||||
if (this.generatorClosingFuture != null)
|
||||
@@ -146,7 +146,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
DhLodPos cornerSubPos = pos.getCornerLodPos(subDetail);
|
||||
CompletableFuture<Boolean>[] subFutures = new CompletableFuture[subPosWidthCount * subPosWidthCount];
|
||||
ArrayList<WorldGenTask> subTasks = new ArrayList<>(subPosWidthCount * subPosWidthCount);
|
||||
SplitTaskTracker splitTaskTracker = new SplitTaskTracker(tracker, new CompletableFuture<>());
|
||||
SplitWorldGenTaskTracker splitTaskTracker = new SplitWorldGenTaskTracker(tracker, new CompletableFuture<>());
|
||||
|
||||
// create the new sub-futures
|
||||
int subFutureIndex = 0;
|
||||
@@ -241,7 +241,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
{
|
||||
// go through each WorldGenTask in the TaskGroup
|
||||
WorldGenTaskGroup taskGroup = groupIter.next();
|
||||
Iterator<WorldGenTask> taskIter = taskGroup.generatorTasks.iterator();
|
||||
Iterator<WorldGenTask> taskIter = taskGroup.worldGenTasks.iterator();
|
||||
while (taskIter.hasNext())
|
||||
{
|
||||
// remove this task if it has been garbage collected
|
||||
@@ -254,7 +254,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
}
|
||||
|
||||
// remove this group if it is now empty
|
||||
if (taskGroup.generatorTasks.isEmpty())
|
||||
if (taskGroup.worldGenTasks.isEmpty())
|
||||
{
|
||||
groupIter.remove();
|
||||
}
|
||||
@@ -287,7 +287,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
{
|
||||
// the existing group has an equal or lower detail level,
|
||||
// we can just append the new task to its list.
|
||||
existingWorldGenGroup.generatorTasks.add(task);
|
||||
existingWorldGenGroup.worldGenTasks.add(task);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -300,7 +300,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
LodUtil.assertTrue(taskRemoved);
|
||||
|
||||
// re-add the task group
|
||||
existingWorldGenGroup.generatorTasks.add(task);
|
||||
existingWorldGenGroup.worldGenTasks.add(task);
|
||||
this.addAndCombineTaskGroup(existingWorldGenGroup);
|
||||
}
|
||||
}
|
||||
@@ -317,7 +317,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
if (existingWorldGenGroup != null && existingWorldGenGroup.dataDetail == taskDataDetail)
|
||||
{
|
||||
// We can just append to the higher detail level group
|
||||
existingWorldGenGroup.generatorTasks.add(task);
|
||||
existingWorldGenGroup.worldGenTasks.add(task);
|
||||
addedToHigherDetailGroup = true;
|
||||
break;
|
||||
}
|
||||
@@ -328,7 +328,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
// no higher detail group exists that we can append to,
|
||||
// create a new task group
|
||||
existingWorldGenGroup = new WorldGenTaskGroup(task.pos, taskDataDetail);
|
||||
existingWorldGenGroup.generatorTasks.add(task);
|
||||
existingWorldGenGroup.worldGenTasks.add(task);
|
||||
this.addAndCombineTaskGroup(existingWorldGenGroup);
|
||||
}
|
||||
}
|
||||
@@ -367,7 +367,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
// We should have already ALWAYS selected the higher granularity.
|
||||
LodUtil.assertTrue(group.pos.detailLevel < newTaskGroup.pos.detailLevel);
|
||||
groupIter.remove(); // Remove and consume all from that lower granularity request
|
||||
newTaskGroup.generatorTasks.addAll(group.generatorTasks);
|
||||
newTaskGroup.worldGenTasks.addAll(group.worldGenTasks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
// We can just append us into the existing list.
|
||||
for (WorldGenTaskGroup g : groups)
|
||||
{
|
||||
newGroup.generatorTasks.addAll(g.generatorTasks);
|
||||
newGroup.worldGenTasks.addAll(g.worldGenTasks);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -430,7 +430,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
LodUtil.assertTrue(worked);
|
||||
for (WorldGenTaskGroup g : groups)
|
||||
{
|
||||
newGroup.generatorTasks.addAll(g.generatorTasks);
|
||||
newGroup.worldGenTasks.addAll(g.worldGenTasks);
|
||||
}
|
||||
this.addAndCombineTaskGroup(newGroup); // Recursive check the new group
|
||||
}
|
||||
@@ -441,7 +441,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
newGroup = new WorldGenTaskGroup(parentPos, newTaskGroup.dataDetail);
|
||||
for (WorldGenTaskGroup g : groups)
|
||||
{
|
||||
newGroup.generatorTasks.addAll(g.generatorTasks);
|
||||
newGroup.worldGenTasks.addAll(g.worldGenTasks);
|
||||
}
|
||||
this.addAndCombineTaskGroup(newGroup); // Recursive check the new group
|
||||
}
|
||||
@@ -559,7 +559,8 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
DhChunkPos chunkPosMin = new DhChunkPos(pos.getCornerBlockPos());
|
||||
//LOGGER.info("Generating section {} with granularity {} at {}", pos, granularity, chunkPosMin);
|
||||
task.genFuture = startGenerationEvent(this.generator, chunkPosMin, granularity, dataDetail, task.group::accept);
|
||||
|
||||
task.genFuture = startGenerationEvent(this.generator, chunkPosMin, granularity, dataDetail, task.group::onGenerationComplete);
|
||||
task.genFuture.whenComplete((voidObj, exception) ->
|
||||
{
|
||||
if (exception != null)
|
||||
@@ -570,12 +571,12 @@ public class WorldGenerationQueue implements Closeable
|
||||
LOGGER.error("Error generating data for section "+pos, exception);
|
||||
}
|
||||
|
||||
task.group.generatorTasks.forEach(worldGenTask -> worldGenTask.future.complete(false));
|
||||
task.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(false));
|
||||
}
|
||||
else
|
||||
{
|
||||
//LOGGER.info("Section generation at "+pos+" completed");
|
||||
task.group.generatorTasks.forEach(worldGenTask -> worldGenTask.future.complete(true));
|
||||
task.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(true));
|
||||
}
|
||||
boolean worked = this.inProgressGenTasksByLodPos.remove(pos, task);
|
||||
LodUtil.assertTrue(worked);
|
||||
@@ -612,7 +613,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
{
|
||||
// go through each WorldGenTask in the TaskGroup
|
||||
WorldGenTaskGroup taskGroup = taskGroupIter.next();
|
||||
Iterator<WorldGenTask> taskIter = taskGroup.generatorTasks.iterator();
|
||||
Iterator<WorldGenTask> taskIter = taskGroup.worldGenTasks.iterator();
|
||||
while (taskIter.hasNext())
|
||||
{
|
||||
// remove this task if it has been garbage collected
|
||||
@@ -629,7 +630,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
}
|
||||
|
||||
// remove this group if it is now empty
|
||||
if (taskGroup.generatorTasks.isEmpty())
|
||||
if (taskGroup.worldGenTasks.isEmpty())
|
||||
{
|
||||
taskGroupIter.remove();
|
||||
}
|
||||
@@ -650,7 +651,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
public CompletableFuture<Void> startClosing(boolean cancelCurrentGeneration, boolean alsoInterruptRunning)
|
||||
{
|
||||
this.waitingTaskGroupsByLodPos.values().forEach(worldGenTaskGroup -> worldGenTaskGroup.generatorTasks.forEach(
|
||||
this.waitingTaskGroupsByLodPos.values().forEach(worldGenTaskGroup -> worldGenTaskGroup.worldGenTasks.forEach(
|
||||
(worldGenTask) ->
|
||||
{
|
||||
try { worldGenTask.future.cancel(true); } catch (CancellationException ignored) { /* don't log shutdown exceptions */ }
|
||||
@@ -754,7 +755,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
private static CompletableFuture<Void> startGenerationEvent(IDhApiWorldGenerator worldGenerator,
|
||||
DhChunkPos chunkPosMin,
|
||||
byte granularity, byte targetDataDetail,
|
||||
Consumer<ChunkSizedFullDataSource> resultConsumer)
|
||||
Consumer<ChunkSizedFullDataSource> generationCompleteConsumer)
|
||||
{
|
||||
EDhApiDistantGeneratorMode generatorMode = Config.Client.WorldGenerator.distantGeneratorMode.get();
|
||||
return worldGenerator.generateChunks(chunkPosMin.x, chunkPosMin.z, granularity, targetDataDetail, generatorMode, (objectArray) ->
|
||||
@@ -762,7 +763,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
try
|
||||
{
|
||||
IChunkWrapper chunk = SingletonInjector.INSTANCE.get(IWrapperFactory.class).createChunkWrapper(objectArray);
|
||||
resultConsumer.accept(LodDataBuilder.createChunkData(chunk));
|
||||
generationCompleteConsumer.accept(LodDataBuilder.createChunkData(chunk));
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.seibel.lod.core.generation.tasks;
|
||||
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.ChunkSizedFullDataSource;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Leetom
|
||||
* @version 2022-11-25
|
||||
*/
|
||||
public abstract class AbstractWorldGenTaskTracker
|
||||
{
|
||||
/**
|
||||
* Returns true if the task hasn't been garbage collected. <br>
|
||||
* TODO rename to fit the above description better
|
||||
*/
|
||||
public abstract boolean isMemoryAddressValid();
|
||||
|
||||
public abstract Consumer<ChunkSizedFullDataSource> getConsumer();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.seibel.lod.core.generation.tasks;
|
||||
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.ChunkSizedFullDataSource;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Leetom
|
||||
* @version 2022-11-25
|
||||
*/
|
||||
public interface IWorldGenTaskTracker
|
||||
{
|
||||
/** Returns true if the task hasn't been garbage collected. */
|
||||
boolean isMemoryAddressValid();
|
||||
|
||||
Consumer<ChunkSizedFullDataSource> getOnGenTaskCompleteConsumer();
|
||||
|
||||
}
|
||||
+5
-5
@@ -13,9 +13,9 @@ import com.seibel.lod.core.generation.WorldGenerationQueue;
|
||||
* @author Leetom
|
||||
* @version 2022-11-25
|
||||
*/
|
||||
public class SplitTaskTracker extends AbstractWorldGenTaskTracker
|
||||
public class SplitWorldGenTaskTracker implements IWorldGenTaskTracker
|
||||
{
|
||||
public final AbstractWorldGenTaskTracker parentTracker;
|
||||
public final IWorldGenTaskTracker parentTracker;
|
||||
public final CompletableFuture<Boolean> parentFuture;
|
||||
|
||||
/** cached value to allow for quicker checking */
|
||||
@@ -23,7 +23,7 @@ public class SplitTaskTracker extends AbstractWorldGenTaskTracker
|
||||
|
||||
|
||||
|
||||
public SplitTaskTracker(AbstractWorldGenTaskTracker parentTracker, CompletableFuture<Boolean> parentFuture)
|
||||
public SplitWorldGenTaskTracker(IWorldGenTaskTracker parentTracker, CompletableFuture<Boolean> parentFuture)
|
||||
{
|
||||
this.parentTracker = parentTracker;
|
||||
this.parentFuture = parentFuture;
|
||||
@@ -31,7 +31,7 @@ public class SplitTaskTracker extends AbstractWorldGenTaskTracker
|
||||
|
||||
|
||||
|
||||
/** Recalculates and returns the new {@link SplitTaskTracker#isValid} value */
|
||||
/** Recalculates and returns the new {@link SplitWorldGenTaskTracker#isValid} value */
|
||||
public boolean recalculateIsValid()
|
||||
{
|
||||
if (!this.isValid)
|
||||
@@ -52,6 +52,6 @@ public class SplitTaskTracker extends AbstractWorldGenTaskTracker
|
||||
public boolean isMemoryAddressValid() { return this.isValid; }
|
||||
|
||||
@Override
|
||||
public Consumer<ChunkSizedFullDataSource> getConsumer() { return this.parentTracker.getConsumer(); }
|
||||
public Consumer<ChunkSizedFullDataSource> getOnGenTaskCompleteConsumer() { return this.parentTracker.getOnGenTaskCompleteConsumer(); }
|
||||
|
||||
}
|
||||
@@ -12,11 +12,11 @@ public final class WorldGenTask
|
||||
{
|
||||
public final DhLodPos pos;
|
||||
public final byte dataDetailLevel;
|
||||
public final AbstractWorldGenTaskTracker taskTracker;
|
||||
public final IWorldGenTaskTracker taskTracker;
|
||||
public final CompletableFuture<Boolean> future;
|
||||
|
||||
|
||||
public WorldGenTask(DhLodPos pos, byte dataDetail, AbstractWorldGenTaskTracker taskTracker, CompletableFuture<Boolean> future)
|
||||
public WorldGenTask(DhLodPos pos, byte dataDetail, IWorldGenTaskTracker taskTracker, CompletableFuture<Boolean> future)
|
||||
{
|
||||
this.dataDetailLevel = dataDetail;
|
||||
this.pos = pos;
|
||||
|
||||
@@ -16,7 +16,7 @@ public final class WorldGenTaskGroup
|
||||
public final DhLodPos pos;
|
||||
public byte dataDetail;
|
||||
/** Only accessed by the generator polling thread */
|
||||
public final LinkedList<WorldGenTask> generatorTasks = new LinkedList<>();
|
||||
public final LinkedList<WorldGenTask> worldGenTasks = new LinkedList<>();
|
||||
|
||||
|
||||
|
||||
@@ -28,21 +28,22 @@ public final class WorldGenTaskGroup
|
||||
|
||||
|
||||
|
||||
public void accept(ChunkSizedFullDataSource data)
|
||||
public void onGenerationComplete(ChunkSizedFullDataSource chunkSizedFullDataSource)
|
||||
{
|
||||
Iterator<WorldGenTask> tasks = this.generatorTasks.iterator();
|
||||
Iterator<WorldGenTask> tasks = this.worldGenTasks.iterator();
|
||||
while (tasks.hasNext())
|
||||
{
|
||||
WorldGenTask task = tasks.next();
|
||||
Consumer<ChunkSizedFullDataSource> consumer = task.taskTracker.getConsumer();
|
||||
if (consumer == null)
|
||||
Consumer<ChunkSizedFullDataSource> onGenTaskCompleteConsumer = task.taskTracker.getOnGenTaskCompleteConsumer();
|
||||
if (onGenTaskCompleteConsumer == null)
|
||||
{
|
||||
tasks.remove();
|
||||
task.future.complete(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
consumer.accept(data);
|
||||
// TODO why aren't we removing the task if it has a consumer?
|
||||
onGenTaskCompleteConsumer.accept(chunkSizedFullDataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user