Cleared records under native writes

- Added DeferredPlacementRecords to gate tracking on Identifier and TileWrapper slices
- Cleared deferred custom and tile records at positions native structure placement changed
- Implemented block change tracking in the Bukkit and modded structure policies
- Covered invalidation through the custom block materialization pass
- Covered modded wrapper change tracking and protected cells
- Passed disabled change sets in existing wrapper tests
This commit is contained in:
Brian Neumann-Fopiano committed 2026-10-16 19:36:35 -04:00
1 parent a3eccd8a65
commit ff537f4abc
7 files changed
+357 -9

No files matched your search

@@ -0,0 +1,90 @@
package art.arcane.iris.generation.mantle;
import art.arcane.iris.generation.runtime.Engine;
import art.arcane.iris.integration.Identifier;
import art.arcane.iris.world.storage.matter.TileWrapper;
import art.arcane.volmlib.nativelib.terrain.NativeBlockChangeSet;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
import art.arcane.volmlib.util.matter.Matter;
import art.arcane.volmlib.util.matter.MatterSlice;
public final class DeferredPlacementRecords {
private DeferredPlacementRecords() {
}
public static NativeBlockChangeSet track(Engine engine, NativeBlockChangeSet.Bounds bounds) {
Mantle<Matter> mantle = engine.getMantle().getMantle();
for (int chunkX = bounds.minChunkX(); chunkX <= bounds.maxChunkX(); chunkX++) {
for (int chunkZ = bounds.minChunkZ(); chunkZ <= bounds.maxChunkZ(); chunkZ++) {
if (hasRecords(mantle, chunkX, chunkZ)) {
return NativeBlockChangeSet.create(bounds);
}
}
}
return NativeBlockChangeSet.disabled();
}
public static void invalidate(Engine engine, NativeBlockChangeSet changes) {
if (changes.isEmpty()) {
return;
}
Mantle<Matter> mantle = engine.getMantle().getMantle();
int minHeight = engine.getMinHeight();
changes.forEachChunk((chunkX, chunkZ) -> invalidateChunk(mantle, changes, chunkX, chunkZ, minHeight));
}
private static boolean hasRecords(Mantle<Matter> mantle, int chunkX, int chunkZ) {
MantleChunk<Matter> chunk = mantle.useChunk(chunkX, chunkZ);
try {
synchronized (chunk) {
return hasRecords(chunk);
}
} finally {
chunk.release();
}
}
private static boolean hasRecords(MantleChunk<Matter> chunk) {
for (int section = 0; section < chunk.sectionCount(); section++) {
Matter matter = chunk.get(section);
if (matter != null && (matter.hasSlice(Identifier.class) || matter.hasSlice(TileWrapper.class))) {
return true;
}
}
return false;
}
private static void invalidateChunk(Mantle<Matter> mantle, NativeBlockChangeSet changes,
int chunkX, int chunkZ, int minHeight) {
MantleChunk<Matter> chunk = mantle.useChunk(chunkX, chunkZ);
try {
synchronized (chunk) {
if (!hasRecords(chunk)) {
return;
}
changes.forEachPosition(chunkX, chunkZ, (x, y, z) -> clearRecords(chunk, x & 15, y - minHeight, z & 15));
}
} finally {
chunk.release();
}
}
private static void clearRecords(MantleChunk<Matter> chunk, int x, int y, int z) {
if (y < 0 || (y >> 4) >= chunk.sectionCount()) {
return;
}
Matter section = chunk.get(y >> 4);
if (section == null) {
return;
}
clearRecord(section.getSlice(Identifier.class), x, y & 15, z);
clearRecord(section.getSlice(TileWrapper.class), x, y & 15, z);
}
private static void clearRecord(MatterSlice<?> slice, int x, int y, int z) {
if (slice != null) {
slice.set(x, y, z, null);
}
}
}
@@ -4,6 +4,7 @@ import art.arcane.iris.generation.terrain.IrisDimension;
import art.arcane.volmlib.nativelib.terrain.structure.StructureCachePolicy;
import art.arcane.volmlib.nativelib.terrain.structure.StructureStagePolicy;
import art.arcane.iris.generation.runtime.Engine;
import art.arcane.iris.generation.mantle.DeferredPlacementRecords;
import art.arcane.iris.generation.terrain.IrisMaterialPalette;
import art.arcane.iris.structure.nativegen.GenerationWritePolicy;
import art.arcane.iris.structure.nativegen.IrisStructurePolicy;
@@ -13,6 +14,7 @@ import art.arcane.iris.structure.nativegen.NativeStructureStartPlan;
import art.arcane.iris.structure.nativegen.NativeStructureVolumeIndex;
import art.arcane.iris.structure.nativegen.StructureLocateSearch;
import art.arcane.iris.structure.placement.IrisStructureLocator;
import art.arcane.volmlib.nativelib.terrain.NativeBlockChangeSet;
import art.arcane.volmlib.nativelib.terrain.NativeBlockPositionPredicate;
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
import art.arcane.volmlib.nativelib.terrain.structure.StructureLocateSearchAccess;
@@ -103,6 +105,16 @@ public final class BukkitStructureStagePolicy implements StructureStagePolicy<
context.getDimensionStackContext(), context.getMinHeight());
}
@Override
public NativeBlockChangeSet trackBlockChanges(Engine context, NativeBlockChangeSet.Bounds bounds) {
return DeferredPlacementRecords.track(context, bounds);
}
@Override
public void invalidateBlockChanges(Engine context, NativeBlockChangeSet changes) {
DeferredPlacementRecords.invalidate(context, changes);
}
@Override
public IntBinaryOperator surfaceHeight(Engine context) {
return (x, z) -> Engine.hostHeight(context, x, z, true) + context.getMinHeight();