Errr....
1. Make VerticalQuality overall is higher. 2. Rework how FAR_FIRST works. 3. Clean up some stuff.
This commit is contained in:
@@ -19,7 +19,9 @@
|
||||
|
||||
package com.seibel.lod.core.api;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -60,6 +62,22 @@ public class ClientApi
|
||||
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||
private static final IWrapperFactory FACTORY = SingletonHandler.get(IWrapperFactory.class);
|
||||
private static final EventApi EVENT_API = EventApi.INSTANCE;
|
||||
|
||||
public static final boolean ENABLE_LAG_SPIKE_LOGGING = true;
|
||||
public static final long LAG_SPIKE_THRESOLD_NS = TimeUnit.NANOSECONDS.convert(16, TimeUnit.MILLISECONDS);
|
||||
|
||||
public static class LagSpikeCatcher {
|
||||
|
||||
long timer = System.nanoTime();
|
||||
public LagSpikeCatcher() {}
|
||||
public void end(String source) {
|
||||
if (!ENABLE_LAG_SPIKE_LOGGING) return;
|
||||
timer = System.nanoTime() - timer;
|
||||
if (timer > LAG_SPIKE_THRESOLD_NS) {
|
||||
ClientApi.LOGGER.info("LagSpikeCatcher: "+source+" took "+Duration.ofNanos(timer)+"!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* there is some setup that should only happen once,
|
||||
@@ -81,8 +99,10 @@ public class ClientApi
|
||||
|
||||
public void clientChunkLoadEvent(IChunkWrapper chunk, IWorldWrapper world)
|
||||
{
|
||||
LagSpikeCatcher clientChunkLoad = new LagSpikeCatcher();
|
||||
//ClientApi.LOGGER.info("Lod Generating add: "+chunk.getLongChunkPos());
|
||||
toBeLoaded.add(chunk.getLongChunkPos());
|
||||
clientChunkLoad.end("clientChunkLoad");
|
||||
}
|
||||
|
||||
//private HashSet<AbstractChunkPosWrapper> lastFrame = new HashSet<AbstractChunkPosWrapper>();
|
||||
@@ -115,7 +135,8 @@ public class ClientApi
|
||||
ApiShared.lodBuilder.defaultDimensionWidthInRegions);
|
||||
ApiShared.lodWorld.addLodDimension(lodDim);
|
||||
}
|
||||
|
||||
|
||||
LagSpikeCatcher updateToBeLoadedChunk = new LagSpikeCatcher();
|
||||
for (long pos : toBeLoaded) {
|
||||
if (generating.size() >= 8) {
|
||||
//ClientApi.LOGGER.info("Lod Generating Full! Remining: "+toBeLoaded.size());
|
||||
@@ -139,18 +160,24 @@ public class ClientApi
|
||||
toBeLoaded.add(pos);
|
||||
});
|
||||
}
|
||||
updateToBeLoadedChunk.end("updateToBeLoadedChunk");
|
||||
|
||||
|
||||
|
||||
|
||||
LagSpikeCatcher updateSettings = new LagSpikeCatcher();
|
||||
DetailDistanceUtil.updateSettings();
|
||||
EVENT_API.viewDistanceChangedEvent();
|
||||
updateSettings.end("updateSettings");
|
||||
LagSpikeCatcher updatePlayerMove = new LagSpikeCatcher();
|
||||
EVENT_API.playerMoveEvent(lodDim);
|
||||
updatePlayerMove.end("updatePlayerMove");
|
||||
|
||||
|
||||
|
||||
|
||||
LagSpikeCatcher cutAndExpendAsync = new LagSpikeCatcher();
|
||||
lodDim.cutRegionNodesAsync(MC.getPlayerBlockPos().getX(), MC.getPlayerBlockPos().getZ());
|
||||
lodDim.expandOrLoadRegionsAsync(MC.getPlayerBlockPos().getX(), MC.getPlayerBlockPos().getZ());
|
||||
cutAndExpendAsync.end("cutAndExpendAsync");
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.seibel.lod.core.api.ClientApi;
|
||||
import com.seibel.lod.core.enums.LodDirection;
|
||||
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
|
||||
import com.seibel.lod.core.objects.lod.LodDimension;
|
||||
import com.seibel.lod.core.objects.lod.LodRegion;
|
||||
@@ -205,7 +206,7 @@ public class LodBuilder
|
||||
lodDim.regenDimensionBuffers = true;
|
||||
|
||||
if (!region.doesDataExist((byte)0, chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode))
|
||||
throw new RuntimeException();
|
||||
throw new RuntimeException("data at detail 0 is still null after writes to it!");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
@@ -247,8 +248,8 @@ public class LodBuilder
|
||||
y = height - 1;
|
||||
// We search light on above air block
|
||||
int depth = determineBottomPointFrom(chunk, config, x, y, z,
|
||||
count < this.config.client().graphics().quality().getVerticalQuality().maxConnectedLods
|
||||
&& !hasCeiling);
|
||||
//count < this.config.client().graphics().quality().getVerticalQuality().maxConnectedLods &&
|
||||
(!hasCeiling || !topBlock));
|
||||
if (hasCeiling && topBlock)
|
||||
y = depth;
|
||||
int light = getLightValue(chunk, x, y, z, hasCeiling, hasSkyLight, topBlock);
|
||||
@@ -266,6 +267,27 @@ public class LodBuilder
|
||||
if (result.length != maxVerticalData) throw new ArrayIndexOutOfBoundsException();
|
||||
System.arraycopy(result, 0, data, dataOffset, maxVerticalData);
|
||||
}
|
||||
|
||||
public static final LodDirection[] DIRECTIONS = new LodDirection[] {
|
||||
LodDirection.UP,
|
||||
LodDirection.DOWN,
|
||||
LodDirection.WEST,
|
||||
LodDirection.EAST,
|
||||
LodDirection.NORTH,
|
||||
LodDirection.SOUTH };
|
||||
|
||||
private boolean hasCliffFace(IChunkWrapper chunk, int x, int y, int z) {
|
||||
for (LodDirection dir : DIRECTIONS) {
|
||||
int cx = x+dir.getNormal().x;
|
||||
int cy = y+dir.getNormal().y;
|
||||
int cz = z+dir.getNormal().z;
|
||||
if (!chunk.blockPosInsideChunk(cx, cy, cz)) continue;
|
||||
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(cx, cy, cz);
|
||||
if (block == null || block.hasNoCollision() || block.isToAvoid() || block.isNonFull() || block.hasNoCollision())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the lowest valid point from the bottom.
|
||||
@@ -293,9 +315,9 @@ public class LodBuilder
|
||||
|
||||
for (int y = yAbs - 1; y >= chunk.getMinBuildHeight(); y--)
|
||||
{
|
||||
|
||||
if (!isLayerValidLodPoint(chunk, xAbs, y, zAbs)
|
||||
|| (strictEdge && colorOfBlock != chunk.getBlockColorWrapper(xAbs, y, zAbs).getColor()))
|
||||
|| (strictEdge && hasCliffFace(chunk, xAbs, y, zAbs)
|
||||
&& colorOfBlock != chunk.getBlockColorWrapper(xAbs, y, zAbs).getColor()))
|
||||
{
|
||||
depth = (short) (y + 1);
|
||||
break;
|
||||
|
||||
@@ -29,21 +29,23 @@ package com.seibel.lod.core.enums.config;
|
||||
public enum VerticalQuality
|
||||
{
|
||||
LOW(
|
||||
new int[] { 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 },
|
||||
0
|
||||
new int[] { 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
|
||||
4
|
||||
),
|
||||
|
||||
MEDIUM(
|
||||
new int[] { 4, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1 },
|
||||
1
|
||||
new int[] { 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
|
||||
8
|
||||
),
|
||||
|
||||
HIGH(
|
||||
new int[] { 8, 8, 4, 4, 2, 2, 2, 1, 1, 1, 1 },
|
||||
2
|
||||
new int[] { 16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1 },
|
||||
16
|
||||
);
|
||||
|
||||
public final int[] maxVerticalData;
|
||||
|
||||
@Deprecated // Will find other ways to optimize
|
||||
public final int maxConnectedLods;
|
||||
|
||||
VerticalQuality(int[] maxVerticalData, int maxConnectedLods)
|
||||
|
||||
@@ -31,7 +31,6 @@ public class PosToGenerateContainer
|
||||
{
|
||||
private final int playerPosX;
|
||||
private final int playerPosZ;
|
||||
public final byte farMinDetail;
|
||||
private int nearSize;
|
||||
private int farSize;
|
||||
|
||||
@@ -39,14 +38,10 @@ public class PosToGenerateContainer
|
||||
private final int[][] nearPosToGenerate;
|
||||
private final int[][] farPosToGenerate;
|
||||
|
||||
|
||||
|
||||
|
||||
public PosToGenerateContainer(byte farMinDetail, int maxDataToGenerate, int playerPosX, int playerPosZ)
|
||||
public PosToGenerateContainer(int maxDataToGenerate, int playerPosX, int playerPosZ)
|
||||
{
|
||||
this.playerPosX = playerPosX;
|
||||
this.playerPosZ = playerPosZ;
|
||||
this.farMinDetail = farMinDetail;
|
||||
nearSize = 0;
|
||||
farSize = 0;
|
||||
nearPosToGenerate = new int[maxDataToGenerate][4];
|
||||
@@ -56,65 +51,67 @@ public class PosToGenerateContainer
|
||||
|
||||
|
||||
// TODO what is going on in this method?
|
||||
public void addPosToGenerate(byte detailLevel, int posX, int posZ, boolean sort)
|
||||
public void addNearPosToGenerate(byte detailLevel, int posX, int posZ, boolean sort)
|
||||
{
|
||||
int distance = LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ);
|
||||
int index;
|
||||
|
||||
if (detailLevel >= farMinDetail)
|
||||
{
|
||||
// We are introducing a position in the far array
|
||||
|
||||
index = farSize;
|
||||
if (index == farPosToGenerate.length) {
|
||||
if (LevelPosUtil.compareDistance(distance, farPosToGenerate[index - 1][3]) > 0) {
|
||||
return;
|
||||
}
|
||||
index--;
|
||||
} else farSize++;
|
||||
|
||||
if (sort) {
|
||||
while (index > 0 && LevelPosUtil.compareDistance(distance, farPosToGenerate[index - 1][3]) <= 0)
|
||||
{
|
||||
farPosToGenerate[index][0] = farPosToGenerate[index - 1][0];
|
||||
farPosToGenerate[index][1] = farPosToGenerate[index - 1][1];
|
||||
farPosToGenerate[index][2] = farPosToGenerate[index - 1][2];
|
||||
farPosToGenerate[index][3] = farPosToGenerate[index - 1][3];
|
||||
index--;
|
||||
}
|
||||
}
|
||||
farPosToGenerate[index][0] = detailLevel + 1;
|
||||
farPosToGenerate[index][1] = posX;
|
||||
farPosToGenerate[index][2] = posZ;
|
||||
farPosToGenerate[index][3] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We are introducing a position in the near array
|
||||
//We are introducing a position in the near array
|
||||
|
||||
index = nearSize;
|
||||
if (index == nearPosToGenerate.length) {
|
||||
if (LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) > 0) {
|
||||
return;
|
||||
}
|
||||
index--;
|
||||
} else nearSize++;
|
||||
|
||||
if (sort) {
|
||||
while (index > 0 && LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) <= 0)
|
||||
{
|
||||
nearPosToGenerate[index][0] = nearPosToGenerate[index - 1][0];
|
||||
nearPosToGenerate[index][1] = nearPosToGenerate[index - 1][1];
|
||||
nearPosToGenerate[index][2] = nearPosToGenerate[index - 1][2];
|
||||
nearPosToGenerate[index][3] = nearPosToGenerate[index - 1][3];
|
||||
index--;
|
||||
}
|
||||
index = nearSize;
|
||||
if (index == nearPosToGenerate.length) {
|
||||
if (LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) > 0) {
|
||||
return;
|
||||
}
|
||||
index--;
|
||||
} else nearSize++;
|
||||
|
||||
if (sort) {
|
||||
while (index > 0 && LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) <= 0)
|
||||
{
|
||||
nearPosToGenerate[index][0] = nearPosToGenerate[index - 1][0];
|
||||
nearPosToGenerate[index][1] = nearPosToGenerate[index - 1][1];
|
||||
nearPosToGenerate[index][2] = nearPosToGenerate[index - 1][2];
|
||||
nearPosToGenerate[index][3] = nearPosToGenerate[index - 1][3];
|
||||
index--;
|
||||
}
|
||||
nearPosToGenerate[index][0] = detailLevel + 1;
|
||||
nearPosToGenerate[index][1] = posX;
|
||||
nearPosToGenerate[index][2] = posZ;
|
||||
nearPosToGenerate[index][3] = distance;
|
||||
}
|
||||
nearPosToGenerate[index][0] = detailLevel + 1;
|
||||
nearPosToGenerate[index][1] = posX;
|
||||
nearPosToGenerate[index][2] = posZ;
|
||||
nearPosToGenerate[index][3] = distance;
|
||||
}
|
||||
|
||||
// TODO what is going on in this method?
|
||||
public void addFarPosToGenerate(byte detailLevel, int posX, int posZ, boolean sort)
|
||||
{
|
||||
int distance = LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ);
|
||||
int index;
|
||||
|
||||
// We are introducing a position in the far array
|
||||
|
||||
index = farSize;
|
||||
if (index == farPosToGenerate.length) {
|
||||
if (LevelPosUtil.compareDistance(distance, farPosToGenerate[index - 1][3]) > 0) {
|
||||
return;
|
||||
}
|
||||
index--;
|
||||
} else farSize++;
|
||||
|
||||
if (sort) {
|
||||
while (index > 0 && LevelPosUtil.compareDistance(distance, farPosToGenerate[index - 1][3]) <= 0)
|
||||
{
|
||||
farPosToGenerate[index][0] = farPosToGenerate[index - 1][0];
|
||||
farPosToGenerate[index][1] = farPosToGenerate[index - 1][1];
|
||||
farPosToGenerate[index][2] = farPosToGenerate[index - 1][2];
|
||||
farPosToGenerate[index][3] = farPosToGenerate[index - 1][3];
|
||||
index--;
|
||||
}
|
||||
}
|
||||
farPosToGenerate[index][0] = detailLevel + 1;
|
||||
farPosToGenerate[index][1] = posX;
|
||||
farPosToGenerate[index][2] = posZ;
|
||||
farPosToGenerate[index][3] = distance;
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
|
||||
@@ -398,7 +398,7 @@ public class LodDimension
|
||||
// and cut it if it is higher then that
|
||||
minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ,
|
||||
playerPosX, playerPosZ);
|
||||
detail = DetailDistanceUtil.getTreeCutDetailFromDistance(minDistance);
|
||||
detail = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
|
||||
if (region.getMinDetailLevel() < detail) {
|
||||
if (region.needSaving) return; // FIXME: A crude attempt at lowering chance of race condition!
|
||||
region.cutTree(detail);
|
||||
@@ -452,8 +452,8 @@ public class LodDimension
|
||||
playerPosZ);
|
||||
maxDistance = LevelPosUtil.maxDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX,
|
||||
playerPosZ);
|
||||
minDetail = DetailDistanceUtil.getTreeGenDetailFromDistance(minDistance);
|
||||
maxDetail = DetailDistanceUtil.getTreeGenDetailFromDistance(maxDistance);
|
||||
minDetail = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
|
||||
maxDetail = DetailDistanceUtil.getDetailLevelFromDistance(maxDistance);
|
||||
|
||||
boolean updated = false;
|
||||
if (region == null) {
|
||||
@@ -524,7 +524,7 @@ public class LodDimension
|
||||
GenerationPriority priority, DistanceGenerationMode genMode)
|
||||
{
|
||||
PosToGenerateContainer posToGenerate;
|
||||
posToGenerate = new PosToGenerateContainer((byte) 8, maxDataToGenerate, playerBlockPosX, playerBlockPosZ);
|
||||
posToGenerate = new PosToGenerateContainer(maxDataToGenerate, playerBlockPosX, playerBlockPosZ);
|
||||
|
||||
|
||||
// This ensures that we don't spawn way too much regions without finish flushing them first.
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package com.seibel.lod.core.objects.lod;
|
||||
|
||||
import com.seibel.lod.core.api.ClientApi;
|
||||
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
|
||||
import com.seibel.lod.core.enums.config.DropoffQuality;
|
||||
import com.seibel.lod.core.enums.config.GenerationPriority;
|
||||
@@ -71,6 +70,15 @@ public class LodRegion {
|
||||
public volatile int needRegenBuffer = 2;
|
||||
public volatile boolean needSaving = false;
|
||||
public volatile int isWriting = 0;
|
||||
|
||||
public static byte calculateFarModeSwitch(byte targetLevel) {
|
||||
if (targetLevel==0) return 0; // Always use detail 0 if it's way too close
|
||||
double part = targetLevel / (double)LodUtil.REGION_DETAIL_LEVEL;
|
||||
byte farModeLevel = LodUtil.DETAIL_OPTIONS-(LodUtil.CHUNK_DETAIL_LEVEL+1);
|
||||
farModeLevel *= part;
|
||||
farModeLevel += (LodUtil.CHUNK_DETAIL_LEVEL+1);
|
||||
return (byte)LodUtil.clamp(LodUtil.CHUNK_DETAIL_LEVEL+1, farModeLevel, LodUtil.DETAIL_OPTIONS - 1);
|
||||
}
|
||||
|
||||
public LodRegion(byte minDetailLevel, RegionPos regionPos, VerticalQuality verticalQuality) {
|
||||
this.minDetailLevel = minDetailLevel;
|
||||
@@ -145,7 +153,8 @@ public class LodRegion {
|
||||
// detailLevel changes.
|
||||
if (this.dataContainer[detailLevel] == null)
|
||||
return false;// this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
|
||||
if (this.dataContainer[detailLevel].getVerticalSize() != verticalSize) throw new RuntimeException();
|
||||
if (this.dataContainer[detailLevel].getVerticalSize() != verticalSize)
|
||||
throw new RuntimeException("Provided data's verticalSize is different from current storage's verticalSize!");
|
||||
|
||||
boolean updated = this.dataContainer[detailLevel].addChunkOfData(data, posX, posZ, widthX, widthZ, override);
|
||||
//ClientApi.LOGGER.info("addChunkOfData(region:{}, level:{}, x:{}, z:{}, wx:{}, wz:{}, override:{}, updated:{})",
|
||||
@@ -161,7 +170,7 @@ public class LodRegion {
|
||||
|
||||
}
|
||||
if (!doesDataExist(detailLevel, posX, posZ, DistanceGenerationMode.values()[DataPointUtil.getGenerationMode(data[0])])) {
|
||||
throw new RuntimeException();
|
||||
throw new RuntimeException("Data still doesn't exist after addChunkOfData!");
|
||||
}
|
||||
|
||||
return updated;
|
||||
@@ -219,43 +228,44 @@ public class LodRegion {
|
||||
// calculate what LevelPos are in range to generate
|
||||
int minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX,
|
||||
playerPosZ);
|
||||
|
||||
|
||||
// determine this child's levelPos
|
||||
byte childDetailLevel = (byte) (detailLevel - 1);
|
||||
int childOffsetPosX = offsetPosX * 2;
|
||||
int childOffsetPosZ = offsetPosZ * 2;
|
||||
DistanceGenerationMode testerGenMode = detailLevel > LodUtil.CHUNK_DETAIL_LEVEL ? DistanceGenerationMode.NONE : genMode;
|
||||
|
||||
|
||||
byte targetDetailLevel = DetailDistanceUtil.getGenerationDetailFromDistance(minDistance);
|
||||
|
||||
byte targetDetailLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
|
||||
byte farModeSwitchLevel = (priority == GenerationPriority.NEAR_FIRST) ? 0 : calculateFarModeSwitch(targetDetailLevel);
|
||||
|
||||
if (targetDetailLevel <= detailLevel) {
|
||||
if (targetDetailLevel == detailLevel) {
|
||||
if (!doesDataExist(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size, testerGenMode))
|
||||
posToGenerate.addPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
|
||||
if (!doesDataExist(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size, testerGenMode)) {
|
||||
if (detailLevel==farModeSwitchLevel && priority == GenerationPriority.FAR_FIRST)
|
||||
posToGenerate.addFarPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
|
||||
offsetPosZ + regionPosZ * size, shouldSort);
|
||||
} else {
|
||||
if (priority == GenerationPriority.FAR_FIRST && detailLevel >= posToGenerate.farMinDetail
|
||||
&& !doesDataExist(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size, testerGenMode)) {
|
||||
posToGenerate.addPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
|
||||
else
|
||||
posToGenerate.addNearPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
|
||||
offsetPosZ + regionPosZ * size, shouldSort);
|
||||
} else if (detailLevel > LodUtil.CHUNK_DETAIL_LEVEL) {
|
||||
for (int x = 0; x <= 1; x++)
|
||||
for (int z = 0; z <= 1; z++)
|
||||
getPosToGenerate(posToGenerate, childDetailLevel, childOffsetPosX + x, childOffsetPosZ + z, playerPosX,
|
||||
playerPosZ, priority, genMode, shouldSort);
|
||||
} else {
|
||||
// we want at max one request per chunk (since the world generator creates
|
||||
// chunks).
|
||||
// So for lod smaller than a chunk, only recurse down
|
||||
// the top right child
|
||||
getPosToGenerate(posToGenerate, childDetailLevel, childOffsetPosX, childOffsetPosZ, playerPosX, playerPosZ,
|
||||
priority, genMode, shouldSort);
|
||||
}
|
||||
} else if (detailLevel == farModeSwitchLevel
|
||||
&& !doesDataExist(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size, testerGenMode)) {
|
||||
posToGenerate.addFarPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
|
||||
offsetPosZ + regionPosZ * size, shouldSort);
|
||||
} else if (detailLevel > LodUtil.CHUNK_DETAIL_LEVEL) {
|
||||
for (int x = 0; x <= 1; x++)
|
||||
for (int z = 0; z <= 1; z++)
|
||||
getPosToGenerate(posToGenerate, childDetailLevel, childOffsetPosX + x, childOffsetPosZ + z, playerPosX,
|
||||
playerPosZ, priority, genMode, shouldSort);
|
||||
} else {
|
||||
// we want at max one request per chunk (since the world generator creates
|
||||
// chunks).
|
||||
// So for lod smaller than a chunk, only recurse down
|
||||
// the top right child
|
||||
getPosToGenerate(posToGenerate, childDetailLevel, childOffsetPosX, childOffsetPosZ, playerPosX, playerPosZ,
|
||||
priority, genMode, shouldSort);
|
||||
}
|
||||
}
|
||||
// we have gone beyond the target Detail level
|
||||
// we can stop generating
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,12 +278,15 @@ public class LodRegion {
|
||||
public void getPosToRender(PosToRenderContainer posToRender, int playerPosX, int playerPosZ,
|
||||
boolean requireCorrectDetailLevel, DropoffQuality dropoffQuality) {
|
||||
int minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ);
|
||||
byte targetLevel = DetailDistanceUtil.getDrawDetailFromDistance(minDistance);
|
||||
byte targetLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
|
||||
// FarModeSwitchLevel or above is the level where a giant block of lod is not acceptable even if not all child data exist.
|
||||
byte farModeSwitchLevel = requireCorrectDetailLevel ? 0 : calculateFarModeSwitch(targetLevel);
|
||||
if (requireCorrectDetailLevel) farModeSwitchLevel = 0;
|
||||
if (targetLevel <= dropoffQuality.fastModeSwitch) {
|
||||
getPosToRender(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ,
|
||||
requireCorrectDetailLevel);
|
||||
} else {
|
||||
getPosToRenderFlat(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, targetLevel, requireCorrectDetailLevel);
|
||||
getPosToRenderFlat(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, targetLevel, farModeSwitchLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,47 +303,40 @@ public class LodRegion {
|
||||
// equivalent to 2^(...)
|
||||
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
|
||||
|
||||
byte desiredLevel;
|
||||
int maxDistance;
|
||||
int minDistance;
|
||||
int childLevel;
|
||||
|
||||
// calculate the LevelPos that are in range
|
||||
maxDistance = LevelPosUtil.maxDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ);
|
||||
desiredLevel = DetailDistanceUtil.getLodDrawDetail(DetailDistanceUtil.getDrawDetailFromDistance(maxDistance));
|
||||
minDistance = LevelPosUtil.minDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ);
|
||||
childLevel = DetailDistanceUtil.getLodDrawDetail(DetailDistanceUtil.getDrawDetailFromDistance(minDistance));
|
||||
|
||||
if (detailLevel == childLevel - 1) {
|
||||
posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size);
|
||||
} else
|
||||
// if (desiredLevel > detailLevel)
|
||||
// {
|
||||
// we have gone beyond the target Detail level
|
||||
// we can stop generating
|
||||
// } else
|
||||
if (desiredLevel == detailLevel) {
|
||||
int minDistance = LevelPosUtil.minDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ);
|
||||
byte minLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
|
||||
// FarModeSwitchLevel or above is the level where a giant block of lod is not acceptable even if not all child data exist.
|
||||
byte farModeSwitchLevel = requireCorrectDetailLevel ? 0 : calculateFarModeSwitch(minLevel);
|
||||
|
||||
if (detailLevel == minLevel) {
|
||||
posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size);
|
||||
} else // case where (detailLevel > desiredLevel)
|
||||
{
|
||||
int childPosX = (offsetPosX + regionPosX*size) * 2;
|
||||
int childPosZ = (offsetPosZ + regionPosZ*size) * 2;
|
||||
byte childDetailLevel = (byte) (detailLevel - 1);
|
||||
int childrenCount = 0;
|
||||
|
||||
for (int x = 0; x <= 1; x++) {
|
||||
for (int z = 0; z <= 1; z++) {
|
||||
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
|
||||
if (!requireCorrectDetailLevel)
|
||||
childrenCount++;
|
||||
else
|
||||
|
||||
if (detailLevel > farModeSwitchLevel) {
|
||||
// Giant block is not acceptable. So leave empty void if data doesn't exist.
|
||||
for (int x = 0; x <= 1; x++) {
|
||||
for (int z = 0; z <= 1; z++) {
|
||||
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
|
||||
getPosToRender(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, playerPosX,
|
||||
playerPosZ, requireCorrectDetailLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Giant block is acceptable. So use this level lod if not all child data exist.
|
||||
int childrenCount = 0;
|
||||
for (int x = 0; x <= 1; x++) {
|
||||
for (int z = 0; z <= 1; z++) {
|
||||
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
|
||||
childrenCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!requireCorrectDetailLevel) {
|
||||
// If all the four children exist go deeper
|
||||
if (childrenCount == 4) {
|
||||
for (int x = 0; x <= 1; x++)
|
||||
@@ -348,36 +354,42 @@ public class LodRegion {
|
||||
* This method will fill the posToRender array with all levelPos that are
|
||||
* render-able. But the entire region try use the same detail level.
|
||||
*/
|
||||
private void getPosToRenderFlat(PosToRenderContainer posToRender, byte detailLevel, int offsetPosX, int offsetPosZ, byte targetLevel, boolean requireCorrectDetailLevel) {
|
||||
private void getPosToRenderFlat(PosToRenderContainer posToRender, byte detailLevel, int offsetPosX, int offsetPosZ,
|
||||
byte targetLevel, byte farModeSwitchLevel) {
|
||||
// equivalent to 2^(...)
|
||||
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
|
||||
|
||||
if (detailLevel == targetLevel) {
|
||||
posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size);
|
||||
} else // case where (detailLevel > desiredLevel)
|
||||
{
|
||||
int childPosX = (offsetPosX + regionPosX*size) * 2;
|
||||
int childPosZ = (offsetPosZ + regionPosX*size) * 2;
|
||||
int childPosZ = (offsetPosZ + regionPosZ*size) * 2;
|
||||
byte childDetailLevel = (byte) (detailLevel - 1);
|
||||
int childrenCount = 0;
|
||||
|
||||
for (int x = 0; x <= 1; x++) {
|
||||
for (int z = 0; z <= 1; z++) {
|
||||
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
|
||||
if (!requireCorrectDetailLevel)
|
||||
childrenCount++;
|
||||
else
|
||||
getPosToRenderFlat(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, targetLevel, requireCorrectDetailLevel);
|
||||
|
||||
if (detailLevel > farModeSwitchLevel) {
|
||||
// Giant block is not acceptable. So leave empty void if data doesn't exist.
|
||||
for (int x = 0; x <= 1; x++) {
|
||||
for (int z = 0; z <= 1; z++) {
|
||||
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
|
||||
getPosToRenderFlat(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, targetLevel, farModeSwitchLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Giant block is acceptable. So use this level lod if not all child data exist.
|
||||
int childrenCount = 0;
|
||||
for (int x = 0; x <= 1; x++) {
|
||||
for (int z = 0; z <= 1; z++) {
|
||||
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
|
||||
childrenCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!requireCorrectDetailLevel) {
|
||||
// If all the four children exist go deeper
|
||||
if (childrenCount == 4) {
|
||||
for (int x = 0; x <= 1; x++)
|
||||
for (int z = 0; z <= 1; z++)
|
||||
getPosToRenderFlat(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, targetLevel, requireCorrectDetailLevel);
|
||||
getPosToRenderFlat(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, targetLevel, farModeSwitchLevel);
|
||||
} else {
|
||||
posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size);
|
||||
}
|
||||
|
||||
@@ -1177,13 +1177,13 @@ public class VerticalLevelContainer implements LevelContainer
|
||||
}
|
||||
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getVerticalSize());
|
||||
if (!anyDataExist)
|
||||
throw new RuntimeException();
|
||||
throw new RuntimeException("Update data called but no child datapoint exist!");
|
||||
|
||||
if ((!DataPointUtil.doesItExist(data[0])) && anyDataExist)
|
||||
throw new RuntimeException();
|
||||
throw new RuntimeException("Update data called but higher level datapoint doesn't exist even though child data does exist!");
|
||||
|
||||
if (DataPointUtil.getGenerationMode(data[0]) != DataPointUtil.getGenerationMode(lowerLevelContainer.getSingleData(posX*2, posZ*2)))
|
||||
throw new RuntimeException();
|
||||
throw new RuntimeException("Update data called but higher level datapoint does not have the same GenerationMode as the top left corner child datapoint!");
|
||||
|
||||
|
||||
forceWriteVerticalData(data, posX, posZ);
|
||||
|
||||
@@ -34,8 +34,11 @@ public class DetailDistanceUtil
|
||||
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonHandler.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
@Deprecated
|
||||
private static final double genMultiplier = 1.0;
|
||||
@Deprecated
|
||||
private static final double treeGenMultiplier = 1.0;
|
||||
@Deprecated
|
||||
private static final double treeCutMultiplier = 1.0;
|
||||
private static byte minGenDetail = CONFIG.client().graphics().quality().getDrawResolution().detailLevel;
|
||||
private static byte minDrawDetail = CONFIG.client().graphics().quality().getDrawResolution().detailLevel;
|
||||
@@ -44,21 +47,6 @@ public class DetailDistanceUtil
|
||||
private static int minDetailDistance = (int) (MC_RENDER.getRenderDistance()*16 * 1.42f);
|
||||
private static int maxDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * 16 * 2;
|
||||
|
||||
@Deprecated
|
||||
private static final HorizontalResolution[] lodGenDetails = {
|
||||
HorizontalResolution.BLOCK,
|
||||
HorizontalResolution.TWO_BLOCKS,
|
||||
HorizontalResolution.FOUR_BLOCKS,
|
||||
HorizontalResolution.HALF_CHUNK,
|
||||
HorizontalResolution.CHUNK,
|
||||
HorizontalResolution.CHUNK,
|
||||
HorizontalResolution.CHUNK,
|
||||
HorizontalResolution.CHUNK,
|
||||
HorizontalResolution.CHUNK,
|
||||
HorizontalResolution.CHUNK,
|
||||
HorizontalResolution.CHUNK };
|
||||
|
||||
|
||||
|
||||
public static void updateSettings()
|
||||
{
|
||||
@@ -93,44 +81,54 @@ public class DetailDistanceUtil
|
||||
return baseDistanceFunction(detail);
|
||||
}
|
||||
|
||||
public static byte baseInverseFunction(int distance, byte minDetail, boolean useRenderMinDistance)
|
||||
public static byte baseInverseFunction(int distance, byte minDetail)
|
||||
{
|
||||
byte detail;
|
||||
if (distance == 0
|
||||
|| (distance < minDetailDistance && useRenderMinDistance)
|
||||
|| CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality())
|
||||
return minDetail;
|
||||
distance -= minDetailDistance;
|
||||
|
||||
if (distance < 0 || CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality())
|
||||
distance = 0;
|
||||
int distanceUnit = CONFIG.client().graphics().quality().getHorizontalScale() * 16;
|
||||
double scaledDistance = distance;
|
||||
scaledDistance /= distanceUnit;
|
||||
if (CONFIG.client().graphics().quality().getHorizontalQuality() == HorizontalQuality.LOWEST)
|
||||
detail = (byte) (distance / distanceUnit);
|
||||
detail = (byte) (scaledDistance);
|
||||
else
|
||||
{
|
||||
double base = CONFIG.client().graphics().quality().getHorizontalQuality().quadraticBase;
|
||||
double logBase = Math.log(base);
|
||||
//noinspection IntegerDivisionInFloatingPointContext
|
||||
detail = (byte) (Math.log(distance / distanceUnit) / logBase);
|
||||
detail = (byte) (Math.log(scaledDistance) / logBase);
|
||||
}
|
||||
return (byte) LodUtil.clamp(minDetail, detail, maxDetail - 1);
|
||||
return (byte) LodUtil.clamp(minDetail, detail+minDetail, maxDetail - 1);
|
||||
}
|
||||
|
||||
|
||||
public static byte getDetailLevelFromDistance(int distance)
|
||||
{
|
||||
return baseInverseFunction(distance, minDrawDetail);
|
||||
}
|
||||
|
||||
@Deprecated //Reason: All merged into `getDetailLevelFromDistance`
|
||||
public static byte getDrawDetailFromDistance(int distance)
|
||||
{
|
||||
return baseInverseFunction(distance, minDrawDetail, false);
|
||||
return baseInverseFunction(distance, minDrawDetail);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated //Reason: Same as 'getDrawDetailFromDistance'
|
||||
public static byte getGenerationDetailFromDistance(int distance)
|
||||
{
|
||||
return baseInverseFunction((int) (distance * genMultiplier), minGenDetail, true);
|
||||
return baseInverseFunction((int) (distance * genMultiplier), minGenDetail);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated //Reason: Same as 'getDrawDetailFromDistance'
|
||||
public static byte getTreeCutDetailFromDistance(int distance)
|
||||
{
|
||||
return baseInverseFunction((int) (distance * treeCutMultiplier), minGenDetail, true);
|
||||
return baseInverseFunction((int) (distance * treeCutMultiplier), minGenDetail);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated //Reason: Same as 'getDrawDetailFromDistance'
|
||||
public static byte getTreeGenDetailFromDistance(int distance)
|
||||
{
|
||||
return baseInverseFunction((int) (distance * treeGenMultiplier), minGenDetail, true);
|
||||
return baseInverseFunction((int) (distance * treeGenMultiplier), minGenDetail);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +140,7 @@ public class DetailDistanceUtil
|
||||
return CONFIG.client().worldGenerator().getDistanceGenerationMode();
|
||||
}*/
|
||||
|
||||
@Deprecated
|
||||
public static byte getLodDrawDetail(byte detail)
|
||||
{
|
||||
detail += minDrawDetail;
|
||||
@@ -150,27 +149,6 @@ public class DetailDistanceUtil
|
||||
return detail;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static HorizontalResolution getLodGenDetail(int detail)
|
||||
{
|
||||
if (detail < minGenDetail)
|
||||
return lodGenDetails[minGenDetail];
|
||||
else
|
||||
return lodGenDetails[detail];
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public static byte getCutLodDetail(int detail)
|
||||
{
|
||||
if (detail < minGenDetail)
|
||||
return lodGenDetails[minGenDetail].detailLevel;
|
||||
else if (detail == maxDetail)
|
||||
return LodUtil.REGION_DETAIL_LEVEL;
|
||||
else
|
||||
return lodGenDetails[detail].detailLevel;
|
||||
}
|
||||
|
||||
public static int getMaxVerticalData(int detail)
|
||||
{
|
||||
return CONFIG.client().graphics().quality().getVerticalQuality().maxVerticalData[LodUtil.clamp(minGenDetail, detail, LodUtil.REGION_DETAIL_LEVEL)];
|
||||
|
||||
@@ -62,4 +62,10 @@ public interface IChunkWrapper
|
||||
default int getBlockLight(int x, int y, int z) {return -1;}
|
||||
|
||||
default int getSkyLight(int x, int y, int z) {return -1;}
|
||||
|
||||
default boolean blockPosInsideChunk(int x, int y, int z) {
|
||||
return (x>=getMinX() && x<=getMaxX()
|
||||
&& y>=getMinBuildHeight() && y<getMaxBuildHeight()
|
||||
&& z>=getMinZ() && z<=getMaxZ());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user