From 89062a88cf7c4ca1b6c2a219701b8a3952c48483 Mon Sep 17 00:00:00 2001 From: Christopher Cyclonit Klinge Date: Wed, 30 Mar 2022 11:57:27 +0200 Subject: [PATCH 1/2] Removed SurfaceTrackerLeaf.loadCube, because leaves can no longer load new cubes. If a new cube is added to a tree, a new leaf will be created instead. Moved invocations of HeightmapNode.sectionLoaded into ProtoCube and LevelCube respectively to loosen coupling between them and SurfaceTrackerLeaf. Changed SurfaceTrackerLeaf.node to be final. Added copy-constructor to SurfaceTrackerLeaf. Changed SurfaceTrackerBranch.loadCube to support creating new leaves based on existing leaves. Uses the new copy-constructor in SurfaceTrackerLeaf. Removed heightmap handling from LevelCube.postLoad and moved it into the proto promotion constructor. --- .../world/level/chunk/LevelCube.java | 51 +++++++-------- .../world/level/chunk/ProtoCube.java | 8 +-- .../SurfaceTrackerBranch.java | 35 ++++++++--- .../SurfaceTrackerLeaf.java | 44 +++++-------- .../SurfaceTrackerNode.java | 24 +++++-- .../SurfaceTrackerSectionStorage.java | 2 +- .../SurfaceTrackerWrapper.java | 4 +- .../heightmap/SurfaceTrackerBranchTest.java | 2 +- .../heightmap/SurfaceTrackerLeafTest.java | 31 +++------- .../heightmap/SurfaceTrackerNodesTest.java | 62 ++++++++++--------- 10 files changed, 132 insertions(+), 131 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java index 7ade6b474..dae523d92 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java @@ -225,21 +225,32 @@ public LevelCube(Level level, ProtoCube protoCube, @Nullable Consumer this.setAllStarts(protoCube.getAllCubeStructureStarts()); this.setAllReferences(protoCube.getAllReferences()); - this.heightmaps.putAll(protoCube.getCubeHeightmaps()); + // copy protoCube's heightmaps + ChunkPos pos = this.cubePos.asChunkPos(); + HeightmapStorage storage = ((CubicServerLevel) this.level).getHeightmapStorage(); - SurfaceTrackerLeaf[] protoCubeLightHeightmaps = protoCube.getLightHeightmaps(); - for (int localZ = 0; localZ < CubeAccess.DIAMETER_IN_SECTIONS; localZ++) { - for (int localX = 0; localX < CubeAccess.DIAMETER_IN_SECTIONS; localX++) { - int i = localX + localZ * CubeAccess.DIAMETER_IN_SECTIONS; + for (int sectionX = 0; sectionX < CubeAccess.DIAMETER_IN_SECTIONS; sectionX++) { + for (int sectionZ = 0; sectionZ < CubeAccess.DIAMETER_IN_SECTIONS; sectionZ++) { - this.lightHeightmaps[i] = protoCubeLightHeightmaps[i]; - if (this.lightHeightmaps[i] == null) { - System.out.println("Got a null light heightmap while upgrading from CubePrimer at " + this.cubePos); - } else { - this.lightHeightmaps[i].loadCube(localX, localZ, ((CubicServerLevel) this.level).getHeightmapStorage(), this); + LevelChunk chunk = this.level.getChunk(pos.x + sectionX, pos.z + sectionZ); + int heightmapIndex = sectionX + sectionZ * DIAMETER_IN_SECTIONS; + + // promote the ProtoCube's vanilla heightmaps for this chunk + for (Map.Entry entry : chunk.getHeightmaps()) { + SurfaceTrackerWrapper wrapper = (SurfaceTrackerWrapper) entry.getValue(); + SurfaceTrackerLeaf protoLeaf = protoCube.getCubeHeightmaps().get(entry.getKey())[heightmapIndex]; + SurfaceTrackerLeaf levelLeaf = wrapper.loadCube(storage, this, protoLeaf); + sectionLoaded(levelLeaf, sectionX, sectionZ); } + + // promote the ProtoCube's light heightmap for this chunk + SurfaceTrackerWrapper lightWrapper = (SurfaceTrackerWrapper) ((LightHeightmapGetter) chunk).getLightHeightmap(); + SurfaceTrackerLeaf lightProtoLeaf = protoCube.getLightHeightmaps()[heightmapIndex]; + SurfaceTrackerLeaf lightLevelLeaf = lightWrapper.loadCube(storage, this, lightProtoLeaf); + sectionLoaded(lightLevelLeaf, sectionX, sectionZ); } } + this.setCubeLight(protoCube.hasCubeLight()); this.dirty = true; } @@ -1090,29 +1101,11 @@ public void unpackTicks() { } public void postLoad() { + if (this.postLoad != null) { this.postLoad.accept(this); this.postLoad = null; } - // TODO heightmap stuff should probably be elsewhere rather than here. - ChunkPos pos = this.cubePos.asChunkPos(); - HeightmapStorage storage = ((CubicServerLevel) this.level).getHeightmapStorage(); - for (int x = 0; x < CubeAccess.DIAMETER_IN_SECTIONS; x++) { - for (int z = 0; z < CubeAccess.DIAMETER_IN_SECTIONS; z++) { - - // This force-loads the column, but it shouldn't matter if column-cube load order is working properly. - LevelChunk chunk = this.level.getChunk(pos.x + x, pos.z + z); - ((ColumnCubeMapGetter) chunk).getCubeMap().markLoaded(this.cubePos.getY()); - for (Map.Entry entry : chunk.getHeightmaps()) { - Heightmap heightmap = entry.getValue(); - SurfaceTrackerWrapper tracker = (SurfaceTrackerWrapper) heightmap; - tracker.loadCube(storage, this); - } - - // TODO probably don't want to do this if the cube was already loaded as a CubePrimer - ((LightHeightmapGetter) chunk).getServerLightHeightmap().loadCube(storage, this); - } - } } public void invalidateAllBlockEntities() { diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java index a9d3597ec..e63870957 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java @@ -224,7 +224,8 @@ public void onEnteringFeaturesStatus() { } } - lightHeightmap.loadCube(((CubicServerLevel) this.levelHeightAccessor).getHeightmapStorage(), this); + SurfaceTrackerLeaf lightLeaf = lightHeightmap.loadCube(((CubicServerLevel) this.levelHeightAccessor).getHeightmapStorage(), this, null); + sectionLoaded(lightLeaf, dx, dz); for (int z = 0; z < SECTION_DIAMETER; z++) { for (int x = 0; x < SECTION_DIAMETER; x++) { @@ -368,12 +369,11 @@ private SurfaceTrackerLeaf[] getHeightmapSections(Heightmap.Types type) { for (int dx = 0; dx < CubeAccess.DIAMETER_IN_SECTIONS; dx++) { for (int dz = 0; dz < CubeAccess.DIAMETER_IN_SECTIONS; dz++) { int idx = dx + dz * CubeAccess.DIAMETER_IN_SECTIONS; - SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(cubePos.getY(), null, (byte) type.ordinal()); - leaf.loadCube(dx, dz, ((CubicServerLevel) ((ServerLevelAccessor) this.levelHeightAccessor).getLevel()).getHeightmapStorage(), this); + SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(this, null, (byte) type.ordinal()); // On creation of a new node for a cube, both the node and its parents must be marked dirty leaf.setAllDirty(); - leaf.markAncestorsDirty(); surfaceTrackerLeaves[idx] = leaf; + sectionLoaded(leaf, dx, dz); } } return surfaceTrackerLeaves; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java index 536a82bb4..b282060db 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java @@ -43,7 +43,7 @@ protected int updateHeight(int x, int z, int idx) { } } - @Override public void loadCube(int localSectionX, int localSectionZ, HeightmapStorage storage, HeightmapNode newNode) { + public SurfaceTrackerLeaf loadCube(int localSectionX, int localSectionZ, HeightmapStorage storage, HeightmapNode newNode, @Nullable SurfaceTrackerLeaf protoLeaf) { int newScale = scale - 1; // Attempt to load all children from storage @@ -56,18 +56,39 @@ protected int updateHeight(int x, int z, int idx) { int idx = indexOfRawHeightNode(newNode.getNodeY(), scale, scaledY); int newScaledY = indexToScaledY(idx, scale, scaledY); - if (children[idx] == null) { - // If the child containing new node has not been loaded from storage, create it - // Scale 1 nodes create leaf node children - if (newScale == 0) { - children[idx] = new SurfaceTrackerLeaf(newScaledY, this, this.heightmapType); + + // child is a leaf + if (newScale == 0) { + + assert children[idx] == null : "Duplicate leaf!"; + + SurfaceTrackerLeaf newLeaf; + if (protoLeaf == null) { + newLeaf = new SurfaceTrackerLeaf(newNode, this, this.heightmapType); } else { + newLeaf = new SurfaceTrackerLeaf(newNode, this, protoLeaf); + } + children[idx] = newLeaf; + newNode.sectionLoaded(newLeaf, localSectionX, localSectionZ); + newLeaf.markAncestorsDirty(); + + onChildLoaded(); + + return newLeaf; + } + + // child is a branch + else { + + if (children[idx] == null) { children[idx] = new SurfaceTrackerBranch(newScale, newScaledY, this, this.heightmapType); } + + return ((SurfaceTrackerBranch) children[idx]).loadCube(localSectionX, localSectionZ, storage, newNode, protoLeaf); } - children[idx].loadCube(localSectionX, localSectionZ, storage, newNode); } + @Override protected void unload(HeightmapStorage storage) { for (SurfaceTrackerNode child : this.children) { assert child == null : "Heightmap branch being unloaded while holding a child?!"; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerLeaf.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerLeaf.java index d8157639b..279ca8e7a 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerLeaf.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerLeaf.java @@ -11,12 +11,22 @@ import io.github.opencubicchunks.cubicchunks.world.level.levelgen.heightmap.HeightmapStorage; public class SurfaceTrackerLeaf extends SurfaceTrackerNode { - protected HeightmapNode node; - public SurfaceTrackerLeaf(int y, @Nullable SurfaceTrackerBranch parent, byte heightmapType) { - super(0, y, parent, heightmapType); + protected final HeightmapNode node; + + public SurfaceTrackerLeaf(HeightmapNode node, @Nullable SurfaceTrackerBranch parent, byte heightmapType) { + super(0, node.getNodeY(), parent, heightmapType); + + this.node = node; + } + + public SurfaceTrackerLeaf(HeightmapNode node, @Nullable SurfaceTrackerBranch parent, SurfaceTrackerLeaf protoLeaf) { + super(0, node.getNodeY(), parent, protoLeaf.heightmapType, protoLeaf.heights, protoLeaf.dirtyPositions); + + this.node = node; } + @Override protected int updateHeight(int x, int z, int idx) { synchronized(this) { @@ -29,27 +39,6 @@ protected int updateHeight(int x, int z, int idx) { } } - @Override - public synchronized void loadCube(int localSectionX, int localSectionZ, HeightmapStorage storage, @Nonnull HeightmapNode newNode) { - boolean isBeingInitialized = this.node == null; - - this.node = newNode; - newNode.sectionLoaded(this, localSectionX, localSectionZ); - - // Parent might be null for proto-cube leaf nodes - // If we are inserting a new node (it's parent is null), the parents must be updated. - // The parent can already be set for LevelCubes, their heights are inherited from their ProtoCubes - // and do not need to be updated - if (this.parent != null) { - this.markAncestorsDirty(); - if (isBeingInitialized) { - // If this is the first node inserted into this leaf, we inform the parent node. - // Both ProtoCube and LevelCube will call loadCube, this avoids invalid reference counting - this.parent.onChildLoaded(); - } - } - } - @Override protected void unload(@Nonnull HeightmapStorage storage) { assert this.node == null : "Heightmap leaf being unloaded while holding a cube?!"; @@ -68,7 +57,7 @@ public void cubeUnloaded(int localSectionX, int localSectionZ, HeightmapStorage // On unloading the node, the leaf must have no dirty positions updateDirtyHeights(localSectionX, localSectionZ); - this.node = null; +// TODO: this.node = null; // Parent can be null for a protocube that hasn't been added to the global heightmap if (parent != null) { @@ -149,9 +138,4 @@ public SurfaceTrackerLeaf getSectionAbove() { // TODO this can be optimized - don't need to go to the root every time, just the lowest node that is a parent of both this node and the node above. return this.getRoot().getMinScaleNode(scaledY + 1); } - - @VisibleForTesting - public void setNode(@Nullable HeightmapNode node) { - this.node = node; - } } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java index 11c10745e..e3b8d8de6 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java @@ -40,16 +40,30 @@ public abstract class SurfaceTrackerNode { protected final byte heightmapType; public SurfaceTrackerNode(int scale, int scaledY, @Nullable SurfaceTrackerBranch parent, byte heightmapType) { -// super((ChunkAccess) node, types); - // +1 in bit size to make room for null values - this.heights = new BitStorage(BASE_SIZE_BITS + 1 + scale * NODE_COUNT_BITS, WIDTH_BLOCKS * WIDTH_BLOCKS); - this.dirtyPositions = new long[WIDTH_BLOCKS * WIDTH_BLOCKS / Long.SIZE]; + this(scale, scaledY, parent, heightmapType, + new BitStorage(BASE_SIZE_BITS + 1 + scale * NODE_COUNT_BITS, WIDTH_BLOCKS * WIDTH_BLOCKS), + new long[WIDTH_BLOCKS * WIDTH_BLOCKS / Long.SIZE] + ); + } + + protected SurfaceTrackerNode(int scale, int scaledY, @Nullable SurfaceTrackerBranch parent, byte heightmapType, BitStorage heights, long[] dirtyPositions) { + this.heights = heights; + this.dirtyPositions = dirtyPositions; this.parent = parent; this.scaledY = scaledY; this.scale = (byte) scale; this.heightmapType = heightmapType; } + + private BitStorage getRawHeights() { + return heights; + } + + private long[] getDirtyPositions() { + return dirtyPositions; + } + /** * Get the height for a given position. Recomputes the height if the column is marked dirty in this section. * x and z are GLOBAL coordinates (cube local is also fine, but section/chunk local is WRONG). @@ -68,8 +82,6 @@ public int getHeight(int x, int z) { */ protected abstract int updateHeight(int x, int z, int idx); - public abstract void loadCube(int localSectionX, int localSectionZ, HeightmapStorage storage, HeightmapNode newNode); - /** * Tells a node to unload itself, nulling its parent, and passing itself to the provided storage */ diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerSectionStorage.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerSectionStorage.java index 022a6da77..0da2da76c 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerSectionStorage.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerSectionStorage.java @@ -15,7 +15,7 @@ public void unloadNode(SurfaceTrackerNode surfaceTrackerNode) { saved.put(new PackedTypeScaleScaledY(surfaceTrackerNode.heightmapType, surfaceTrackerNode.scale, surfaceTrackerNode.scaledY), surfaceTrackerNode); if (surfaceTrackerNode.scale == 0) { - ((SurfaceTrackerLeaf) surfaceTrackerNode).node = null; +// TODO: ((SurfaceTrackerLeaf) surfaceTrackerNode).node = null; } else { Arrays.fill(((SurfaceTrackerBranch) surfaceTrackerNode).children, null); } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java index 18dc87270..ab857c93d 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java @@ -76,8 +76,8 @@ public long[] getRawData() { return data.getRaw(); } - public synchronized void loadCube(HeightmapStorage storage, HeightmapNode node) { - this.surfaceTracker.loadCube(blockToCubeLocalSection(dx), blockToCubeLocalSection(dz), storage, node); + public synchronized SurfaceTrackerLeaf loadCube(HeightmapStorage storage, HeightmapNode node, @Nullable SurfaceTrackerLeaf protoLeaf) { + return this.surfaceTracker.loadCube(blockToCubeLocalSection(dx), blockToCubeLocalSection(dz), storage, node, protoLeaf); } @Nullable diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java index ea9d58bd8..e78256eba 100644 --- a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java @@ -37,7 +37,7 @@ public void testValidScaleBounds() { public void testLeafInsertionIntoRoot() { NullHeightmapStorage storage = new NullHeightmapStorage(); SurfaceTrackerBranch root = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); - root.loadCube(0, 0, storage, new TestHeightmapNode(0)); + root.loadCube(0, 0, storage, new TestHeightmapNode(0), null); SurfaceTrackerLeaf leaf = root.getMinScaleNode(0); assertNotNull(leaf, "Appropriate leaf was null after loading node into root"); diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java index 0d2737e04..d107b0f1e 100644 --- a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java @@ -30,9 +30,10 @@ public class SurfaceTrackerLeafTest { */ @Test public void testCubeLoadUnload() { - SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(0, null, (byte) 0); - leaf.loadCube(0, 0, null, new TestHeightmapNode(0)); + TestHeightmapNode testNode = new TestHeightmapNode(0); + SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(testNode, null, (byte) 0); + assertNotNull(leaf.getNode(), "Leaf had null HeightmapNode after being loaded"); leaf.cubeUnloaded(0, 0, null); @@ -48,7 +49,7 @@ public void testLeafUnload() { //Set up leaf and node with parent SurfaceTrackerBranch parent = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); - parent.loadCube(0, 0, storage, new TestHeightmapNode(0)); + parent.loadCube(0, 0, storage, new TestHeightmapNode(0), null); SurfaceTrackerLeaf leaf = parent.getMinScaleNode(0); //Unload the node @@ -63,11 +64,9 @@ public void testLeafUnload() { */ @Test public void testNoValidHeights() { - NullHeightmapStorage storage = new NullHeightmapStorage(); - SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(0, null, (byte) 0); TestHeightmapNode testNode = new TestHeightmapNode(0); - leaf.loadCube(0, 0, storage, testNode); + SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(testNode, null, (byte) 0); Consumer setHeight = block -> testNode.setBlock(block.x(), block.y() & (SurfaceTrackerLeaf.SCALE_0_NODE_HEIGHT - 1), block.z(), block.isOpaque()); @@ -92,11 +91,8 @@ public void testNoValidHeights() { public void testBasicFunctionality() { ReferenceHeightmap reference = new ReferenceHeightmap(0); - NullHeightmapStorage storage = new NullHeightmapStorage(); - - SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(0, null, (byte) 0); TestHeightmapNode testNode = new TestHeightmapNode(0); - leaf.loadCube(0, 0, storage, testNode); + SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(testNode, null, (byte) 0); Consumer setHeight = block -> { reference.set(block.y(), block.isOpaque()); @@ -135,11 +131,8 @@ public void testBasicFunctionality() { public void testManyPositions(int nodeY) { ReferenceHeightmap reference = new ReferenceHeightmap(nodeY); - NullHeightmapStorage storage = new NullHeightmapStorage(); - - SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(nodeY, null, (byte) 0); TestHeightmapNode testNode = new TestHeightmapNode(nodeY); - leaf.loadCube(0, 0, storage, testNode); + SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(testNode, null, (byte) 0); Consumer setHeight = block -> { reference.set(block.y(), block.isOpaque()); @@ -177,11 +170,8 @@ public void testManyPositions(int nodeY) { public void testSeededRandom() { ReferenceHeightmap reference = new ReferenceHeightmap(0); - NullHeightmapStorage storage = new NullHeightmapStorage(); - - SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(0, null, (byte) 0); TestHeightmapNode testNode = new TestHeightmapNode(0); - leaf.loadCube(0, 0, storage, testNode); + SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(testNode, null, (byte) 0); Consumer setHeight = block -> { reference.set(block.y(), block.isOpaque()); @@ -208,10 +198,9 @@ public void testSeededRandom() { */ @Test public void testBounds() { - NullHeightmapStorage storage = new NullHeightmapStorage(); - SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(0, null, (byte) 0); - leaf.loadCube(0, 0, storage, new TestHeightmapNode(0)); + TestHeightmapNode node = new TestHeightmapNode(0); + SurfaceTrackerLeaf leaf = new SurfaceTrackerLeaf(node, null, (byte) 0); Consumer setHeight = block -> { leaf.onSetBlock(block.x(), block.y(), block.z(), type -> block.isOpaque()); diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java index 5f2254231..49a496f7b 100644 --- a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java @@ -51,14 +51,14 @@ public void sanityTest() { ReferenceHeightmap reference = new ReferenceHeightmap(2048); TestHeightmapNode node0 = new TestHeightmapNode(0); - SurfaceTrackerNode[] roots = new SurfaceTrackerNode[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; + SurfaceTrackerBranch[] roots = new SurfaceTrackerBranch[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; for (int i = 0; i < roots.length; i++) { roots[i] = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); } for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node0); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node0, null); } } @@ -95,14 +95,14 @@ public void testNoValidHeights() { ReferenceHeightmap reference = new ReferenceHeightmap(2048); TestHeightmapNode node0 = new TestHeightmapNode(0); - SurfaceTrackerNode[] roots = new SurfaceTrackerNode[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; + SurfaceTrackerBranch[] roots = new SurfaceTrackerBranch[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; for (int i = 0; i < roots.length; i++) { - roots[i] = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); + roots[i] = new SurfaceTrackerBranch(SurfaceTrackerBranch.MAX_SCALE, 0, null, (byte) 0); } for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node0); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node0, null); } } @@ -139,7 +139,7 @@ public void seededRandom() { ReferenceHeightmap reference = new ReferenceHeightmap(maxCoordinate); Map nodes = new HashMap<>(); - SurfaceTrackerNode[] roots = new SurfaceTrackerNode[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; + SurfaceTrackerBranch[] roots = new SurfaceTrackerBranch[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; for (int i = 0; i < roots.length; i++) { roots[i] = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); } @@ -150,7 +150,7 @@ public void seededRandom() { TestHeightmapNode node = new TestHeightmapNode(y); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node,null); } } return node; @@ -179,7 +179,7 @@ public void simpleUnloadTree1() { TestHeightmapStorage storage = new TestHeightmapStorage(); Map nodes = new HashMap<>(); - SurfaceTrackerNode[] roots = new SurfaceTrackerNode[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; + SurfaceTrackerBranch[] roots = new SurfaceTrackerBranch[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; for (int i = 0; i < roots.length; i++) { roots[i] = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); } @@ -188,7 +188,7 @@ public void simpleUnloadTree1() { TestHeightmapNode node = new TestHeightmapNode(yPos); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node, null); } } return node; @@ -217,7 +217,7 @@ public void simpleUnloadTree2() { TestHeightmapStorage storage = new TestHeightmapStorage(); Map nodes = new HashMap<>(); - SurfaceTrackerNode[] roots = new SurfaceTrackerNode[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; + SurfaceTrackerBranch[] roots = new SurfaceTrackerBranch[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; for (int i = 0; i < roots.length; i++) { roots[i] = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); } @@ -226,7 +226,7 @@ public void simpleUnloadTree2() { TestHeightmapNode node = new TestHeightmapNode(yPos); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node, null); } } return node; @@ -271,7 +271,7 @@ public void seededRandomUnloadTree() { TestHeightmapStorage storage = new TestHeightmapStorage(); Map nodes = new HashMap<>(); - SurfaceTrackerNode[] roots = new SurfaceTrackerNode[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; + SurfaceTrackerBranch[] roots = new SurfaceTrackerBranch[CubeAccess.DIAMETER_IN_SECTIONS * CubeAccess.DIAMETER_IN_SECTIONS]; for (int i = 0; i < roots.length; i++) { roots[i] = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); } @@ -280,7 +280,7 @@ public void seededRandomUnloadTree() { TestHeightmapNode node = new TestHeightmapNode(yPos); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node, null); } } return node; @@ -325,11 +325,11 @@ public void testUnloadReload() { TestHeightmapStorage storage = new TestHeightmapStorage(); Map nodes = new HashMap<>(); - SurfaceTrackerNode root = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); + SurfaceTrackerBranch root = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); Function loadNode = y -> nodes.computeIfAbsent(y, yPos -> { TestHeightmapNode node = new TestHeightmapNode(yPos); - root.loadCube(0, 0, storage, node); + root.loadCube(0, 0, storage, node,null); return node; }); Function unloadNode = y -> { @@ -349,7 +349,7 @@ public void testUnloadReload() { unloadNode.apply(0); - root.loadCube(0, 0, storage, cubeNode); + root.loadCube(0, 0, storage, cubeNode, null); SurfaceTrackerLeaf reloadedNode = root.getMinScaleNode(0); @@ -421,12 +421,13 @@ private static void verifyAllNodesInRequiredSet(SurfaceTrackerBranch branch, Lon */ static class NullHeightmapStorage implements HeightmapStorage { @Override public void unloadNode(SurfaceTrackerNode node) { - if (node.getScale() == 0) { - ((SurfaceTrackerLeaf) node).setNode(null); - } else { - Arrays.fill(((SurfaceTrackerBranch) node).getChildren(), null); - } - node.setParent(null); + throw new RuntimeException("Not implemented"); +// if (node.getScale() == 0) { +// ((SurfaceTrackerLeaf) node).setNode(null); +// } else { +// Arrays.fill(((SurfaceTrackerBranch) node).getChildren(), null); +// } +// node.setParent(null); } @Nullable @Override public SurfaceTrackerNode loadNode(SurfaceTrackerBranch parent, byte heightmapType, int scale, int scaledY) { @@ -441,14 +442,15 @@ static class TestHeightmapStorage implements HeightmapStorage { Object2ReferenceMap saved = new Object2ReferenceOpenHashMap<>(); @Override public void unloadNode(SurfaceTrackerNode node) { - if (node.getScale() == 0) { - ((SurfaceTrackerLeaf) node).setNode(null); - } else { - Arrays.fill(((SurfaceTrackerBranch) node).getChildren(), null); - } - node.setParent(null); - - saved.put(new PackedTypeScaleScaledY(node.getRawType(), node.getScale(), node.getScaledY()), node); + throw new RuntimeException("Not implemented"); +// if (node.getScale() == 0) { +// ((SurfaceTrackerLeaf) node).setNode(null); +// } else { +// Arrays.fill(((SurfaceTrackerBranch) node).getChildren(), null); +// } +// node.setParent(null); +// +// saved.put(new PackedTypeScaleScaledY(node.getRawType(), node.getScale(), node.getScaledY()), node); } @Override public SurfaceTrackerNode loadNode(SurfaceTrackerBranch parent, byte heightmapType, int scale, int scaledY) { SurfaceTrackerNode removed = saved.remove(new PackedTypeScaleScaledY(heightmapType, scale, scaledY)); From 831b72918e113b480e2716c68ea767f36eea8f21 Mon Sep 17 00:00:00 2001 From: Christopher Cyclonit Klinge Date: Wed, 30 Mar 2022 17:38:25 +0200 Subject: [PATCH 2/2] Intermediate commit to allow debugging by others. --- .../world/level/chunk/LevelCube.java | 44 ++++++++++++------- .../world/level/chunk/ProtoCube.java | 25 +++++------ .../levelgen/heightmap/HeightmapNode.java | 4 -- .../SurfaceTrackerBranch.java | 23 +++++++--- .../SurfaceTrackerNode.java | 8 ---- .../SurfaceTrackerWrapper.java | 2 +- .../heightmap/SurfaceTrackerBranchTest.java | 2 +- .../heightmap/SurfaceTrackerLeafTest.java | 2 +- .../heightmap/SurfaceTrackerNodesTest.java | 20 ++++----- 9 files changed, 64 insertions(+), 66 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java index dae523d92..da9377750 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/LevelCube.java @@ -229,6 +229,11 @@ public LevelCube(Level level, ProtoCube protoCube, @Nullable Consumer ChunkPos pos = this.cubePos.asChunkPos(); HeightmapStorage storage = ((CubicServerLevel) this.level).getHeightmapStorage(); + // initialize the heightmap map + for (Heightmap.Types type : Heightmap.Types.values()) { + this.heightmaps.put(type, new SurfaceTrackerLeaf[DIAMETER_IN_SECTIONS*DIAMETER_IN_SECTIONS]); + } + for (int sectionX = 0; sectionX < CubeAccess.DIAMETER_IN_SECTIONS; sectionX++) { for (int sectionZ = 0; sectionZ < CubeAccess.DIAMETER_IN_SECTIONS; sectionZ++) { @@ -238,16 +243,22 @@ public LevelCube(Level level, ProtoCube protoCube, @Nullable Consumer // promote the ProtoCube's vanilla heightmaps for this chunk for (Map.Entry entry : chunk.getHeightmaps()) { SurfaceTrackerWrapper wrapper = (SurfaceTrackerWrapper) entry.getValue(); - SurfaceTrackerLeaf protoLeaf = protoCube.getCubeHeightmaps().get(entry.getKey())[heightmapIndex]; + + SurfaceTrackerLeaf[] protoLeaves = protoCube.getCubeHeightmaps().get(entry.getKey()); + SurfaceTrackerLeaf protoLeaf = protoLeaves != null ? protoLeaves[heightmapIndex] : null; + SurfaceTrackerLeaf levelLeaf = wrapper.loadCube(storage, this, protoLeaf); - sectionLoaded(levelLeaf, sectionX, sectionZ); + this.heightmaps.get(entry.getKey())[heightmapIndex] = levelLeaf; } // promote the ProtoCube's light heightmap for this chunk SurfaceTrackerWrapper lightWrapper = (SurfaceTrackerWrapper) ((LightHeightmapGetter) chunk).getLightHeightmap(); - SurfaceTrackerLeaf lightProtoLeaf = protoCube.getLightHeightmaps()[heightmapIndex]; - SurfaceTrackerLeaf lightLevelLeaf = lightWrapper.loadCube(storage, this, lightProtoLeaf); - sectionLoaded(lightLevelLeaf, sectionX, sectionZ); + SurfaceTrackerLeaf lightLevelLeaf = lightWrapper.loadCube(storage, this, null); + + if (lightLevelLeaf == null) + System.out.println("!"); + + this.lightHeightmaps[heightmapIndex] = lightLevelLeaf; } } @@ -259,18 +270,6 @@ public LevelCube(Level level, ProtoCube protoCube, @Nullable Consumer return this.heightmaps; } - @Override public void sectionLoaded(@Nonnull SurfaceTrackerLeaf surfaceTrackerLeaf, int localSectionX, int localSectionZ) { - int idx = localSectionX + localSectionZ * DIAMETER_IN_SECTIONS; - - if (surfaceTrackerLeaf.getRawType() == -1) { //light - this.lightHeightmaps[idx] = surfaceTrackerLeaf; - } else { // normal heightmap - this.heightmaps.computeIfAbsent(surfaceTrackerLeaf.getType(), - type -> new SurfaceTrackerLeaf[DIAMETER_IN_SECTIONS * DIAMETER_IN_SECTIONS] - )[idx] = surfaceTrackerLeaf; - } - } - @Override public void unloadNode(@Nonnull HeightmapStorage storage) { for (SurfaceTrackerLeaf[] heightmapLeaves : this.heightmaps.values()) { @@ -319,6 +318,17 @@ public int getHighestLight(int x, int z) { int zSection = blockToCubeLocalSection(z); int idx = xSection + zSection * DIAMETER_IN_SECTIONS; + + SurfaceTrackerLeaf leaf = this.lightHeightmaps[idx]; + try { + Thread.sleep(1); + } catch (InterruptedException ex) { + throw new RuntimeException(); + } + SurfaceTrackerLeaf leaf2 = this.lightHeightmaps[idx]; + if (leaf == null) + System.out.println("!"); + SurfaceTrackerLeaf sectionAbove = this.lightHeightmaps[idx].getSectionAbove(); int dy = CubeAccess.DIAMETER_IN_BLOCKS - 1; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java index e63870957..494028884 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/chunk/ProtoCube.java @@ -225,7 +225,12 @@ public void onEnteringFeaturesStatus() { } SurfaceTrackerLeaf lightLeaf = lightHeightmap.loadCube(((CubicServerLevel) this.levelHeightAccessor).getHeightmapStorage(), this, null); - sectionLoaded(lightLeaf, dx, dz); + int heightmapIndex = dx + dz * DIAMETER_IN_SECTIONS; + + if (lightLeaf == null) + System.out.println("!"); + + this.lightHeightmaps[heightmapIndex] = lightLeaf; for (int z = 0; z < SECTION_DIAMETER; z++) { for (int x = 0; x < SECTION_DIAMETER; x++) { @@ -241,19 +246,6 @@ public void onEnteringFeaturesStatus() { } } - @Override - public void sectionLoaded(@Nonnull SurfaceTrackerLeaf surfaceTrackerLeaf, int localSectionX, int localSectionZ) { - int idx = localSectionX + localSectionZ * DIAMETER_IN_SECTIONS; - - if (surfaceTrackerLeaf.getRawType() == -1) { //light - this.lightHeightmaps[idx] = surfaceTrackerLeaf; - } else { // normal heightmap - this.heightmaps.computeIfAbsent(surfaceTrackerLeaf.getType(), - type -> new SurfaceTrackerLeaf[DIAMETER_IN_SECTIONS * DIAMETER_IN_SECTIONS] - )[idx] = surfaceTrackerLeaf; - } - } - @Override public void unloadNode(@Nonnull HeightmapStorage storage) { for (SurfaceTrackerLeaf[] heightmapLeaves : this.heightmaps.values()) { @@ -373,7 +365,6 @@ private SurfaceTrackerLeaf[] getHeightmapSections(Heightmap.Types type) { // On creation of a new node for a cube, both the node and its parents must be marked dirty leaf.setAllDirty(); surfaceTrackerLeaves[idx] = leaf; - sectionLoaded(leaf, dx, dz); } } return surfaceTrackerLeaves; @@ -539,6 +530,10 @@ public int getHighestLight(int x, int z) { int zSection = blockToCubeLocalSection(z); int idx = xSection + zSection * DIAMETER_IN_SECTIONS; + + if (this.lightHeightmaps[idx] == null) + System.out.println("!"); + SurfaceTrackerLeaf sectionAbove = this.lightHeightmaps[idx].getSectionAbove(); int dy = CubeAccess.DIAMETER_IN_BLOCKS - 1; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/HeightmapNode.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/HeightmapNode.java index e14753eca..8e6282cc2 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/HeightmapNode.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/HeightmapNode.java @@ -6,10 +6,6 @@ public interface HeightmapNode { - default void sectionLoaded(@Nonnull SurfaceTrackerLeaf surfaceTrackerLeaf, int localSectionX, int localSectionZ) { - throw new IllegalStateException("Should not be reached"); - } - void unloadNode(@Nonnull HeightmapStorage storage); int getHighest(int x, int z, byte heightmapType); diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java index b282060db..02c12b989 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerBranch.java @@ -43,7 +43,7 @@ protected int updateHeight(int x, int z, int idx) { } } - public SurfaceTrackerLeaf loadCube(int localSectionX, int localSectionZ, HeightmapStorage storage, HeightmapNode newNode, @Nullable SurfaceTrackerLeaf protoLeaf) { + public SurfaceTrackerLeaf loadCube(HeightmapStorage storage, HeightmapNode newNode, @Nullable SurfaceTrackerLeaf protoLeaf) { int newScale = scale - 1; // Attempt to load all children from storage @@ -60,16 +60,24 @@ public SurfaceTrackerLeaf loadCube(int localSectionX, int localSectionZ, Heightm // child is a leaf if (newScale == 0) { - assert children[idx] == null : "Duplicate leaf!"; + assert protoLeaf == null || children[idx] == null : "!"; SurfaceTrackerLeaf newLeaf; - if (protoLeaf == null) { - newLeaf = new SurfaceTrackerLeaf(newNode, this, this.heightmapType); - } else { + + // converting an existing node + if (children[idx] != null) { + newLeaf = new SurfaceTrackerLeaf(newNode, this, (SurfaceTrackerLeaf) children[idx]); + } + // attaching an external leaf + else if (protoLeaf != null) { newLeaf = new SurfaceTrackerLeaf(newNode, this, protoLeaf); } + // creating a new leaf + else { + newLeaf = new SurfaceTrackerLeaf(newNode, this, this.heightmapType); + } + children[idx] = newLeaf; - newNode.sectionLoaded(newLeaf, localSectionX, localSectionZ); newLeaf.markAncestorsDirty(); onChildLoaded(); @@ -80,11 +88,12 @@ public SurfaceTrackerLeaf loadCube(int localSectionX, int localSectionZ, Heightm // child is a branch else { + // lazily create new branches if (children[idx] == null) { children[idx] = new SurfaceTrackerBranch(newScale, newScaledY, this, this.heightmapType); } - return ((SurfaceTrackerBranch) children[idx]).loadCube(localSectionX, localSectionZ, storage, newNode, protoLeaf); + return ((SurfaceTrackerBranch) children[idx]).loadCube(storage, newNode, protoLeaf); } } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java index e3b8d8de6..1c62a3e3a 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerNode.java @@ -56,14 +56,6 @@ protected SurfaceTrackerNode(int scale, int scaledY, @Nullable SurfaceTrackerBra } - private BitStorage getRawHeights() { - return heights; - } - - private long[] getDirtyPositions() { - return dirtyPositions; - } - /** * Get the height for a given position. Recomputes the height if the column is marked dirty in this section. * x and z are GLOBAL coordinates (cube local is also fine, but section/chunk local is WRONG). diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java index ab857c93d..bdf30f735 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/level/levelgen/heightmap/surfacetrackertree/SurfaceTrackerWrapper.java @@ -77,7 +77,7 @@ public long[] getRawData() { } public synchronized SurfaceTrackerLeaf loadCube(HeightmapStorage storage, HeightmapNode node, @Nullable SurfaceTrackerLeaf protoLeaf) { - return this.surfaceTracker.loadCube(blockToCubeLocalSection(dx), blockToCubeLocalSection(dz), storage, node, protoLeaf); + return this.surfaceTracker.loadCube(storage, node, protoLeaf); } @Nullable diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java index e78256eba..c4d045315 100644 --- a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerBranchTest.java @@ -37,7 +37,7 @@ public void testValidScaleBounds() { public void testLeafInsertionIntoRoot() { NullHeightmapStorage storage = new NullHeightmapStorage(); SurfaceTrackerBranch root = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); - root.loadCube(0, 0, storage, new TestHeightmapNode(0), null); + root.loadCube(storage, new TestHeightmapNode(0), null); SurfaceTrackerLeaf leaf = root.getMinScaleNode(0); assertNotNull(leaf, "Appropriate leaf was null after loading node into root"); diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java index d107b0f1e..ce8e4f4cd 100644 --- a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerLeafTest.java @@ -49,7 +49,7 @@ public void testLeafUnload() { //Set up leaf and node with parent SurfaceTrackerBranch parent = new SurfaceTrackerBranch(SurfaceTrackerNode.MAX_SCALE, 0, null, (byte) 0); - parent.loadCube(0, 0, storage, new TestHeightmapNode(0), null); + parent.loadCube(storage, new TestHeightmapNode(0), null); SurfaceTrackerLeaf leaf = parent.getMinScaleNode(0); //Unload the node diff --git a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java index 49a496f7b..5f8984ca1 100644 --- a/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java +++ b/src/test/java/io/github/opencubicchunks/cubicchunks/levelgen/heightmap/SurfaceTrackerNodesTest.java @@ -58,7 +58,7 @@ public void sanityTest() { for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node0, null); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(storage, node0, null); } } @@ -102,7 +102,7 @@ public void testNoValidHeights() { for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node0, null); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(storage, node0, null); } } @@ -150,7 +150,7 @@ public void seededRandom() { TestHeightmapNode node = new TestHeightmapNode(y); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node,null); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(storage, node,null); } } return node; @@ -188,7 +188,7 @@ public void simpleUnloadTree1() { TestHeightmapNode node = new TestHeightmapNode(yPos); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node, null); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(storage, node, null); } } return node; @@ -226,7 +226,7 @@ public void simpleUnloadTree2() { TestHeightmapNode node = new TestHeightmapNode(yPos); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node, null); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(storage, node, null); } } return node; @@ -280,7 +280,7 @@ public void seededRandomUnloadTree() { TestHeightmapNode node = new TestHeightmapNode(yPos); for (int localSectionX = 0; localSectionX < CubeAccess.DIAMETER_IN_SECTIONS; localSectionX++) { for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) { - roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(localSectionX, localSectionZ, storage, node, null); + roots[localSectionX + CubeAccess.DIAMETER_IN_SECTIONS * localSectionZ].loadCube(storage, node, null); } } return node; @@ -329,7 +329,7 @@ public void testUnloadReload() { Function loadNode = y -> nodes.computeIfAbsent(y, yPos -> { TestHeightmapNode node = new TestHeightmapNode(yPos); - root.loadCube(0, 0, storage, node,null); + root.loadCube(storage, node,null); return node; }); Function unloadNode = y -> { @@ -349,7 +349,7 @@ public void testUnloadReload() { unloadNode.apply(0); - root.loadCube(0, 0, storage, cubeNode, null); + root.loadCube(storage, cubeNode, null); SurfaceTrackerLeaf reloadedNode = root.getMinScaleNode(0); @@ -488,10 +488,6 @@ void setBlock(int x, int localY, int z, boolean isOpaque) { section.onSetBlock(x, (this.y << SurfaceTrackerNode.SCALE_0_NODE_BITS) + localY, z, heightmapType -> isOpaque); } - @Override public void sectionLoaded(@Nonnull SurfaceTrackerLeaf leaf, int localSectionX, int localSectionZ) { - this.sections[localSectionX + localSectionZ * CubeAccess.DIAMETER_IN_SECTIONS] = leaf; - } - @Override public void unloadNode(@Nonnull HeightmapStorage storage) { SurfaceTrackerLeaf[] nodes = this.sections; for (int localSectionZ = 0; localSectionZ < CubeAccess.DIAMETER_IN_SECTIONS; localSectionZ++) {