Fixed detail level stuck at 0 in far pos caused by overflow issues

This commit is contained in:
tom lee
2022-02-07 14:00:10 +08:00
parent 1e08fc51ec
commit b51cb7ca51
5 changed files with 75 additions and 90 deletions
@@ -53,21 +53,22 @@ public class PosToGenerateContainer
// TODO what is going on in this method?
public void addNearPosToGenerate(byte detailLevel, int posX, int posZ, boolean sort)
{
int distance = LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ);
// FIXME: This is a cast from double to int!!! OVERFLOW MAY HAPPEN!
int distance = (int)LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ);
int index;
//We are introducing a position in the near array
index = nearSize;
if (index == nearPosToGenerate.length) {
if (LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) > 0) {
if (Integer.compare(distance, nearPosToGenerate[index - 1][3]) > 0) {
return;
}
index--;
} else nearSize++;
if (sort) {
while (index > 0 && LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) <= 0)
while (index > 0 && Integer.compare(distance, nearPosToGenerate[index - 1][3]) <= 0)
{
nearPosToGenerate[index][0] = nearPosToGenerate[index - 1][0];
nearPosToGenerate[index][1] = nearPosToGenerate[index - 1][1];
@@ -85,21 +86,22 @@ public class PosToGenerateContainer
// 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);
// FIXME: This is a cast from double to int!!! OVERFLOW MAY HAPPEN!
int distance = (int)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) {
if (Integer.compare(distance, farPosToGenerate[index - 1][3]) > 0) {
return;
}
index--;
} else farSize++;
if (sort) {
while (index > 0 && LevelPosUtil.compareDistance(distance, farPosToGenerate[index - 1][3]) <= 0)
while (index > 0 && Integer.compare(distance, farPosToGenerate[index - 1][3]) <= 0)
{
farPosToGenerate[index][0] = farPosToGenerate[index - 1][0];
farPosToGenerate[index][1] = farPosToGenerate[index - 1][1];
@@ -290,7 +290,7 @@ public class LodDimension
Pos minPos = regions.getMinInRange();
// go over every region in the dimension
iterateWithSpiral((int x, int z) -> {
int minDistance;
double minDistance;
byte detail;
LodRegion region = regions.get(x+minPos.x, z+minPos.y);
@@ -358,8 +358,8 @@ public class LodDimension
int regionX;
int regionZ;
LodRegion region;
int minDistance;
int maxDistance;
double minDistance;
double maxDistance;
byte minDetail;
byte maxDetail;
regionX = x + minPos.x;
@@ -372,6 +372,19 @@ public class LodDimension
playerPosZ);
maxDistance = LevelPosUtil.maxDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX,
playerPosZ);
{
double debugRPosX = LevelPosUtil.convert(LodUtil.REGION_DETAIL_LEVEL, regionX, (byte) 0) + LodUtil.REGION_WIDTH/2;
double debugRPosZ = LevelPosUtil.convert(LodUtil.REGION_DETAIL_LEVEL, regionZ, (byte) 0) + LodUtil.REGION_WIDTH/2;
double deltaRPosX = debugRPosX - playerPosX;
double deltaRPosZ = debugRPosZ - playerPosZ;
double debugDistance = Math.sqrt(deltaRPosX*deltaRPosX + deltaRPosZ*deltaRPosZ);
if (minDistance > debugDistance || maxDistance < debugDistance || minDistance > maxDistance) {
ClientApi.LOGGER.error("MinDistance/MaxDistance is WRONG!!! minDist: [{}], maxDist: [{}], centerDist: [{}]\n"
+ "At center block pos: {} {}, region pos: {}",
minDistance, maxDistance, debugDistance, debugRPosX, debugRPosZ, regionPos);
return;
}
}
minDetail = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
maxDetail = DetailDistanceUtil.getDetailLevelFromDistance(maxDistance);
boolean updated = false;
@@ -695,6 +708,7 @@ public class LodDimension
ramLogger.info("Dumping Ram Usage for LodDim in {} with {} regions...", dimension.getDimensionName(), regionCount);
int nonNullRegionCount = 0;
int dirtiedRegionCount = 0;
int writingRegionCount = 0;
long totalUsage = 0;
int[] detailCount = new int[LodUtil.DETAIL_OPTIONS];
long[] detailUsage = new long[LodUtil.DETAIL_OPTIONS];
@@ -702,11 +716,15 @@ public class LodDimension
if (r==null) continue;
nonNullRegionCount++;
if (r.needSaving) dirtiedRegionCount++;
if (r.isWriting != 0) writingRegionCount++;
LevelContainer[] container = r.debugGetDataContainers().clone();
if (container == null || container.length != LodUtil.DETAIL_OPTIONS) {
ClientApi.LOGGER.warn("DumpRamUsage encountered an invalid region!");
continue;
}
for (int i = 0; i < LodUtil.DETAIL_OPTIONS; i++) {
if (container[i] == null) continue;
detailCount[i]++;
@@ -716,8 +734,8 @@ public class LodDimension
}
}
ramLogger.info("================================================");
ramLogger.info("Non Null Regions: [{}], Dirtied Regions: [{}], Bytes: [{}]",
nonNullRegionCount, dirtiedRegionCount, new UnitBytes(totalUsage));
ramLogger.info("Non Null Regions: [{}], Dirtied Regions: [{}], Writing Regions: [{}], Bytes: [{}]",
nonNullRegionCount, dirtiedRegionCount, writingRegionCount, new UnitBytes(totalUsage));
ramLogger.info("------------------------------------------------");
for (int i = 0; i < LodUtil.DETAIL_OPTIONS; i++) {
ramLogger.info("DETAIL {}: Containers: [{}], Bytes: [{}]", i, detailCount[i], new UnitBytes(detailUsage[i]));
@@ -228,7 +228,7 @@ public class LodRegion {
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
// calculate what LevelPos are in range to generate
int minDistance = LevelPosUtil.minDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ);
double minDistance = LevelPosUtil.minDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ);
// determine this child's levelPos
byte childDetailLevel = (byte) (detailLevel - 1);
@@ -276,14 +276,14 @@ public class LodRegion {
*/
public void getPosToRender(PosToRenderContainer posToRender, int playerPosX, int playerPosZ,
GenerationPriority priority, DropoffQuality dropoffQuality) {
int minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ);
double minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ);
byte targetLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
if (targetLevel <= dropoffQuality.fastModeSwitch) {
getPosToRender(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ,
priority);
} else {
// FarModeSwitchLevel or above is the level where a giant block of lod is not acceptable even if not all child data exist.
int maxDistance = LevelPosUtil.maxDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ);
double maxDistance = LevelPosUtil.maxDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ);
byte farModeSwitchLevel = (priority == GenerationPriority.NEAR_FIRST) ? 0 :
calculateFarModeSwitch(DetailDistanceUtil.getDetailLevelFromDistance(maxDistance));
if (priority == GenerationPriority.FAR_FIRST) farModeSwitchLevel = 8;
@@ -305,7 +305,7 @@ public class LodRegion {
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
// calculate the LevelPos that are in range
int minDistance = LevelPosUtil.minDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ);
double 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 = (priority == GenerationPriority.NEAR_FIRST) ? 0 : calculateFarModeSwitch(minLevel);
@@ -19,6 +19,7 @@
package com.seibel.lod.core.util;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.HorizontalQuality;
import com.seibel.lod.core.enums.config.HorizontalResolution;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
@@ -42,10 +43,10 @@ public class DetailDistanceUtil
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;
private static final int maxDetail = LodUtil.REGION_DETAIL_LEVEL + 1;
private static final int minDistance = 0;
private static int minDetailDistance = (int) (MC_RENDER.getRenderDistance()*16 * 1.42f);
private static int maxDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * 16 * 2;
private static final byte maxDetail = LodUtil.DETAIL_OPTIONS;
private static final double minDistance = 0;
private static double minDetailDistance = (int) (MC_RENDER.getRenderDistance()*16 * 1.42f);
private static double maxDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * 16 * 2;
public static void updateSettings()
@@ -56,8 +57,7 @@ public class DetailDistanceUtil
maxDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * 16 * 8;
}
/*// Need UPDATE and BUG FIX
public static int baseDistanceFunction(int detail)
public static double baseDistanceFunction(int detail)
{
if (detail <= minGenDetail)
return minDistance;
@@ -69,21 +69,27 @@ public class DetailDistanceUtil
int distanceUnit = CONFIG.client().graphics().quality().getHorizontalScale() * 16;
if (CONFIG.client().graphics().quality().getHorizontalQuality() == HorizontalQuality.LOWEST)
return (detail * distanceUnit);
return ((double)detail * distanceUnit);
else
{
double base = CONFIG.client().graphics().quality().getHorizontalQuality().quadraticBase;
return (int) (Math.pow(base, detail) * distanceUnit);
return Math.pow(base, detail) * distanceUnit;
}
}
public static int getDrawDistanceFromDetail(int detail)
public static double getDrawDistanceFromDetail(int detail)
{
return baseDistanceFunction(detail);
}*/
}
public static byte baseInverseFunction(int distance, byte minDetail)
public static byte baseInverseFunction(double distance, byte minDetail)
{
double maxDetailDistance = getDrawDistanceFromDetail(maxDetail-1);
if (distance > maxDetailDistance) {
//ClientApi.LOGGER.info("DEBUG: Scale as max: {}", distance);
return maxDetail-1;
}
int detail;
distance -= minDetailDistance;
@@ -103,34 +109,10 @@ public class DetailDistanceUtil
return (byte) LodUtil.clamp(minDetail, detail+minDetail, maxDetail - 1);
}
public static byte getDetailLevelFromDistance(int distance)
public static byte getDetailLevelFromDistance(double distance)
{
return baseInverseFunction(distance, minDrawDetail);
}
@Deprecated //Reason: All merged into `getDetailLevelFromDistance`
public static byte getDrawDetailFromDistance(int distance)
{
return baseInverseFunction(distance, minDrawDetail);
}
@Deprecated //Reason: Same as 'getDrawDetailFromDistance'
public static byte getGenerationDetailFromDistance(int distance)
{
return baseInverseFunction((int) (distance * genMultiplier), minGenDetail);
}
@Deprecated //Reason: Same as 'getDrawDetailFromDistance'
public static byte getTreeCutDetailFromDistance(int distance)
{
return baseInverseFunction((int) (distance * treeCutMultiplier), minGenDetail);
}
@Deprecated //Reason: Same as 'getDrawDetailFromDistance'
public static byte getTreeGenDetailFromDistance(int distance)
{
return baseInverseFunction((int) (distance * treeGenMultiplier), minGenDetail);
}
// NOTE: The recent LodWorldGenerator changes assumes that this value doesn't change with 'detail'.
@@ -141,15 +123,6 @@ public class DetailDistanceUtil
return CONFIG.client().worldGenerator().getDistanceGenerationMode();
}*/
@Deprecated
public static byte getLodDrawDetail(byte detail)
{
detail += minDrawDetail;
if (detail > 10)
detail = 10;
return detail;
}
public static int getMaxVerticalData(int detail)
{
return CONFIG.client().graphics().quality().getVerticalQuality().maxVerticalData[LodUtil.clamp(minGenDetail, detail, LodUtil.REGION_DETAIL_LEVEL)];
@@ -149,32 +149,32 @@ public class LevelPosUtil
return convert(detailLevel, pos, LodUtil.CHUNK_DETAIL_LEVEL);
}
public static int myPow2(int x)
public static double myPow2(double x)
{
return x*x;
}
public static int maxDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ)
public static double maxDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ)
{
int width = 1 << detailLevel;
int startPosX = posX * width;
int startPosZ = posZ * width;
int endPosX = myPow2(playerPosX - startPosX - width);
int endPosZ = myPow2(playerPosZ - startPosZ - width);
double startPosX = posX * width;
double startPosZ = posZ * width;
double endPosX = myPow2(playerPosX - startPosX - width);
double endPosZ = myPow2(playerPosZ - startPosZ - width);
startPosX = myPow2(playerPosX - startPosX);
startPosZ = myPow2(playerPosZ - startPosZ);
int maxDistance = (int) Math.sqrt(startPosX + startPosZ);
maxDistance = Math.max(maxDistance, (int) Math.sqrt(startPosX + endPosZ));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(endPosX + startPosZ));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(endPosX + endPosZ));
double maxDistance = Math.sqrt(startPosX + startPosZ);
maxDistance = Math.max(maxDistance, Math.sqrt(startPosX + endPosZ));
maxDistance = Math.max(maxDistance, Math.sqrt(endPosX + startPosZ));
maxDistance = Math.max(maxDistance, Math.sqrt(endPosX + endPosZ));
return maxDistance;
}
public static int minDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ)
public static double minDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ)
{
int width = 1 << detailLevel;
@@ -203,35 +203,27 @@ public class LevelPosUtil
}
else
{
startPosX = myPow2(playerPosX - startPosX);
startPosZ = myPow2(playerPosZ - startPosZ);
endPosX = myPow2(playerPosX - endPosX);
endPosZ = myPow2(playerPosZ - endPosZ);
double startPosX2 = myPow2(playerPosX - startPosX);
double startPosZ2 = myPow2(playerPosZ - startPosZ);
double endPosX2 = myPow2(playerPosX - endPosX);
double endPosZ2 = myPow2(playerPosZ - endPosZ);
int minDistance = (int) Math.sqrt(startPosX + startPosZ);
minDistance = Math.min(minDistance, (int) Math.sqrt(startPosX + endPosZ));
minDistance = Math.min(minDistance, (int) Math.sqrt(endPosX + startPosZ));
minDistance = Math.min(minDistance, (int) Math.sqrt(endPosX + endPosZ));
double minDistance = Math.sqrt(startPosX2 + startPosZ2);
minDistance = Math.min(minDistance, Math.sqrt(startPosX2 + endPosZ2));
minDistance = Math.min(minDistance, Math.sqrt(endPosX2 + startPosZ2));
minDistance = Math.min(minDistance, Math.sqrt(endPosX2 + endPosZ2));
return minDistance;
}
}
public static int compareDistance(int firstDistance, int secondDistance)
public static double compareLevelAndDistance(byte firstDetail, double firstDistance, byte secondDetail, double secondDistance)
{
return Integer.compare(
firstDistance,
secondDistance);
}
public static int compareLevelAndDistance(byte firstDetail, int firstDistance, byte secondDetail, int secondDistance)
{
int compareResult = Integer.compare(
int compareResult = Byte.compare(
secondDetail,
firstDetail);
if (compareResult == 0)
{
compareResult = Integer.compare(
compareResult = Double.compare(
firstDistance,
secondDistance);
}