Fix LODs loading outside render distance

Fixes !1233
This commit is contained in:
James Seibel
2026-04-19 21:48:26 -05:00
parent 7e40546bc5
commit 2c266d2495
2 changed files with 74 additions and 14 deletions
@@ -245,7 +245,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
//===================// //===================//
//region //region
// remove out of bounds sections // remove out of bound sections
this.setCenterBlockPos(playerPos, (renderSection) -> this.setCenterBlockPos(playerPos, (renderSection) ->
{ {
if (renderSection != null) if (renderSection != null)
@@ -497,7 +497,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
// create the node // create the node
if (quadNode == null) if (quadNode == null)
{ {
rootNode.setValue(sectionPos, new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider)); rootNode.setValue(sectionPos, new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider));
quadNode = rootNode.getNode(sectionPos); quadNode = rootNode.getNode(sectionPos);
} }
@@ -506,6 +506,16 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
LodUtil.assertNotReach("Unable to add node with pos ["+DhSectionPos.toString(sectionPos)+"] to tree root ["+rootNode+"]."); LodUtil.assertNotReach("Unable to add node with pos ["+DhSectionPos.toString(sectionPos)+"] to tree root ["+rootNode+"].");
} }
// Skip sections that are out-of-bounds.
// If not done some sections will appear and/or generate
// outside the desired render distance
if (!this.isSectionPosInBounds(quadNode.sectionPos))
{
return;
}
// make sure the render section is created (shouldn't be necessary, but just in case) // make sure the render section is created (shouldn't be necessary, but just in case)
LodRenderSection renderSection = quadNode.value; LodRenderSection renderSection = quadNode.value;
if (renderSection == null) if (renderSection == null)
@@ -1121,6 +1131,17 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
{ {
this.populateListWithEnabledRenderSections(this.debugNodeList); this.populateListWithEnabledRenderSections(this.debugNodeList);
//// can be uncommented for debugging/finding a specific position
//debugRenderer.makeParticle(
// new AbstractDebugWireframeRenderer.BoxParticle(
// new AbstractDebugWireframeRenderer.Box(
// DhSectionPos.encode((byte)7, 3,-1)
// , -64, 400,
// 0.1f,
// Color.YELLOW),
// 0.5, 0f
// ));
for (int i = 0; i < this.debugNodeList.size(); i++) for (int i = 0; i < this.debugNodeList.size(); i++)
{ {
LodRenderSection renderSection = this.debugNodeList.get(i); LodRenderSection renderSection = this.debugNodeList.get(i);
@@ -359,19 +359,11 @@ public class QuadTree<T>
{ {
this.centerBlockPos = newCenterPos; this.centerBlockPos = newCenterPos;
MovableGridRingList.Pos2D expectedCenterPos = new MovableGridRingList.Pos2D( int newCenterPosX = BitShiftUtil.divideByPowerOfTwo(this.centerBlockPos.x, this.treeRootDetailLevel);
BitShiftUtil.divideByPowerOfTwo(this.centerBlockPos.x, this.treeRootDetailLevel), int newCenterPosZ = BitShiftUtil.divideByPowerOfTwo(this.centerBlockPos.z, this.treeRootDetailLevel);
BitShiftUtil.divideByPowerOfTwo(this.centerBlockPos.z, this.treeRootDetailLevel));
if (this.topRingList.getCenter().equals(expectedCenterPos)) // remove out of bound root nodes
{ this.topRingList.moveTo(newCenterPosX, newCenterPosZ, (quadNode) ->
// tree doesn't need to be moved
return;
}
// remove out of bounds root nodes
this.topRingList.moveTo(expectedCenterPos.getX(), expectedCenterPos.getY(), (quadNode) ->
{ {
if (quadNode != null) if (quadNode != null)
{ {
@@ -383,6 +375,53 @@ public class QuadTree<T>
} }
} }
}); });
// remove out of bound child nodes
this.topRingList.forEach((rootNode) ->
{
this.recursivelyClearOutOfBoundNodes(rootNode, removedItemConsumer);
});
}
private void recursivelyClearOutOfBoundNodes(@Nullable QuadNode<T> quadNode, @Nullable Consumer<? super T> removedItemConsumer)
{
// nodes shouldn't be null, but just in case
if (quadNode == null)
{
return;
}
// go over each child node
for (int i = 0; i < 4; i++)
{
QuadNode<T> childNode = quadNode.getChildByIndex(i);
if (childNode == null
|| childNode.value == null)
{
// no need to go any deeper if this node is already empty
continue;
}
// clear nodes from the bottom up
this.recursivelyClearOutOfBoundNodes(childNode, removedItemConsumer);
// clear this node if out of bounds
if (!this.isSectionPosInBounds(childNode.sectionPos))
{
T oldValue = childNode.value;
// We don't remove the node until the root is removed since there isn't an
// easy way to do so.
// However, from outside the tree a null value is equivalent to the node
// not existing, so it should work fine.
childNode.value = null;
if (removedItemConsumer != null)
{
removedItemConsumer.accept(oldValue);
}
}
}
} }
public final DhBlockPos2D getCenterBlockPos() { return this.centerBlockPos; } public final DhBlockPos2D getCenterBlockPos() { return this.centerBlockPos; }