Make Far Pos gen no longer saves all detail level, speed up far gen tons

This commit is contained in:
tom lee
2022-02-08 13:41:19 +08:00
parent b51cb7ca51
commit 1b27161518
7 changed files with 118 additions and 34 deletions
@@ -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);
}, () -> {
@@ -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<lodCount; subX++) {
for (int subZ=0; subZ<lodCount; subZ++) {
long[] toBeMerged = DataPointUtil.extractDataArray(
data, 16, 16, subX*lodWidth, subZ*lodWidth, lodWidth, lodWidth);
if(toBeMerged.length != lodWidth*lodWidth*inputVertQual) throw new RuntimeException();
long[] merged = DataPointUtil.mergeMultiData(toBeMerged, inputVertQual, vertQual);
if (merged.length != vertQual) throw new RuntimeException();
if (!DataPointUtil.doesItExist(merged[0]) ||
DataPointUtil.getGenerationMode(merged[0]) != config.distanceGenerationMode.complexity)
throw new RuntimeException();
System.arraycopy(merged, 0, mergedData, (subZ+subX*lodCount)*vertQual, vertQual);
}
}
data = mergedData;
}
if (lodCount*lodCount*vertQual != data.length) throw new RuntimeException();
for (int i=0; i<data.length; i+=vertQual) {
if (!DataPointUtil.doesItExist(data[i]) ||
DataPointUtil.getGenerationMode(data[i]) != config.distanceGenerationMode.complexity) {
ClientApi.LOGGER.error("NULL data at {}, detail {}, vertQual {}, lodCount {}, chunkPos [{},{}]\n"
+ "Data: {}",
i, targetLevel, vertQual, lodCount, chunkX, chunkZ, DataPointUtil.toString(data[i]));
throw new RuntimeException("Null data!");
}
}
//ClientApi.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}",
// chunk.getChunkPosX(), chunk.getChunkPosZ(), chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode);
region.addChunkOfData(targetLevel,
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, targetLevel),
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkZ, targetLevel),
lodCount, lodCount, data, vertQual, override);
region.regenerateLodFromArea(targetLevel,
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, targetLevel),
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkZ, targetLevel),
lodCount, lodCount);
lodDim.regenDimensionBuffers = true;
if (!region.doesDataExist(targetLevel,
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, targetLevel),
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkZ, targetLevel),
config.distanceGenerationMode))
throw new RuntimeException("data at detail 0 is still null after writes to it!");
} catch (Exception e) {
e.printStackTrace();
} finally {
region.isWriting--;
}
return true;
}
/** creates a vertical DataPoint */
private void writeVerticalData(long[] data, int dataOffset, int maxVerticalData,
IChunkWrapper chunk, LodBuilderConfig config, int chunkSubPosX, int chunkSubPosZ)
@@ -160,7 +160,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--;
}
}
@@ -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--;
}
}
@@ -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) -> {
@@ -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;
@@ -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<outWidth; x++) {
System.arraycopy(source, ((outX+x)*inHeight+outY)*dataSetSize,
out, (x*outHeight)*dataSetSize,
outHeight*dataSetSize);
}
return out;
}
private static final ThreadLocal<short[]> tLocalHeightAndDepth = new ThreadLocal<short[]>();
private static final ThreadLocal<long[]> tMaxVerticalData = new ThreadLocal<long[]>();
@@ -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];
@@ -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);
}