refactoring

This commit is contained in:
James Seibel
2023-03-11 10:37:02 -06:00
parent d687ec892a
commit c5c298708f
8 changed files with 80 additions and 77 deletions
@@ -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);
}
@@ -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)
{
@@ -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();
}
@@ -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);
}
}
}