History capture fast paths

- Natural terrain capture scans columns as block state runs
- Biome samples reuse the palette index of an identical key
- Cave biome capture samples the subterrain planner directly when live
- Repeated object markers skip decoding
- Saved biome encoding hashes each distinct column once
This commit is contained in:
Brian Neumann-Fopiano committed 2026-10-22 11:05:58 -04:00
1 parent d9c5d00be3
commit f7f9f5f651
7 files changed
+395 -43

No files matched your search

@@ -120,13 +120,40 @@ public final class IrisTransitionGeometryActuator extends EngineAssignedComponen
@Override
public BoundaryColumnGeometry.Voxel voxel(int localX, int worldY, int localZ) {
NativeBlockState state = blocks.getRaw(localX, worldY - minimumY, localZ);
if (state == null) {
if (air == null) {
air = IrisPlatforms.get().registries().air();
}
state = air;
return voxelOf(stateAt(localX, worldY - minimumY, localZ));
}
@Override
public void scanColumn(int localX, int localZ, int minimumY, int height, SavedTerrainChunk.VoxelRuns runs) {
if (height <= 0) {
return;
}
int base = minimumY - this.minimumY;
NativeBlockState runState = stateAt(localX, base, localZ);
int start = 0;
for (int offset = 1; offset < height; offset++) {
NativeBlockState state = stateAt(localX, base + offset, localZ);
if (state != runState) {
runs.add(start, offset, voxelOf(runState));
start = offset;
runState = state;
}
}
runs.add(start, height, voxelOf(runState));
}
private NativeBlockState stateAt(int localX, int offset, int localZ) {
NativeBlockState state = blocks.getRaw(localX, offset, localZ);
if (state != null) {
return state;
}
if (air == null) {
air = IrisPlatforms.get().registries().air();
}
return air;
}
private BoundaryColumnGeometry.Voxel voxelOf(NativeBlockState state) {
if (state != lastState) {
lastVoxel = voxels.computeIfAbsent(state, GeometrySource::encode);
lastState = state;
@@ -257,11 +257,16 @@ public final class BoundaryColumnGeometry implements NativeBlockColumn {
}
void add(Voxel voxel) {
add(voxel, 1);
}
void add(Voxel voxel, int run) {
Objects.requireNonNull(voxel, "Geometry voxel");
if (count == 0 || !sameVoxel(voxels[count - 1], voxel)) {
voxels[count++] = voxel;
}
ends[count - 1] = ++length;
length += run;
ends[count - 1] = length;
}
BoundaryColumnGeometry build(int minimumY) {
@@ -16,6 +16,9 @@ import art.arcane.iris.generation.hydrology.HydrologyColumnSample;
import art.arcane.iris.generation.hydrology.cave.HydrologyCaveCell;
import art.arcane.iris.generation.biome.IrisBiome;
import art.arcane.iris.generation.terrain.IrisRegion;
import art.arcane.iris.generation.terrain.IrisDimension;
import art.arcane.iris.generation.subterrain.SubterrainCell;
import art.arcane.iris.generation.subterrain.SubterrainPlanner;
import art.arcane.iris.generation.terrain.IrisDimensionCarvingResolver;
import art.arcane.iris.structure.placement.IrisStructurePlacement;
import art.arcane.volmlib.util.mantle.flag.ReservedFlag;
@@ -170,13 +173,14 @@ public final class GenerationSemanticCapture {
cavern == null ? null : cavern.getCustomBiome()
);
});
IrisComplex complex = engine.getComplex();
mantle.iterateChunk(chunkX, chunkZ, HydrologyCaveCell.class, (localX, y, localZ, cell) -> {
if (!caveSpace.test(localX, y, localZ)) {
return;
}
int blockX = minimumX + localX;
int blockZ = minimumZ + localZ;
if (!hasFullHydrologyWeight(engine.getComplex(), blockX, blockZ)) {
if (!hasFullHydrologyWeight(complex, blockX, blockZ)) {
return;
}
captureCave(
@@ -199,12 +203,8 @@ public final class GenerationSemanticCapture {
Math.addExact(minimumZ, localZ))));
}
});
mantle.iterateChunk(chunkX, chunkZ, String.class, (localX, y, localZ, marker) -> {
StructurePlacementMarker.Decoded decoded = StructurePlacementMarker.decode(marker);
if (decoded != null) {
semantics.addObject(decoded.objectKey());
}
});
ObjectMarkers objects = new ObjectMarkers(semantics);
mantle.iterateChunk(chunkX, chunkZ, String.class, (localX, y, localZ, marker) -> objects.add(marker));
}
private static boolean hasFullHydrologyWeight(IrisComplex complex, int blockX, int blockZ) {
@@ -273,10 +273,76 @@ public final class GenerationSemanticCapture {
}
}
private static final class ObjectMarkers {
private final ChunkGenerationSemantics.Builder semantics;
private String lastMarker;
private ObjectMarkers(ChunkGenerationSemantics.Builder semantics) {
this.semantics = semantics;
}
private void add(String marker) {
if (marker != null && marker.equals(lastMarker)) {
return;
}
StructurePlacementMarker.Decoded decoded = StructurePlacementMarker.decode(marker);
if (decoded != null) {
semantics.addObject(decoded.objectKey());
}
lastMarker = marker;
}
}
private static final class SubterrainBiomes {
private final Engine engine;
private final boolean live;
private final SubterrainPlanner planner;
private final int minimumY;
private SubterrainBiomes(Engine engine, boolean live, SubterrainPlanner planner, int minimumY) {
this.engine = engine;
this.live = live;
this.planner = planner;
this.minimumY = minimumY;
}
private static SubterrainBiomes of(Engine engine, int minimumY) {
if (engine.getClass() != IrisEngine.class) {
return new SubterrainBiomes(engine, false, null, 0);
}
IrisEngine irisEngine = (IrisEngine) engine;
if (!irisEngine.hasGenerationRuntimeScope() && irisEngine.getGenerationHistoryRuntimeRouter().isPresent()) {
return new SubterrainBiomes(engine, false, null, 0);
}
IrisComplex complex = engine.getComplex();
IrisDimension dimension = engine.getDimension();
SubterrainPlanner planner = complex == null || dimension == null || !dimension.allowsSubterrainFeatures()
|| dimension.getSubterrainFeatures() == null || dimension.getSubterrainFeatures().isEmpty()
? null
: complex.getSubterrainPlanner();
return new SubterrainBiomes(engine, true, planner, minimumY);
}
private IrisBiome resolve(int x, int y, int z) {
if (!live) {
return engine.getSubterrainBiome(x, y, z);
}
if (planner == null) {
return null;
}
SubterrainCell cell = planner.sample(x, y + minimumY, z);
if (!cell.occupied() || cell.room().biome().isEmpty()) {
return null;
}
return engine.getSubterrainBiome(x, y, z);
}
}
private static final class CaveBiomes {
private final Engine engine;
private final boolean scoped;
private final CaveFallback fallback;
private SubterrainBiomes subterrain;
private final IrisDimensionCarvingResolver.State fallbackState = new IrisDimensionCarvingResolver.State();
private IrisDimensionCarvingResolver.Snapshot snapshot;
private int minimumY;
@@ -305,8 +371,9 @@ public final class GenerationSemanticCapture {
if (snapshot == null) {
snapshot = IrisDimensionCarvingResolver.snapshot(engine);
minimumY = engine.getWorld().minHeight();
subterrain = SubterrainBiomes.of(engine, minimumY);
}
IrisBiome featureBiome = engine.getSubterrainBiome(x, y, z);
IrisBiome featureBiome = subterrain.resolve(x, y, z);
if (featureBiome != null) {
return featureBiome;
}
@@ -622,10 +622,16 @@ public final class SavedBiomeStore {
private static byte[] encode(SavedBiomeChunk chunk) throws IOException {
LinkedHashMap<SavedBiomeChunk.Cell, Integer> palette = new LinkedHashMap<>();
LinkedHashMap<SavedBiomeChunk.Column, Integer> columns = new LinkedHashMap<>();
byte[] columnIndices = new byte[256];
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
SavedBiomeChunk.Column column = chunk.column(x, z);
columns.computeIfAbsent(column, ignored -> columns.size());
int known = columns.size();
int index = columns.computeIfAbsent(column, ignored -> columns.size());
columnIndices[z * 16 + x] = (byte) index;
if (index < known) {
continue;
}
palette.computeIfAbsent(column.surface(), ignored -> palette.size());
palette.computeIfAbsent(column.caveBase(), ignored -> palette.size());
for (SavedBiomeChunk.Span span : column.vertical()) {
@@ -660,11 +666,7 @@ public final class SavedBiomeStore {
writeUnsigned(output, palette.get(span.cell()));
}
}
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
output.writeByte(columns.get(chunk.column(x, z)));
}
}
output.write(columnIndices);
}
if (raw.size() > MAXIMUM_DECODED_BYTES) {
throw new IOException("Saved biome chunk exceeds its decoded size limit");
@@ -63,38 +63,32 @@ public final class SavedTerrainChunk {
}
Math.addExact(minimumY, height);
List<TerrainBoundarySignature> columns = new ArrayList<>(256);
BoundaryColumnGeometry.Runs runs = new BoundaryColumnGeometry.Runs(height);
ColumnScan scan = new ColumnScan(height);
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
if (boundaryOnly && x != 0 && x != 15 && z != 0 && z != 15) {
columns.add(null);
continue;
}
runs.clear();
scan.reset();
source.scanColumn(x, z, minimumY, height, scan);
scan.requireCovered();
List<String> biomePalette = new ArrayList<>(4);
short[] biomeIndices = new short[height / 4];
int surface = 0;
int floor = 0;
int fluid = -1;
for (int offset = 0; offset < height; offset++) {
int y = minimumY + offset;
BoundaryColumnGeometry.Voxel voxel = Objects.requireNonNull(source.voxel(x, y, z), "voxel");
runs.add(voxel);
if (voxel.phase() != BoundaryColumnGeometry.Phase.AIR) {
surface = offset;
}
if (voxel.phase() == BoundaryColumnGeometry.Phase.SOLID) {
floor = offset;
}
if (!voxel.fluidStateKey().isEmpty()) {
fluid = offset;
}
if (offset % 4 == 0) {
String biome = Objects.requireNonNull(source.biome(x, y, z), "physical biome");
biomeIndices[offset / 4] = paletteIndex(biomePalette, biome);
String lastBiome = null;
short lastIndex = 0;
for (int offset = 0; offset < height; offset += 4) {
String biome = Objects.requireNonNull(source.biome(x, minimumY + offset, z), "physical biome");
if (biome != lastBiome) {
lastIndex = paletteIndex(biomePalette, biome);
lastBiome = biome;
}
biomeIndices[offset / 4] = lastIndex;
}
BoundaryColumnGeometry geometry = runs.build(minimumY);
int surface = scan.surface;
int floor = scan.floor;
int fluid = scan.fluid;
BoundaryColumnGeometry geometry = scan.runs.build(minimumY);
OptionalInt groundSurface = source.groundSurface(x, z);
if (groundSurface.isPresent()) {
floor = geometry.surfaceOffsetNear(groundSurface.getAsInt());
@@ -209,5 +203,64 @@ public final class SavedTerrainChunk {
BoundaryColumnGeometry.Voxel voxel(int localX, int worldY, int localZ) throws IOException;
String biome(int localX, int worldY, int localZ) throws IOException;
default void scanColumn(int localX, int localZ, int minimumY, int height, VoxelRuns runs) throws IOException {
for (int offset = 0; offset < height; offset++) {
runs.add(offset, offset + 1, voxel(localX, minimumY + offset, localZ));
}
}
}
@FunctionalInterface
public interface VoxelRuns {
void add(int startOffset, int endOffset, BoundaryColumnGeometry.Voxel voxel);
}
private static final class ColumnScan implements VoxelRuns {
private final BoundaryColumnGeometry.Runs runs;
private final int height;
private int covered;
private int surface;
private int floor;
private int fluid;
private ColumnScan(int height) {
this.runs = new BoundaryColumnGeometry.Runs(height);
this.height = height;
}
private void reset() {
runs.clear();
covered = 0;
surface = 0;
floor = 0;
fluid = -1;
}
@Override
public void add(int startOffset, int endOffset, BoundaryColumnGeometry.Voxel voxel) {
Objects.requireNonNull(voxel, "voxel");
if (startOffset != covered || endOffset <= startOffset || endOffset > height) {
throw new IllegalArgumentException("Voxel runs must cover the column in order");
}
runs.add(voxel, endOffset - startOffset);
covered = endOffset;
int last = endOffset - 1;
if (voxel.phase() != BoundaryColumnGeometry.Phase.AIR) {
surface = last;
}
if (voxel.phase() == BoundaryColumnGeometry.Phase.SOLID) {
floor = last;
}
if (!voxel.fluidStateKey().isEmpty()) {
fluid = last;
}
}
private void requireCovered() {
if (covered != height) {
throw new IllegalStateException("Voxel runs must cover the whole column");
}
}
}
}