diff --git a/src/main/java/com/seibel/lod/core/a7/PlaceHolderQueue.java b/src/main/java/com/seibel/lod/core/a7/PlaceHolderQueue.java new file mode 100644 index 000000000..b009c09b9 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/a7/PlaceHolderQueue.java @@ -0,0 +1,7 @@ +package com.seibel.lod.core.a7; + +import com.seibel.lod.core.a7.datatype.PlaceHolderRenderSource; + +public interface PlaceHolderQueue { + void track(PlaceHolderRenderSource source); // Note: Implementation should only track a weak reference to the source. +} diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java index 871d6541a..9598b161d 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java @@ -16,6 +16,8 @@ import java.io.OutputStream; import java.util.concurrent.atomic.AtomicReference; public interface LodRenderSource { + DhSectionPos getSectionPos(); + void enableRender(IClientLevel level, LodQuadTree quadTree); void disableRender(); boolean isRenderReady(); @@ -35,4 +37,9 @@ public interface LodRenderSource { void update(ChunkSizedData chunkData); byte getRenderVersion(); + + /** + * Whether this object is still valid. If not, a new one should be created. + */ + boolean isValid(); } diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/EmptyRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/PlaceHolderRenderSource.java similarity index 67% rename from src/main/java/com/seibel/lod/core/a7/datatype/EmptyRenderSource.java rename to src/main/java/com/seibel/lod/core/a7/datatype/PlaceHolderRenderSource.java index 2ae5618a3..ee22e2f93 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/EmptyRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/PlaceHolderRenderSource.java @@ -2,57 +2,68 @@ package com.seibel.lod.core.a7.datatype; import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; import com.seibel.lod.core.a7.level.IClientLevel; +import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.render.LodQuadTree; import com.seibel.lod.core.a7.render.RenderBuffer; import com.seibel.lod.core.a7.save.io.render.RenderMetaFile; -import com.seibel.lod.core.objects.DHChunkPos; import java.io.IOException; import java.io.OutputStream; import java.util.concurrent.atomic.AtomicReference; -public class EmptyRenderSource implements LodRenderSource { - public static final EmptyRenderSource INSTANCE = new EmptyRenderSource(); +public class PlaceHolderRenderSource implements LodRenderSource { + final DhSectionPos pos; + boolean isValid = true; + public PlaceHolderRenderSource(DhSectionPos pos) { + this.pos = pos; + } + @Override + public DhSectionPos getSectionPos() { + return pos; + } @Override public void enableRender(IClientLevel level, LodQuadTree quadTree) { } @Override - public void disableRender() { - } + public void disableRender() {} @Override public boolean isRenderReady() { return false; } - @Override - public void dispose() { - } - + public void dispose() {} @Override public byte getDetailOffset() { return 0; } - @Override public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference referenceSlot) { return false; } - @Override public void saveRender(IClientLevel level, RenderMetaFile file, OutputStream dataStream) throws IOException { throw new UnsupportedOperationException("EmptyRenderSource should NEVER be saved!"); } - @Override - public void update(ChunkSizedData chunkData) { - } + public void update(ChunkSizedData chunkData) {} @Override public byte getRenderVersion() { return 0; } + + public void markInvalid() { + isValid = false; + } + + @Override + public boolean isValid() { + return isValid; + } + + } diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java index faf82235e..c46845a30 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java @@ -322,4 +322,9 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { public byte getRenderVersion() { return LATEST_VERSION; } + + @Override + public boolean isValid() { + return true; // For now, this is always valid. + } } diff --git a/src/main/java/com/seibel/lod/core/a7/generation/GenerationQueue.java b/src/main/java/com/seibel/lod/core/a7/generation/GenerationQueue.java new file mode 100644 index 000000000..260e238e6 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/a7/generation/GenerationQueue.java @@ -0,0 +1,137 @@ +package com.seibel.lod.core.a7.generation; + +import com.seibel.lod.core.a7.PlaceHolderQueue; +import com.seibel.lod.core.a7.datatype.PlaceHolderRenderSource; +import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; +import com.seibel.lod.core.a7.datatype.full.FullDataSource; +import com.seibel.lod.core.a7.pos.DhBlockPos2D; +import com.seibel.lod.core.a7.pos.DhLodPos; +import com.seibel.lod.core.a7.pos.DhSectionPos; +import com.seibel.lod.core.logging.DhLoggerBuilder; +import com.seibel.lod.core.objects.DHChunkPos; +import com.seibel.lod.core.util.gridList.ArrayGridList; +import org.apache.logging.log4j.Logger; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; + +public class GenerationQueue implements PlaceHolderQueue { + private final Logger logger = DhLoggerBuilder.getLogger(); + DhBlockPos2D lastPlayerPos = new DhBlockPos2D(0, 0); + final HashMap> trackers = new HashMap<>(); + IGenerator generator = null; + final BiConsumer writeConsumer; + + public GenerationQueue(BiConsumer writeConsumer) { + this.writeConsumer = writeConsumer; + } + + public void track(PlaceHolderRenderSource source) { + trackers.put(source.getSectionPos(), new WeakReference<>(source)); + } + + private void update() { + LinkedList toRemove = new LinkedList<>(); + for (DhSectionPos pos : trackers.keySet()) { + WeakReference ref = trackers.get(pos); + if (ref.get() == null) { + toRemove.add(pos); + } + } + for (DhSectionPos pos : toRemove) { + trackers.remove(pos); + } + } + + //FIXME: Do optimizations on polling closest to player. (Currently its a O(n) search!) + //FIXME: Do not return sections that is already being generated. + private DhSectionPos pollClosest(DhBlockPos2D playerPos) { + update(); + DhSectionPos closest = null; + long closestDist = Long.MAX_VALUE; + for (DhSectionPos pos : trackers.keySet()) { + long distSqr = pos.getCenter().getCenter().distSquared(playerPos); + if (distSqr < closestDist) { + closest = pos; + closestDist = distSqr; + } + } + return closest; + } + + public void setGenerator(IGenerator generator) { + this.generator = generator; + } + + private void write(DhSectionPos pos, ChunkSizedData data) { + writeConsumer.accept(pos, data); + WeakReference ref = trackers.get(pos); + if (ref == null) return; // No placeholder there, so no need to trigger a refresh on it. + PlaceHolderRenderSource source = ref.get(); + if (source == null) return; // Same as above. + source.markInvalid(); // Mark the placeholder as invalid, so it will be refreshed on next lodTree update. + } + + public void doGeneration() { + if (generator == null) return; + + DhSectionPos pos = pollClosest(lastPlayerPos); + if (pos == null) return; + + byte dataDetail = generator.getDataDetail(); + byte minGenGranularity = generator.getMinGenerationGranularity(); + byte maxGenGranularity = generator.getMaxGenerationGranularity(); + if (minGenGranularity < 4 || maxGenGranularity < 4) { + throw new IllegalStateException("Generation granularity must be at least 4!"); + } + + byte minUnitDetail = (byte) (dataDetail + minGenGranularity); + byte maxUnitDetail = (byte) (dataDetail + maxGenGranularity); + + byte granularity; + int count; + DHChunkPos chunkPosMin; + if (pos.sectionDetail < minUnitDetail) { + granularity = minGenGranularity; + count = 1; + chunkPosMin = new DHChunkPos(pos.getSectionBBoxPos().convertUpwardsTo(minUnitDetail).getCorner()); + } else if (pos.sectionDetail > maxUnitDetail) { + granularity = maxGenGranularity; + count = 1 << (pos.sectionDetail - maxUnitDetail); + chunkPosMin = new DHChunkPos(pos.getCorner().getCorner()); + } else { + granularity = (byte) (pos.sectionDetail - dataDetail); + count = 1; + chunkPosMin = new DHChunkPos(pos.getCorner().getCorner()); + } + assert granularity >= minGenGranularity && granularity <= maxGenGranularity; + assert count > 0; + assert granularity >= 4; // Thanks compiler. Guess having a 'always true' warning means I did it right. + + CompletableFuture> dataFuture = generator.generate(chunkPosMin, granularity); + + dataFuture.whenComplete((data, ex) -> { + if (ex != null) { + logger.error("Error generating data for section " + pos + ": " + ex); + return; + } + assert data != null; + if (data.gridSize != count) { + logger.error("Generated data grid size (" + data.gridSize + + ") does not match expected size (" + count + ") for section " + pos); + return; + } + final byte sectionDetail = (byte) (dataDetail + FullDataSource.SECTION_SIZE_OFFSET); + data.forEachPos((x,z) -> { + ChunkSizedData chunkData = data.get(x,z); + DhLodPos chunkDataPos = new DhLodPos((byte) (dataDetail + 4), x, z).convertUpwardsTo(sectionDetail); + DhSectionPos sectionPos = new DhSectionPos(chunkDataPos.detail, chunkDataPos.x, chunkDataPos.z); + write(sectionPos, chunkData); + }); + }); + + } +} diff --git a/src/main/java/com/seibel/lod/core/a7/generation/IChunkGenerator.java b/src/main/java/com/seibel/lod/core/a7/generation/IChunkGenerator.java new file mode 100644 index 000000000..aac2ce518 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/a7/generation/IChunkGenerator.java @@ -0,0 +1,23 @@ +package com.seibel.lod.core.a7.generation; + +import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; +import com.seibel.lod.core.a7.datatype.transform.LodDataBuilder; +import com.seibel.lod.core.objects.DHChunkPos; +import com.seibel.lod.core.util.gridList.ArrayGridList; +import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; + +import java.util.concurrent.CompletableFuture; + +public interface IChunkGenerator extends IGenerator { + CompletableFuture> generateChunks(DHChunkPos chunkPosMin, byte granularity); + + @Override + default CompletableFuture> generate(DHChunkPos chunkPosMin, byte granularity) { + return generateChunks(chunkPosMin, granularity).thenApply(chunks -> { + ArrayGridList chunkData = new ArrayGridList<>(chunks.gridSize); + chunks.forEachPos((x, y) -> chunkData.set(x, y, LodDataBuilder.createChunkData(chunks.get(x, y)))); + return chunkData; + }); + } + +} diff --git a/src/main/java/com/seibel/lod/core/a7/generation/IGenerator.java b/src/main/java/com/seibel/lod/core/a7/generation/IGenerator.java new file mode 100644 index 000000000..11a4c3e60 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/a7/generation/IGenerator.java @@ -0,0 +1,31 @@ +package com.seibel.lod.core.a7.generation; + +import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; +import com.seibel.lod.core.objects.DHChunkPos; +import com.seibel.lod.core.util.gridList.ArrayGridList; + +import java.util.concurrent.CompletableFuture; + +public interface IGenerator extends AutoCloseable { + // What is the detail / resolution of the data? (This will offset the generation granularity) + // (minimum detail is 0, maximum detail is 255) (though that high isn't really... realistic) + // (0 = 1x1 block per data, 1 = 2x2 block per data, 2 = 4x4 block per data... etc.) + // TODO: System currently only supports 1x1 block per data. + byte getDataDetail(); + // What is the min batch size of a single generation? + // (minimum return value is 4 since that's the MC chunk size) + // (4 -> 16x16 data per call, 5 -> 32x32 data per call, 6 -> 64x64 data per call... etc.) + byte getMinGenerationGranularity(); + // What is the max batch size of a single generation? + // (minimum return value is 4 since that's the MC chunk size) + // (4 -> 16x16 data per call, 5 -> 32x32 data per call, 6 -> 64x64 data per call... etc.) + byte getMaxGenerationGranularity(); + + // Start a generation event + // (Note that the chunkPos is always aligned to the granularity) + // (For example, if the granularity is 4, data detail is 0, the chunkPos will be aligned to 16x16 blocks) + CompletableFuture> generate(DHChunkPos chunkPosMin, byte granularity); + + // Return whether the generator is currently busy and cannot accept new generation requests. + boolean isBusy(); +} diff --git a/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java b/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java index 56156e4d9..77e0740eb 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java @@ -1,5 +1,6 @@ package com.seibel.lod.core.a7.level; +import com.seibel.lod.core.a7.generation.GenerationQueue; import com.seibel.lod.core.a7.render.LodQuadTree; import com.seibel.lod.core.a7.util.FileScanner; import com.seibel.lod.core.a7.save.io.file.LocalDataFileHandler; @@ -26,6 +27,7 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel { private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); public final LocalSaveStructure save; public final LocalDataFileHandler dataFileHandler; + public GenerationQueue generationQueue = null; public RenderFileHandler renderFileHandler = null; public RenderBufferHandler renderBufferHandler = null; //TODO: Should this be owned by renderer? public final ILevelWrapper level; @@ -54,7 +56,9 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel { LOGGER.warn("Tried to call startRenderer() on the clientServerLevel {} when renderer is already setup!", level); return; } - renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level)); + + generationQueue = new GenerationQueue((a,b) -> renderFileHandler.write(a,b)); // FIXME: Ops. A need B and B need A... Does this work? + renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level), generationQueue); tree = new LodQuadTree(this, Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16, MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler); renderBufferHandler = new RenderBufferHandler(tree); @@ -84,6 +88,7 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel { renderFileHandler.flushAndSave(); //Ignore the completion feature so that this action is async renderFileHandler.close(); renderFileHandler = null; + generationQueue = null; } @Override diff --git a/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java b/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java index 15122031c..478f13407 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java @@ -5,5 +5,4 @@ import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; public interface IServerLevel extends ILevel { void serverTick(); void doWorldGen(); - void submitChunkData(ChunkSizedData data); } diff --git a/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java b/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java index de60ae330..25c7aebd2 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java @@ -363,6 +363,8 @@ public class LodQuadTree { } else { if (!section.isLoaded() && !section.isLoading()) { section.load(renderSourceProvider); + } else if (section.isOutdated()) { + section.reload(renderSourceProvider); } if (section.childCount == 4) section.enableRender(level, this); if (section.childCount == 0) section.disableRender(); diff --git a/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java index 984fac7d4..1b3ca1f81 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java +++ b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java @@ -47,6 +47,13 @@ public class LodRenderSection { if (loadFuture != null || lodRenderSource != null) throw new IllegalStateException("Reloading is not supported!"); loadFuture = renderDataProvider.read(pos); } + public void reload(IRenderSourceProvider renderDataProvider) { + if (loadFuture != null) throw new IllegalStateException("This section is already loading!"); + if (lodRenderSource == null) throw new IllegalStateException("This section is not loaded!"); + lodRenderSource.dispose(); + lodRenderSource = null; + loadFuture = renderDataProvider.read(pos); + } public void tick(LodQuadTree quadTree) { if (loadFuture != null && loadFuture.isDone()) { @@ -78,6 +85,10 @@ public class LodRenderSection { return loadFuture != null; } + public boolean isOutdated() { + return lodRenderSource != null && !lodRenderSource.isValid(); + } + public LodRenderSource getRenderContainer() { return lodRenderSource; } diff --git a/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java b/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java index 59887e115..fe2f1ed00 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java +++ b/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java @@ -1,6 +1,7 @@ package com.seibel.lod.core.a7.render; import com.seibel.lod.core.a7.datatype.LodRenderSource; +import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; import com.seibel.lod.core.objects.Pos2D; import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.render.LodRenderProgram; diff --git a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java index a876c6f44..53470e34e 100644 --- a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java +++ b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java @@ -1,23 +1,16 @@ package com.seibel.lod.core.a7.save.io.render; import com.google.common.collect.HashMultimap; -import com.seibel.lod.core.a7.datatype.EmptyRenderSource; -import com.seibel.lod.core.a7.datatype.LodDataSource; +import com.seibel.lod.core.a7.PlaceHolderQueue; +import com.seibel.lod.core.a7.datatype.PlaceHolderRenderSource; import com.seibel.lod.core.a7.datatype.LodRenderSource; -import com.seibel.lod.core.a7.datatype.RenderSourceLoader; -import com.seibel.lod.core.a7.datatype.column.ColumnRenderLoader; -import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource; import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; -import com.seibel.lod.core.a7.datatype.full.FullFormat; import com.seibel.lod.core.a7.level.IClientLevel; -import com.seibel.lod.core.a7.save.io.file.DataMetaFile; import com.seibel.lod.core.a7.save.io.file.IDataSourceProvider; import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.logging.DhLoggerBuilder; -import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.util.LodUtil; import org.apache.logging.log4j.Logger; -import org.lwjgl.system.CallbackI; import java.io.File; import java.io.IOException; @@ -33,11 +26,13 @@ public class RenderFileHandler implements IRenderSourceProvider { final IClientLevel level; final File saveDir; final IDataSourceProvider dataSourceProvider; + final PlaceHolderQueue placeHolderQueue; - public RenderFileHandler(IDataSourceProvider sourceProvider, IClientLevel level, File saveRootDir) { + public RenderFileHandler(IDataSourceProvider sourceProvider, IClientLevel level, File saveRootDir, PlaceHolderQueue placeHolderQueue) { this.dataSourceProvider = sourceProvider; this.level = level; this.saveDir = saveRootDir; + this.placeHolderQueue = placeHolderQueue; } /* @@ -118,7 +113,9 @@ public class RenderFileHandler implements IRenderSourceProvider { LOGGER.error("Uncaught error on {}:", pos, e); } if (render != null) return render; - return EmptyRenderSource.INSTANCE; + PlaceHolderRenderSource placeHolder = new PlaceHolderRenderSource(pos); + placeHolderQueue.track(placeHolder); + return placeHolder; } ); } diff --git a/src/main/java/com/seibel/lod/core/builders/worldGeneration/BatchGenerator.java b/src/main/java/com/seibel/lod/core/builders/worldGeneration/BatchGenerator.java index 9adf87617..3bc3b7bb6 100644 --- a/src/main/java/com/seibel/lod/core/builders/worldGeneration/BatchGenerator.java +++ b/src/main/java/com/seibel/lod/core/builders/worldGeneration/BatchGenerator.java @@ -19,24 +19,29 @@ package com.seibel.lod.core.builders.worldGeneration; +import com.seibel.lod.core.a7.generation.IChunkGenerator; import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.config.Config; import com.seibel.lod.core.enums.config.EDistanceGenerationMode; import com.seibel.lod.core.enums.config.EGenerationPriority; import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; import com.seibel.lod.core.logging.DhLoggerBuilder; +import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.objects.PosToGenerateContainer; import com.seibel.lod.core.util.LevelPosUtil; import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.util.gridList.ArrayGridList; import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; +import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper; import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper.Steps; import org.apache.logging.log4j.Logger; import java.lang.invoke.MethodHandles; +import java.util.concurrent.CompletableFuture; -public class BatchGenerator +public class BatchGenerator implements IChunkGenerator { public static final boolean ENABLE_GENERATOR_STATS_LOGGING = false; @@ -254,4 +259,60 @@ public class BatchGenerator generationGroup.stop(blocking); } + @Override + public boolean isBusy() { + return generationGroup.getEventCount() > previousThreadCount*1.5; + } + + @Override + public CompletableFuture> generateChunks(DHChunkPos chunkPosMin, byte granularity) { + EDistanceGenerationMode mode = Config.Client.WorldGenerator.distanceGenerationMode.get(); + Steps targetStep = null; + switch (mode) { + case NONE: + targetStep = Steps.Empty; // NOTE: Only load in existing chunks. No new chunk generation + break; + case BIOME_ONLY: + targetStep = Steps.Biomes; // NOTE: No block. Require fake height in LodBuilder + break; + case BIOME_ONLY_SIMULATE_HEIGHT: + targetStep = Steps.Noise; // NOTE: Stone only. Require fake surface + break; + case SURFACE: + targetStep = Steps.Surface; // Carvers or Surface??? + break; + case FEATURES: + case FULL: + targetStep = Steps.Features; + break; + }; + + + int chunkXMin = chunkPosMin.x; + int chunkZMin = chunkPosMin.z; + int genChunkSize = 1 << (granularity - 4); // minus 4 for chunk size as its equal to div by 16 + double runTimeRatio = Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get()>1 ? 1.0 + : Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get(); + return generationGroup.generateChunks(chunkXMin, chunkZMin, genChunkSize, targetStep, runTimeRatio); + } + + @Override + public byte getDataDetail() { + return 0; + } + + @Override + public byte getMinGenerationGranularity() { + return 4; + } + + @Override + public byte getMaxGenerationGranularity() { + return 16; + } + + @Override + public void close() { + stop(true); + } } diff --git a/src/main/java/com/seibel/lod/core/objects/DHChunkPos.java b/src/main/java/com/seibel/lod/core/objects/DHChunkPos.java index c9cab4f0c..3abc5cdb6 100644 --- a/src/main/java/com/seibel/lod/core/objects/DHChunkPos.java +++ b/src/main/java/com/seibel/lod/core/objects/DHChunkPos.java @@ -38,6 +38,10 @@ public class DHChunkPos { this.x = blockPos.x >> 4; // Same as div 16 this.z = blockPos.z >> 4; // Same as div 16 } + public DHChunkPos(DhBlockPos2D blockPos) { + this.x = blockPos.x >> 4; // Same as div 16 + this.z = blockPos.z >> 4; // Same as div 16 + } public DHBlockPos center() { return new DHBlockPos(8 + x << 4, 0, 8 + z << 4); diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/worldGeneration/AbstractBatchGenerationEnvionmentWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/worldGeneration/AbstractBatchGenerationEnvionmentWrapper.java index 84d976dde..de9246b01 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/worldGeneration/AbstractBatchGenerationEnvionmentWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/worldGeneration/AbstractBatchGenerationEnvionmentWrapper.java @@ -20,6 +20,10 @@ package com.seibel.lod.core.wrapperInterfaces.worldGeneration; import com.seibel.lod.core.a7.level.ILevel; +import com.seibel.lod.core.util.gridList.ArrayGridList; +import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; + +import java.util.concurrent.CompletableFuture; public abstract class AbstractBatchGenerationEnvionmentWrapper { public enum Steps { @@ -31,11 +35,15 @@ public abstract class AbstractBatchGenerationEnvionmentWrapper { public abstract void resizeThreadPool(int newThreadCount); + @Deprecated public abstract void updateAllFutures(); public abstract int getEventCount(); + @Deprecated public abstract boolean tryAddPoint(int chunkX, int chunkZ, int genSize, Steps targetStep, boolean genAllDetails, double runTimeRatio); public abstract void stop(boolean blocking); + + public abstract CompletableFuture> generateChunks(int minX, int minZ, int genSize, Steps targetStep, double runTimeRatio); }