diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index 7f301dc90..d39fc34f3 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -25,6 +25,7 @@ import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.enums.LodDetail; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.DataPoint; +import com.seibel.lod.objects.LevelPosUtil; import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.LodWorld; import com.seibel.lod.objects.LevelPos.LevelPos; @@ -163,7 +164,7 @@ public class LodBuilder short[] color; short height; short depth; - LevelPos levelPos = new LevelPos((byte) 0, 0, 0); + int[] levelPos; short[] data; try { @@ -186,20 +187,23 @@ public class LodBuilder startZ, endX, endZ); depth = 0; } - levelPos.changeParameters((byte) 0, - chunk.getPos().x * 16 + startX, - chunk.getPos().z * 16 + startZ); - levelPos.convert(detail.detailLevel); + levelPos = LevelPosUtil.convert( + LevelPosUtil.createLevelPos((byte) 0, + chunk.getPos().x * 16 + startX, + chunk.getPos().z * 16 + startZ), + detail.detailLevel + ); boolean isServer = config.distanceGenerationMode == DistanceGenerationMode.SERVER; data = DataPoint.createDataPoint(height, depth, color[0], color[1], color[2]); - lodDim.addData(levelPos, + boolean added = lodDim.addData(levelPos, data, false, isServer); + System.out.println(added); } //levelPos.changeParameters(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z); - lodDim.updateData(new LevelPos(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z)); + lodDim.updateData(LevelPosUtil.createLevelPos(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z)); } catch (Exception e) { //e.printStackTrace(); @@ -432,12 +436,10 @@ public class LodBuilder Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z)); tmp = tmp.darker(); colorInt = LodUtil.colorToInt(tmp); - } - else if (blockState == Blocks.STONE.defaultBlockState()) + } else if (blockState == Blocks.STONE.defaultBlockState()) { colorInt = LodUtil.STONE_COLOR_INT; - } - else if (blockState == Blocks.MYCELIUM.defaultBlockState()) + } else if (blockState == Blocks.MYCELIUM.defaultBlockState()) { colorInt = LodUtil.MYCELIUM_COLOR_INT; } diff --git a/src/main/java/com/seibel/lod/objects/LevelPosUtil.java b/src/main/java/com/seibel/lod/objects/LevelPosUtil.java new file mode 100644 index 000000000..e3c0758d2 --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/LevelPosUtil.java @@ -0,0 +1,184 @@ +package com.seibel.lod.objects; + +import com.seibel.lod.objects.LevelPos.ImmutableLevelPos; +import com.seibel.lod.objects.LevelPos.MutableLevelPos; +import com.seibel.lod.util.LodUtil; +import net.minecraft.util.math.ChunkPos; + +import java.util.Comparator; + +public class LevelPosUtil +{ + public static int[] convert(int[] levelPos, byte newDetailLevel) + { + return convert(getDetailLevel(levelPos), getPosX(levelPos), getPosZ(levelPos), newDetailLevel); + } + + public static int[] convert(byte detailLevel, int posX, int posZ, byte newDetailLevel) + { + int width; + if (newDetailLevel >= detailLevel) + { + width = 1 << (newDetailLevel - detailLevel); + return createLevelPos( + newDetailLevel, + Math.floorDiv(posX, width), + Math.floorDiv(posZ, width)); + } else + { + width = 1 << (detailLevel - newDetailLevel); + return createLevelPos( + newDetailLevel, + posX * width, + posZ * width); + } + } + + public static int[] createLevelPos(byte detailLevel, int posX, int posZ) + { + return new int[]{detailLevel, posX, posZ}; + } + + public static byte getDetailLevel(int[] levelPos) + { + return (byte) levelPos[0]; + } + + public static int getPosX(int[] levelPos) + { + return levelPos[1]; + } + + public static int getPosZ(int[] levelPos) + { + return levelPos[2]; + } + + public static int[] getRegionModule(int[] levelPos) + { + return getRegionModule(getDetailLevel(levelPos), getPosX(levelPos), getPosZ(levelPos)); + } + + public static int[] getRegionModule(byte detailLevel, int posX, int posZ) + { + int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); + return createLevelPos( + detailLevel, + Math.floorMod(posX, width), + Math.floorMod(posZ, width)); + } + + public static int[] applyOffset(int[] levelPos, int xOffset, int zOffset) + { + return createLevelPos( + getDetailLevel(levelPos), + getPosX(levelPos) + xOffset, + getPosZ(levelPos) + zOffset); + } + + public static int[] applyLevelOffset(int[] levelPos, byte detailOffset, int xOffset, int zOffset) + { + return createLevelPos( + getDetailLevel(levelPos), + getPosX(levelPos) + xOffset * (1 << detailOffset), + getPosZ(levelPos) + zOffset * (1 << detailOffset)); + } + + public static int getRegionPosX(int[] levelPos) + { + int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - getDetailLevel(levelPos)); + return Math.floorDiv(getPosX(levelPos), width); + } + + public static int getRegionPosZ(int[] levelPos) + { + int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - getDetailLevel(levelPos)); + return Math.floorDiv(getPosZ(levelPos), width); + } + + public static ChunkPos getChunkPos(int[] levelPos) + { + levelPos = convert(levelPos, LodUtil.CHUNK_DETAIL_LEVEL); + return new ChunkPos( + getPosX(levelPos), + getPosZ(levelPos)); + } + + public static int maxDistance(int[] levelPos, int playerPosX, int playerPosZ) + { + int width = 1 << getDetailLevel(levelPos); + + int startPosX = getPosX(levelPos) * width; + int startPosZ = getPosX(levelPos) * width; + int endPosX = startPosX + width; + int endPosZ = startPosZ + width; + + int maxDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)); + maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2))); + maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2))); + maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2))); + + return maxDistance; + } + + + public static int minDistance(int[] levelPos, int playerPosX, int playerPosZ) + { + int width = 1 << getDetailLevel(levelPos); + + int startPosX = getPosX(levelPos) * width; + int startPosZ = getPosX(levelPos) * width; + int endPosX = startPosX + width; + int endPosZ = startPosZ + width; + + boolean inXArea = playerPosX >= startPosX && playerPosX <= endPosX; + boolean inZArea = playerPosZ >= startPosZ && playerPosZ <= endPosZ; + if (inXArea && inZArea) + { + return 0; + } else if (inXArea) + { + return Math.min( + Math.abs(playerPosZ - startPosZ), + Math.abs(playerPosZ - endPosZ) + ); + } else if (inZArea) + { + return Math.min( + Math.abs(playerPosX - startPosX), + Math.abs(playerPosX - endPosX) + ); + } else + { + int minDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)); + minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2))); + minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2))); + minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2))); + return minDistance; + } + } + + public static int compareDistance(int posX, int posZ, int[] first, int[] second) + { + return Integer.compare( + minDistance(first, posX, posZ), + minDistance(second, posX, posZ)); + } + + public static int compareLevelAndDistance(int posX, int posZ, int[] first, int[] second) + { + int compareResult = Integer.compare(getDetailLevel(second), getDetailLevel(first)); + if (compareResult == 0) + { + compareResult = Integer.compare( + minDistance(first, posX, posZ), + minDistance(second, posX, posZ)); + } + return compareResult; + } + + public static String toString(int[] levelPos) + { + return (getDetailLevel(levelPos) + " " + getPosX(levelPos) + " " + getPosZ(levelPos)); + } +} diff --git a/src/main/java/com/seibel/lod/objects/LodDimension.java b/src/main/java/com/seibel/lod/objects/LodDimension.java index bf00ec13c..bd75700be 100644 --- a/src/main/java/com/seibel/lod/objects/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodDimension.java @@ -23,6 +23,7 @@ import java.security.InvalidParameterException; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.logging.Level; import org.apache.commons.lang3.mutable.MutableBoolean; @@ -284,6 +285,27 @@ public class LodDimension return regions[xIndex][zIndex]; } + /** + * Gets the region at the given X and Z + *
+ * Returns null if the region doesn't exist + * or is outside the loaded area. + */ + public LodRegion getRegion(int[] levelPos) + { + + int xIndex = (LevelPosUtil.getRegionPosX(levelPos) - center.x) + halfWidth; + int zIndex = (LevelPosUtil.getRegionPosZ(levelPos) - center.z) + halfWidth; + + if (!regionIsInRange(LevelPosUtil.getRegionPosX(levelPos), LevelPosUtil.getRegionPosZ(levelPos))) + throw new ArrayIndexOutOfBoundsException("Region for level pos " + levelPos + " out of range"); + else if (regions[xIndex][zIndex] == null) + throw new InvalidParameterException("Region for level pos " + levelPos + " not currently initialized"); + else if (regions[xIndex][zIndex].getMinDetailLevel() > LevelPosUtil.getDetailLevel(levelPos)) + throw new InvalidParameterException("Region for level pos " + levelPos + " currently only reach level " + regions[xIndex][zIndex].getMinDetailLevel()); + return regions[xIndex][zIndex]; + } + /** * Gets the region at the given X and Z *
@@ -439,12 +461,13 @@ public class LodDimension * stored in the LOD. If an LOD already exists at the given * coordinates it will be overwritten. */ - public synchronized Boolean addData(LevelPos levelPos, short[] lodDataPoint, boolean dontSave, boolean serverQuality) + public synchronized Boolean addData(int[] levelPos, short[] lodDataPoint, boolean dontSave, boolean serverQuality) { // don't continue if the region can't be saved - RegionPos regionPos = levelPos.getRegionPos(); - if (!regionIsInRange(regionPos.x, regionPos.z)) + int xRegion = LevelPosUtil.getRegionPosX(levelPos); + int zRegion = LevelPosUtil.getRegionPosZ(levelPos); + if (!regionIsInRange(xRegion, zRegion)) { return false; } @@ -458,8 +481,8 @@ public class LodDimension try { // mark the region as dirty so it will be saved to disk - int xIndex = (regionPos.x - center.x) + halfWidth; - int zIndex = (regionPos.z - center.z) + halfWidth; + int xIndex = (xRegion - center.x) + halfWidth; + int zIndex = (zRegion - center.z) + halfWidth; isRegionDirty[xIndex][zIndex] = true; regen[xIndex][zIndex] = true; regenDimension = true; @@ -582,10 +605,10 @@ public class LodDimension * Returns null if the LodChunk doesn't exist or * is outside the loaded area. */ - public void updateData(LevelPos levelPos) + public void updateData(int[] levelPos) { - if (levelPos.detailLevel > LodUtil.REGION_DETAIL_LEVEL) - throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + levelPos.detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max."); + if (LevelPosUtil.getDetailLevel(levelPos) > LodUtil.REGION_DETAIL_LEVEL) + throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + LevelPosUtil.getDetailLevel(levelPos) + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max."); LodRegion region = getRegion(levelPos); @@ -611,7 +634,7 @@ public class LodDimension return false; } - return region.doesDataExist(levelPos.clone()); + return region.doesDataExist(LevelPosUtil.createLevelPos(levelPos.detailLevel,levelPos.posX,levelPos.posZ)); } catch (Exception e) { return false; diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index ffba56c32..10354ac3c 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -77,7 +77,6 @@ public class LodRegion implements Serializable dataExistence[lod] = new boolean[size][size]; } int width; - LevelPos levelPos = new LevelPos(); for (byte tempLod = (byte) (minDetailLevel + 1); tempLod <= LodUtil.REGION_DETAIL_LEVEL; tempLod++) { width = 1 << (LodUtil.REGION_DETAIL_LEVEL - tempLod); @@ -85,8 +84,7 @@ public class LodRegion implements Serializable { for (int z = 0; z < width; z++) { - levelPos.changeParameters(tempLod, x, z); - update(levelPos); + update(LevelPosUtil.createLevelPos(tempLod, x, z)); } } } @@ -127,22 +125,25 @@ public class LodRegion implements Serializable * @param dataPoint * @return */ - public boolean addData(LevelPos levelPos, short[] dataPoint, boolean serverQuality) + public boolean addData(int[] levelPos, short[] dataPoint, boolean serverQuality) { - levelPos.performRegionModule(); + levelPos = LevelPosUtil.getRegionModule(levelPos); + byte detailLevel = LevelPosUtil.getDetailLevel(levelPos); + int posX = LevelPosUtil.getPosX(levelPos); + int posZ = LevelPosUtil.getPosZ(levelPos); if (!doesDataExist(levelPos) || serverQuality) { //update the number of node present - if (this.dataExistence[levelPos.detailLevel][levelPos.posX][levelPos.posZ]) numberOfPoints++; + if (this.dataExistence[detailLevel][posX][posZ]) numberOfPoints++; //add the node data - this.height[levelPos.detailLevel][levelPos.posX][levelPos.posZ] = DataPoint.getHeight(dataPoint); - this.depth[levelPos.detailLevel][levelPos.posX][levelPos.posZ] = DataPoint.getDepth(dataPoint); - this.colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][0] = (byte) (DataPoint.getRed(dataPoint) - 128); - this.colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][1] = (byte) (DataPoint.getGreen(dataPoint) - 128); - this.colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][2] = (byte) (DataPoint.getBlue(dataPoint) - 128); - this.dataExistence[levelPos.detailLevel][levelPos.posX][levelPos.posZ] = true; + this.height[detailLevel][posX][posZ] = DataPoint.getHeight(dataPoint); + this.depth[detailLevel][posX][posZ] = DataPoint.getDepth(dataPoint); + this.colors[detailLevel][posX][posZ][0] = (byte) (DataPoint.getRed(dataPoint) - 128); + this.colors[detailLevel][posX][posZ][1] = (byte) (DataPoint.getGreen(dataPoint) - 128); + this.colors[detailLevel][posX][posZ][2] = (byte) (DataPoint.getBlue(dataPoint) - 128); + this.dataExistence[detailLevel][posX][posZ] = true; return true; } else { @@ -203,7 +204,7 @@ public class LodRegion implements Serializable return; } else if (DetailDistanceUtil.getDistanceGenerationInverse(minDistance) == detailLevel) { - if (!doesDataExist(levelPos)) + if (!doesDataExist(LevelPosUtil.createLevelPos(levelPos.detailLevel, levelPos.posX, levelPos.posZ))) { levelPos.changeParameters(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size); if (dataToGenerate.containsKey(levelPos)) @@ -227,7 +228,7 @@ public class LodRegion implements Serializable { levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x, childPosZ + z); - if (!doesDataExist(levelPos)) + if (!doesDataExist(LevelPosUtil.createLevelPos(levelPos.detailLevel, levelPos.posX, levelPos.posZ))) { num++; levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x + regionPosX * childSize, childPosZ + z + regionPosZ * childSize); @@ -261,7 +262,7 @@ public class LodRegion implements Serializable { levelPos.changeParameters(detailLevel, posX, posZ); levelPos.convert(childDetailLevel); - if (!doesDataExist(levelPos)) + if (!doesDataExist(LevelPosUtil.createLevelPos(levelPos.detailLevel, levelPos.posX, levelPos.posZ))) { levelPos.changeParameters(levelPos.detailLevel, levelPos.posX + regionPosX * childSize, levelPos.posZ + regionPosZ * childSize); if (dataToGenerate.containsKey(levelPos)) @@ -335,7 +336,7 @@ public class LodRegion implements Serializable for (int z = 0; z <= 1; z++) { levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x, childPosZ + z); - if (doesDataExist(levelPos)) childrenCount++; + if (doesDataExist(LevelPosUtil.createLevelPos(levelPos.detailLevel, levelPos.posX, levelPos.posZ))) childrenCount++; } } @@ -371,43 +372,36 @@ public class LodRegion implements Serializable /** * @param levelPos */ - public void updateArea(LevelPos levelPos) + public void updateArea(int[] levelPos) { int width; - int startX; - int startZ; - byte detailLevel = levelPos.detailLevel; - int posX = levelPos.posX; - int posZ = levelPos.posZ; + levelPos = LevelPosUtil.getRegionModule(levelPos); + int detailLevel = LevelPosUtil.getDetailLevel(levelPos); + int[] bottomLevelPos; for (byte bottom = (byte) (minDetailLevel + 1); bottom <= detailLevel; bottom++) { - levelPos.convert(bottom); - startX = levelPos.posX; - startZ = levelPos.posZ; + bottomLevelPos = LevelPosUtil.convert(levelPos, bottom); width = 1 << (detailLevel - bottom); for (int x = 0; x < width; x++) { for (int z = 0; z < width; z++) { - levelPos.changeParameters(bottom, startX + x, startZ + z); - update(levelPos); + update(LevelPosUtil.applyOffset(bottomLevelPos, x, z)); } } - levelPos.changeParameters(detailLevel, posX, posZ); } - for (byte tempLod = (byte) (detailLevel + 1); tempLod <= LodUtil.REGION_DETAIL_LEVEL; tempLod++) + for (byte up = (byte) (detailLevel + 1); up <= LodUtil.REGION_DETAIL_LEVEL; up++) { - levelPos.convert(tempLod); - update(levelPos); + update(LevelPosUtil.convert(levelPos, up)); } } /** * @param levelPos */ - private void update(LevelPos levelPos) + private void update(int[] levelPos) { - levelPos.performRegionModule(); + levelPos = LevelPosUtil.getRegionModule(levelPos); int numberOfChildren = 0; int numberOfVoidChildren = 0; @@ -419,9 +413,9 @@ public class LodRegion implements Serializable int newPosX; int newPosZ; byte newDetailLevel; - int detailLevel = levelPos.detailLevel; - int posX = levelPos.posX; - int posZ = levelPos.posZ; + int detailLevel = LevelPosUtil.getDetailLevel(levelPos); + int posX = LevelPosUtil.getPosX(levelPos); + int posZ = LevelPosUtil.getPosZ(levelPos); for (int x = 0; x <= 1; x++) { for (int z = 0; z <= 1; z++) @@ -429,7 +423,7 @@ public class LodRegion implements Serializable newPosX = 2 * posX + x; newPosZ = 2 * posZ + z; newDetailLevel = (byte) (detailLevel - 1); - levelPos.changeParameters(newDetailLevel, newPosX, newPosZ); + levelPos = LevelPosUtil.createLevelPos(newDetailLevel, newPosX, newPosZ); if (doesDataExist(levelPos)) { if (height[newDetailLevel][newPosX][newPosZ] != LodBuilder.DEFAULT_HEIGHT @@ -477,12 +471,12 @@ public class LodRegion implements Serializable * @param levelPos * @return */ - public boolean doesDataExist(LevelPos levelPos) + public boolean doesDataExist(int[] levelPos) { try { - levelPos = levelPos.getRegionModuleLevelPos(); - return dataExistence[levelPos.detailLevel][levelPos.posX][levelPos.posZ]; + levelPos = LevelPosUtil.getRegionModule(levelPos); + return dataExistence[LevelPosUtil.getDetailLevel(levelPos)][LevelPosUtil.getPosX(levelPos)][LevelPosUtil.getPosZ(levelPos)]; } catch (NullPointerException e) { return false; diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer.java index 4753b0f93..0054b9baf 100644 --- a/src/main/java/com/seibel/lod/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodRenderer.java @@ -773,7 +773,7 @@ public class LodRenderer //=============// // full regens // //=============// - + // check if the view distance changed if (ClientProxy.previousLodRenderDistance != LodConfig.CLIENT.lodChunkRenderDistance.get() || mc.options.renderDistance != prevRenderDistance @@ -787,13 +787,7 @@ public class LodRenderer //vanillaRenderedChunks.stream().filter(pos -> ((Math.abs(pos.x - player.xChunk) > mc.options.renderDistance) || (Math.abs(pos.z - player.zChunk) > mc.options.renderDistance))); vanillaRenderedChunks.clear(); } - - // did the user change the debug setting? - if (LodConfig.CLIENT.debugMode.get() != previousDebugMode) - { - previousDebugMode = LodConfig.CLIENT.debugMode.get(); - fullRegen = true; - } + long newTime = System.currentTimeMillis(); @@ -868,6 +862,14 @@ public class LodRenderer { vanillaRenderedChunks.clear(); } + + + // did the user change the debug setting? + if (LodConfig.CLIENT.debugMode.get() != previousDebugMode) + { + previousDebugMode = LodConfig.CLIENT.debugMode.get(); + fullRegen = true; + } } } \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/render/RenderUtil.java b/src/main/java/com/seibel/lod/render/RenderUtil.java index 3b33623cf..930ffd383 100644 --- a/src/main/java/com/seibel/lod/render/RenderUtil.java +++ b/src/main/java/com/seibel/lod/render/RenderUtil.java @@ -121,7 +121,7 @@ public class RenderUtil { // convert the vbo position into a direction vector // starting from the player's position - Vector3d vboVec = new Vector3d(vboCenterPos.getX(), 0, vboCenterPos.getZ()); + Vector3d vboVec = new Vector3d(vboCenterPos.getX(), 64, vboCenterPos.getZ()); Vector3d playerVec = new Vector3d(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ()); Vector3d vboCenterVec = vboVec.subtract(playerVec);