diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java
index e090e1fb8..4faf71b36 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java
@@ -59,9 +59,19 @@ public final class BufferQuad
public boolean hasError = false;
+ // Pre-computed sort keys to avoid recomputing on every comparison
+ // Slight increase in memory for reduction in cpu usage
+ public final long sortKeyEastWest;
+ public final long sortKeyNorthSouth;
- BufferQuad(
+
+ //=============//
+ // constructor //
+ //=============//
+ //region
+
+ public BufferQuad(
short x, short y, short z, short widthEastWest, short widthNorthSouthOrHeight,
int color, byte irisBlockMaterialId, byte skylight, byte blockLight,
EDhDirection direction)
@@ -85,64 +95,46 @@ public final class BufferQuad
this.skyLight = skylight;
this.blockLight = blockLight;
this.direction = direction;
+ this.sortKeyEastWest = computeSortKey(direction, true);
+ this.sortKeyNorthSouth = computeSortKey(direction, false);
}
-
-
-
- /** a rough but fast calculation */
- double calculateDistance(double relativeX, double relativeY, double relativeZ)
+ private long computeSortKey(EDhDirection dir, boolean eastWest)
{
- return Math.pow(relativeX - this.x, 2) + Math.pow(relativeY - this.y, 2) + Math.pow(relativeZ - this.z, 2);
+ if (eastWest)
+ {
+ switch (dir.axis)
+ {
+ case X: return (long) x << 48 | (long) y << 32 | (long) z << 16;
+ case Y: return (long) y << 48 | (long) z << 32 | (long) x << 16;
+ case Z: return (long) z << 48 | (long) y << 32 | (long) x << 16;
+ default: throw new IllegalArgumentException("Invalid Axis enum: [" + dir.axis + "].");
+ }
+ }
+ else
+ {
+ switch (dir.axis)
+ {
+ case X: return (long) x << 48 | (long) z << 32 | (long) y << 16;
+ case Y: return (long) y << 48 | (long) x << 32 | (long) z << 16;
+ case Z: return (long) z << 48 | (long) x << 32 | (long) y << 16;
+ default: throw new IllegalArgumentException("Invalid Axis enum: [" + dir.axis + "].");
+ }
+ }
}
- /** compares this quad's position to the given quad */
+ //endregion
+
+
+
+ /** compares this quad's position to the given quad using pre-computed sort keys */
public int compare(BufferQuad quad, BufferMergeDirectionEnum compareDirection)
{
if (this.direction != quad.direction)
throw new IllegalArgumentException("The other quad is not in the same direction: " + quad.direction + " vs " + this.direction);
- if (compareDirection == BufferMergeDirectionEnum.EastWest)
- {
- switch (this.direction.axis)
- {
- case X:
- return threeDimensionalCompare(this.x, this.y, this.z, quad.x, quad.y, quad.z);
- case Y:
- return threeDimensionalCompare(this.y, this.z, this.x, quad.y, quad.z, quad.x);
- case Z:
- return threeDimensionalCompare(this.z, this.y, this.x, quad.z, quad.y, quad.x);
-
- default:
- throw new IllegalArgumentException("Invalid Axis enum: [" + this.direction.axis + "].");
- }
- }
- else
- {
- switch (this.direction.axis)
- {
- case X:
- return threeDimensionalCompare(this.x, this.z, this.y, quad.x, quad.z, quad.y);
- case Y:
- return threeDimensionalCompare(this.y, this.x, this.z, quad.y, quad.x, quad.z);
- case Z:
- return threeDimensionalCompare(this.z, this.x, this.y, quad.z, quad.x, quad.y);
-
- default:
- throw new IllegalArgumentException("Invalid Axis enum: [" + this.direction.axis + "].");
- }
- }
- }
- /**
- * Compares two 3D points A and B.
- * The X, Y, and Z coordinates can be passed into parameters 0, 1, and 2 in any order
- * provided they are in the same order for both A and B.
- * With the 0th parameter being the most significant when comparing.
- */
- private static int threeDimensionalCompare(short a0, short a1, short a2, short b0, short b1, short b2)
- {
- long a = (long) a0 << 48 | (long) a1 << 32 | (long) a2 << 16;
- long b = (long) b0 << 48 | (long) b1 << 32 | (long) b2 << 16;
- return Long.compare(a, b);
+ return compareDirection == BufferMergeDirectionEnum.EastWest
+ ? Long.compare(this.sortKeyEastWest, quad.sortKeyEastWest)
+ : Long.compare(this.sortKeyNorthSouth, quad.sortKeyNorthSouth);
}
@@ -154,11 +146,15 @@ public final class BufferQuad
public boolean tryMerge(BufferQuad quad, BufferMergeDirectionEnum mergeDirection)
{
if (quad.hasError || this.hasError)
+ {
return false;
+ }
// only merge quads that are in the same direction
if (this.direction != quad.direction)
+ {
return false;
+ }
// make sure these quads share the same perpendicular axis
if ((mergeDirection == BufferMergeDirectionEnum.EastWest && this.y != quad.y)
@@ -175,7 +171,6 @@ public final class BufferQuad
short otherParallelCompareStartPos;
switch (this.direction.axis)
{
- default: // shouldn't normally happen, just here to make the compiler happy
case X:
if (mergeDirection == BufferMergeDirectionEnum.EastWest)
{
@@ -232,6 +227,9 @@ public final class BufferQuad
otherParallelCompareStartPos = quad.z;
}
break;
+
+ default: // shouldn't normally happen, just here to make the compiler happy
+ throw new IllegalArgumentException("Unsupported axis: ["+this.direction.axis+"]");
}
// get the width of this quad in the relevant axis
@@ -333,4 +331,6 @@ public final class BufferQuad
return true;
}
+
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java
index cfa0082e2..bff8ece2a 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java
@@ -341,13 +341,24 @@ public class ColumnBox
// Apply light to the range [adjMinY, adjMaxY)
- applyLightToRange(segments, newSegments, adjMinY, adjMaxY, lightToApply);
+ applyLightToRangeAndPopulateNewSgements(segments, newSegments, adjMinY, adjMaxY, lightToApply);
+ {
+ // swap references so we can use the newly populated segments
+ LongArrayList temp = segments;
+ segments = newSegments;
+ newSegments = temp;
+ }
// Fill overhang area [adjMaxY, adjAboveMinY) with adjSkyLight
short adjAboveMinY = RenderDataPointUtil.getYMin(adjAbovePoint);
if (adjMaxY < adjAboveMinY)
{
- applyLightToRange(segments, newSegments, adjMaxY, adjAboveMinY, adjSkyLight);
+ applyLightToRangeAndPopulateNewSgements(segments, newSegments, adjMaxY, adjAboveMinY, adjSkyLight);
+ {
+ LongArrayList temp = segments;
+ segments = newSegments;
+ newSegments = temp;
+ }
}
}
@@ -373,10 +384,11 @@ public class ColumnBox
/**
* Apply the new light value over the given y range,
* splitting segments as needed
+ * and putting the new segments into "newSegments"
*
* source: claude.ai */ - private static void applyLightToRange( + private static void applyLightToRangeAndPopulateNewSgements( LongArrayList segments, LongArrayList newSegments, short rangeStart, short rangeEnd, byte newLight) @@ -419,9 +431,6 @@ public class ColumnBox newSegments.add(YSegmentUtil.encode(rangeEnd, endY, skyLight)); } } - - segments.clear(); - segments.addAll(newSegments); } private static void tryAddVerticalFaceWithSkyLightToBuilder( diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java index 3af137531..95f249aa2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java @@ -129,6 +129,7 @@ public class FullDataToRenderDataTransformer ColumnRenderView tempExpandingColumnView = ColumnRenderView.getPooled(); RenderDataPointReducingList reducingList = new RenderDataPointReducingList()) { + DhBlockPosMutable mutableBlockPos = new DhBlockPosMutable(); for (int x = 0; x < FullDataSourceV2.WIDTH; x++) { for (int z = 0; z < FullDataSourceV2.WIDTH; z++) @@ -142,7 +143,7 @@ public class FullDataToRenderDataTransformer baseX + BitShiftUtil.pow(x, dataDetail), baseZ + BitShiftUtil.pow(z, dataDetail), columnArrayView, dataColumn, // pooled references so we don't need to re-allocate/get them 4000 times per render source - phantomCheckout, tempExpandingColumnView, reducingList); + phantomCheckout, tempExpandingColumnView, reducingList, mutableBlockPos); } } } @@ -157,7 +158,7 @@ public class FullDataToRenderDataTransformer ColumnRenderView columnArrayView, LongArrayList fullDataColumn, // pooled references - PhantomArrayListCheckout phantomCheckout, ColumnRenderView tempExpandingColumnView, RenderDataPointReducingList reducingList) + PhantomArrayListCheckout phantomCheckout, ColumnRenderView tempExpandingColumnView, RenderDataPointReducingList reducingList, DhBlockPosMutable mutableBlockPos) { // we can't do anything if the full data is missing or empty if (fullDataColumn == null @@ -170,7 +171,7 @@ public class FullDataToRenderDataTransformer if (fullDataLength <= columnArrayView.maxVerticalSliceCount) { // Directly use the arrayView since it fits. - setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, columnArrayView, fullDataColumn); + setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, columnArrayView, fullDataColumn, mutableBlockPos); } else { @@ -178,7 +179,7 @@ public class FullDataToRenderDataTransformer // expand the ColumnArrayView to fit the new larger max vertical size tempExpandingColumnView.populate(dataArrayList, fullDataLength, 0, fullDataLength); - setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, tempExpandingColumnView, fullDataColumn); + setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, tempExpandingColumnView, fullDataColumn, mutableBlockPos); columnArrayView.changeVerticalSizeFrom(tempExpandingColumnView, reducingList); } @@ -186,7 +187,7 @@ public class FullDataToRenderDataTransformer private static void setRenderColumnView( IClientLevelWrapper levelWrapper, FullDataSourceV2 fullDataSource, int blockX, int blockZ, - ColumnRenderView renderColumnData, LongArrayList fullColumnData) + ColumnRenderView renderColumnData, LongArrayList fullColumnData, DhBlockPosMutable mutableBlockPos) { //===============// // config values // @@ -242,7 +243,8 @@ public class FullDataToRenderDataTransformer FullDataPointIdMap fullDataMapping = fullDataSource.mapping; - DhBlockPosMutable mutableBlockPos = new DhBlockPosMutable(blockX, 0, blockZ); + mutableBlockPos.setX(blockX); + mutableBlockPos.setZ(blockZ); // goes from the top down for (int fullDataIndex = 0; fullDataIndex < fullColumnData.size(); fullDataIndex++) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/RateLimitedThreadPoolExecutor.java b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/RateLimitedThreadPoolExecutor.java index ad142d2e9..aa8203c3d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/RateLimitedThreadPoolExecutor.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/RateLimitedThreadPoolExecutor.java @@ -73,10 +73,17 @@ public class RateLimitedThreadPoolExecutor extends ThreadPoolExecutor { super.afterExecute(runnable, throwable); + double ratio = this.runTimeRatioConfig.get(); + if (ratio >= 1.0) + { + // Avoid sleeping for 0 time + return; + } + try { long runTime = System.nanoTime() - this.runStartTime.get(); - Thread.sleep(TimeUnit.NANOSECONDS.toMillis((long) (runTime / this.runTimeRatioConfig.get() - runTime))); + Thread.sleep(TimeUnit.NANOSECONDS.toMillis((long) (runTime / ratio - runTime))); } catch (InterruptedException ignore) { diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index 69dbd660e..4887d3807 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -188,11 +188,11 @@ "If true non terrain objects will be rendered in DH's terrain. \nThis includes beacon beams and clouds.", "distanthorizons.config.client.advanced.graphics.genericRendering.enableBeaconRendering": "Enable Beacon Rendering", - "distanthorizons.config.client.advanced.graphics.genericRendering.beaconRenderHeight": + "distanthorizons.config.client.advanced.graphics.genericRendering.beaconRenderHeight": "Beacon render height", "distanthorizons.config.client.advanced.graphics.genericRendering.beaconRenderHeight.@tooltip": "Sets the maximum height at which beacons will render. \nThis will only affect new beacons coming into LOD render distance. \nBeacons currently visible in LOD chunks will not be affected.", - "distanthorizons.config.client.advanced.graphics.genericRendering.expandDistantBeacons": + "distanthorizons.config.client.advanced.graphics.genericRendering.expandDistantBeacons": "Expand Distant Beacons", "distanthorizons.config.client.advanced.graphics.genericRendering.expandDistantBeacons.@tooltip": "If true LOD beacon beams will be rendered wider at extreme distances, \nmaking them easier to see. \nIf false all LOD beacon beams will only ever be 1 block wide.",