From 1b27161518b7e1bb36de0b1b33ce04eaa0f87e05 Mon Sep 17 00:00:00 2001 From: tom lee Date: Tue, 8 Feb 2022 13:41:19 +0800 Subject: [PATCH] Make Far Pos gen no longer saves all detail level, speed up far gen tons --- .../com/seibel/lod/core/api/ClientApi.java | 2 +- .../core/builders/lodBuilding/LodBuilder.java | 115 ++++++++++++++---- .../worldGeneration/BatchGenerator.java | 8 +- .../lod/core/objects/lod/LodDimension.java | 2 +- .../lod/core/objects/lod/LodRegion.java | 3 +- .../seibel/lod/core/util/DataPointUtil.java | 20 ++- ...tractBatchGenerationEnvionmentWrapper.java | 2 +- 7 files changed, 118 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/api/ClientApi.java b/src/main/java/com/seibel/lod/core/api/ClientApi.java index 26e4ccf9c..a7932e486 100644 --- a/src/main/java/com/seibel/lod/core/api/ClientApi.java +++ b/src/main/java/com/seibel/lod/core/api/ClientApi.java @@ -184,7 +184,7 @@ public class ClientApi generating.add(pos); //ClientApi.LOGGER.info("Lod Generation trying "+pos+". Remining: " +toBeLoaded.size()); ApiShared.lodBuilder.generateLodNodeAsync(chunk, ApiShared.lodWorld, - world.getDimensionType(), DistanceGenerationMode.FULL, true, () -> { + world.getDimensionType(), DistanceGenerationMode.FULL, true, true, () -> { //ClientApi.LOGGER.info("Lod Generation for "+pos+" done. Remining: " +toBeLoaded.size()); generating.remove(pos); }, () -> { diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java index 220fc0d97..8b660ea56 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java @@ -32,12 +32,14 @@ import com.seibel.lod.core.objects.lod.LodWorld; import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.DataPointUtil; import com.seibel.lod.core.util.DetailDistanceUtil; +import com.seibel.lod.core.util.LevelPosUtil; import com.seibel.lod.core.util.LodThreadFactory; import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.SingletonHandler; import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorSingletonWrapper; import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper; import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper; +import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; @@ -90,15 +92,15 @@ public class LodBuilder } - public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim) + public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, boolean genAll) { // Block change event - generateLodNodeAsync(chunk, lodWorld, dim, DistanceGenerationMode.FULL, true, ()->{}, - ()->{generateLodNodeAsync(chunk,lodWorld,dim);}); + generateLodNodeAsync(chunk, lodWorld, dim, DistanceGenerationMode.FULL, true, genAll, ()->{}, + ()->{generateLodNodeAsync(chunk,lodWorld,dim, genAll);}); } public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, - DistanceGenerationMode generationMode, boolean override, Runnable endCallback, Runnable retryCallback) + DistanceGenerationMode generationMode, boolean override, boolean genAll, Runnable endCallback, Runnable retryCallback) { if (lodWorld == null || lodWorld.getIsWorldNotLoaded()) { endCallback.run(); @@ -132,7 +134,7 @@ public class LodBuilder LodDimension lodDim = lodWorld.getLodDimension(dim); if (lodDim == null) return; - retryNeeded = !generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode), override); + retryNeeded = !generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode), override, genAll); } catch (RuntimeException e) { @@ -154,28 +156,19 @@ public class LodBuilder * Creates a LodNode for a chunk in the given world. * @throws IllegalArgumentException thrown if either the chunk or world is null. */ - public boolean generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config, boolean override) - throws IllegalArgumentException + public boolean generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config, boolean override, boolean genAll) { - //config.distanceGenerationMode = DistanceGenerationMode.FULL; - - //long executeTime = System.currentTimeMillis(); if (chunk == null) throw new IllegalArgumentException("generateLodFromChunk given a null chunk"); - LodRegion region = lodDim.getRegion(chunk.getRegionPosX(), chunk.getRegionPosZ()); if (region == null) return false; - // this happens if a LOD is generated after the user leaves the world. if (MC.getWrappedClientWorld() == null) return false; - if (!chunk.isLightCorrect()) return false; - // determine how many LODs to generate vertically - //VerticalQuality verticalQuality = LodConfig.CLIENT.graphics.qualityOption.verticalQuality.get(); - + // generate the LODs int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte)0); long[] data = new long[maxVerticalData*16*16]; @@ -199,9 +192,19 @@ public class LodBuilder data[i*maxVerticalData] = DataPointUtil.createVoidDataPoint(config.distanceGenerationMode.complexity); } } - if (!chunk.isLightCorrect()) return false; + if (genAll) { + return writeAllLodNodeData(lodDim, region, chunk.getChunkPosX(), chunk.getChunkPosZ(), data, config, override); + } else { + return writePartialLodNodeData(lodDim, region, chunk.getChunkPosX(), chunk.getChunkPosZ(), data, config, override); + } + + } + + private boolean writeAllLodNodeData(LodDimension lodDim, LodRegion region, int chunkX, int chunkZ, + long[] data, LodBuilderConfig config, boolean override) + { region.isWriting++; try { if (region.getMinDetailLevel()!= 0) { @@ -216,25 +219,89 @@ public class LodBuilder } //ClientApi.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}", // chunk.getChunkPosX(), chunk.getChunkPosZ(), chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode); - region.addChunkOfData((byte)0, chunk.getMinX(), chunk.getMinZ(), 16, 16, data, maxVerticalData, override); - region.regenerateLodFromArea((byte)0, chunk.getMinX(), chunk.getMinZ(), 16, 16); + region.addChunkOfData((byte)0, chunkX*16, chunkZ*16, 16, 16, data, data.length/16/16, override); + region.regenerateLodFromArea((byte)0, chunkX*16, chunkZ*16, 16, 16); lodDim.regenDimensionBuffers = true; - if (!region.doesDataExist((byte)0, chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode)) + if (!region.doesDataExist((byte)0, chunkX*16, chunkZ*16, config.distanceGenerationMode)) throw new RuntimeException("data at detail 0 is still null after writes to it!"); - if (!region.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getChunkPosX(), chunk.getChunkPosZ(), config.distanceGenerationMode)) + if (!region.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, chunkZ, config.distanceGenerationMode)) throw new RuntimeException("data at chunk detail level is still null after writes to it!"); } catch (Exception e) { e.printStackTrace(); } finally { region.isWriting--; } - return true; - //executeTime = System.currentTimeMillis() - executeTime; - //if (executeTime > 0) ClientApi.LOGGER.info("generateLodNodeFromChunk level: " + detailLevel + " time ms: " + executeTime); } + private boolean writePartialLodNodeData(LodDimension lodDim, LodRegion region, int chunkX, int chunkZ, + long[] data, LodBuilderConfig config, boolean override) + { + region.isWriting++; + try { + byte targetLevel = region.getMinDetailLevel(); + int vertQual = DetailDistanceUtil.getMaxVerticalData(targetLevel); + int lodCount = (targetLevel >= LodUtil.CHUNK_DETAIL_LEVEL) ? + 1 : 1 << (LodUtil.CHUNK_DETAIL_LEVEL - targetLevel); + if (targetLevel != 0) { + int lodWidth = 16/lodCount; + int inputVertQual = data.length/16/16; + long[] mergedData = new long[vertQual*lodCount*lodCount]; + for (int subX=0; subX LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize; - if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep)) { + if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, false)) { toGenerate--; } } @@ -174,7 +174,7 @@ public class BatchGenerator { int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, true)); int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, true)); int genSize = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize; - if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep)) { + if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, true)) { toGenerate--; } } @@ -193,7 +193,7 @@ public class BatchGenerator { int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, true)); int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, true)); int genSize = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize; - if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep)) { + if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, true)) { toGenerate--; } if (toGenerate <= 0) @@ -212,7 +212,7 @@ public class BatchGenerator { int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, false)); int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, false)); int genSize = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? 0 : generationGroupSize; - if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep)) { + if (generationGroup.tryAddPoint(chunkX, chunkZ, genSize, targetStep, false)) { toGenerate--; } } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java index 042f51f0f..662c2bdcf 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java @@ -464,7 +464,7 @@ public class LodDimension // This ensures that we don't spawn way too much regions without finish flushing them first. - if (dirtiedRegionsRoughCount > 16) return posToGenerate; + //if (dirtiedRegionsRoughCount > 16) return posToGenerate; GenerationPriority allowedPriority = dirtiedRegionsRoughCount>12 ? GenerationPriority.NEAR_FIRST : priority; Pos minPos = regions.getMinInRange(); iterateByDistance((int x, int z) -> { diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java index aba1b2cf0..f79cd15bb 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java @@ -507,8 +507,7 @@ public class LodRegion { } /** - * Returns the lowest (least detailed) detail level in this region TODO is that - * right? + * Returns the lowest (least detailed) detail level in this region */ public byte getMinDetailLevel() { return minDetailLevel; diff --git a/src/main/java/com/seibel/lod/core/util/DataPointUtil.java b/src/main/java/com/seibel/lod/core/util/DataPointUtil.java index e0509ddeb..e73c5532a 100644 --- a/src/main/java/com/seibel/lod/core/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/core/util/DataPointUtil.java @@ -309,6 +309,24 @@ public class DataPointUtil } return anyChange; } + + // Extract a section of data from the 2D data array + public static long[] extractDataArray(long[] source, int inWidth, int inHeight, int outX, int outY, int outWidth, int outHeight) { + int dataSetSize = source.length/inWidth/inHeight; + if (dataSetSize*inWidth*inHeight != source.length) + throw new ArrayIndexOutOfBoundsException("\"source\" array invalid width and height"); + if (outWidth > inWidth || outX + outWidth > inWidth) + throw new ArrayIndexOutOfBoundsException("X index out of bounds"); + if (outHeight > inHeight || outY + outHeight > inHeight) + throw new ArrayIndexOutOfBoundsException("Y index out of bounds"); + long[] out = new long[dataSetSize*outWidth*outHeight]; + for (int x=0; x tLocalHeightAndDepth = new ThreadLocal(); private static final ThreadLocal tMaxVerticalData = new ThreadLocal(); @@ -330,7 +348,7 @@ public class DataPointUtil heightAndDepth = new short[heightAndDepthLength]; tLocalHeightAndDepth.set(heightAndDepth); } - int dataPointLength = DetailDistanceUtil.getMaxVerticalData(0); + int dataPointLength = maxVerticalData; long[] dataPoint = tMaxVerticalData.get(); if (dataPoint==null || dataPoint.length != dataPointLength) { dataPoint = new long[dataPointLength]; 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 51c418281..0c022ecff 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 @@ -19,7 +19,7 @@ public abstract class AbstractBatchGenerationEnvionmentWrapper { public abstract int getEventCount(); - public abstract boolean tryAddPoint(int chunkX, int chunkZ, int genSize, Steps targetStep); + public abstract boolean tryAddPoint(int chunkX, int chunkZ, int genSize, Steps targetStep, boolean genAllDetails); public abstract void stop(boolean blocking); }