Optimize world generation

- Limit terrain cleanup to affected columns and batch cave boundary reads.
- Reuse offline generation workers and native air states.
- Gather history writes and defer unpublished append synchronization until atomic publication.
- Cover terrain parity, worker lifecycle, history durability, and publication failures.
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-23 21:32:17 -04:00
1 parent 7986698c1c
commit 38cf4ac7c7
25 files changed
+1362 -226

No files matched your search

@@ -4,6 +4,8 @@ import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
import art.arcane.iris.generation.hydrology.cave.HydrologyCaveCell;
import art.arcane.iris.world.storage.matter.PreObjectMatterCell;
import art.arcane.volmlib.util.function.Consumer4;
import art.arcane.volmlib.util.hunk.bits.DataContainer;
import art.arcane.volmlib.util.hunk.storage.PaletteOrHunk;
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
import art.arcane.volmlib.util.matter.Matter;
@@ -11,6 +13,7 @@ import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.volmlib.util.matter.MatterSlice;
import java.util.Objects;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
@@ -67,6 +70,82 @@ public final class TerrainMatterView {
}
}
public static MatterCavern[] getComposedFace(MantleChunk<Matter> chunk, Face face, int height) {
Objects.requireNonNull(face, "Terrain face");
if (height < 0) {
throw new IllegalArgumentException("Terrain face height must be nonnegative");
}
MatterCavern[] result = new MatterCavern[Math.multiplyExact(height, 16)];
if (chunk == null || height == 0) {
return result;
}
PreObjectMatterCell[] journal = new PreObjectMatterCell[256];
HydrologyCaveCell[] hydrology = new HydrologyCaveCell[256];
MatterCavern[] caverns = new MatterCavern[256];
synchronized (chunk) {
for (int baseY = 0; baseY < height; baseY += 16) {
int section = baseY >> 4;
if (!chunk.exists(section)) {
continue;
}
Matter matter = chunk.get(section);
if (matter == null) {
continue;
}
copyFace(matter.getSlice(PreObjectMatterCell.class), face, journal);
copyFace(matter.getSlice(HydrologyCaveCell.class), face, hydrology);
copyFace(matter.getSlice(MatterCavern.class), face, caverns);
int count = Math.min(16, height - baseY) * 16;
for (int index = 0; index < count; index++) {
PreObjectMatterCell cell = journal[index];
HydrologyCaveCell effectiveHydrology = cell != null && cell.hydrologyCaptured()
? cell.hydrology() : hydrology[index];
result[baseY * 16 + index] = effectiveHydrology != null
? effectiveHydrology.asCavern()
: cell != null && cell.cavernCaptured() ? cell.cavern() : caverns[index];
}
}
}
return result;
}
@SuppressWarnings("unchecked")
private static <T> void copyFace(MatterSlice<T> slice, Face face, T[] destination) {
if (slice == null) {
Arrays.fill(destination, null);
return;
}
if (slice instanceof PaletteOrHunk<?> storage && storage.isPalette()
&& slice.getWidth() == 16 && slice.getHeight() == 16 && slice.getDepth() == 16) {
DataContainer<T> palette = (DataContainer<T>) storage.palette();
palette.copyTo(face.positions, destination);
return;
}
for (int index = 0; index < destination.length; index++) {
int position = face.positions[index];
destination[index] = slice.get(position & 15, (position >> 4) & 15, position >> 8);
}
}
public enum Face {
WEST(true, 0),
EAST(true, 15),
NORTH(false, 0),
SOUTH(false, 15);
private final int[] positions = new int[256];
Face(boolean fixedX, int coordinate) {
for (int y = 0; y < 16; y++) {
for (int offset = 0; offset < 16; offset++) {
int x = fixedX ? coordinate : offset;
int z = fixedX ? offset : coordinate;
positions[y * 16 + offset] = (z << 8) | (y << 4) | x;
}
}
}
}
public static <T> void iterate(MantleChunk<Matter> chunk, Class<T> type,
Consumer4<Integer, Integer, Integer, T> consumer) {
Objects.requireNonNull(chunk, "Terrain mantle chunk");
@@ -532,44 +532,46 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
return;
}
int height = maxY + 1;
MatterCavern[] ownWest = west == null ? null : TerrainMatterView.getComposedFace(mc, TerrainMatterView.Face.WEST, height);
MatterCavern[] ownEast = east == null ? null : TerrainMatterView.getComposedFace(mc, TerrainMatterView.Face.EAST, height);
MatterCavern[] ownNorth = north == null ? null : TerrainMatterView.getComposedFace(mc, TerrainMatterView.Face.NORTH, height);
MatterCavern[] ownSouth = south == null ? null : TerrainMatterView.getComposedFace(mc, TerrainMatterView.Face.SOUTH, height);
MatterCavern[] fromWest = west == null ? null : TerrainMatterView.getComposedFace(west, TerrainMatterView.Face.EAST, height);
MatterCavern[] fromEast = east == null ? null : TerrainMatterView.getComposedFace(east, TerrainMatterView.Face.WEST, height);
MatterCavern[] fromNorth = north == null ? null : TerrainMatterView.getComposedFace(north, TerrainMatterView.Face.SOUTH, height);
MatterCavern[] fromSouth = south == null ? null : TerrainMatterView.getComposedFace(south, TerrainMatterView.Face.NORTH, height);
for (int yy = 1; yy <= maxY; yy++) {
for (int offset = 0; offset < 16; offset++) {
int index = yy * 16 + offset;
if (west != null) {
tryAddBoundaryWall(mc, west, walls, boundaryMasks, 0, yy, offset, 15, offset);
tryAddBoundaryWall(ownWest[index], fromWest[index], walls, boundaryMasks, 0, yy, offset);
}
if (east != null) {
tryAddBoundaryWall(mc, east, walls, boundaryMasks, 15, yy, offset, 0, offset);
tryAddBoundaryWall(ownEast[index], fromEast[index], walls, boundaryMasks, 15, yy, offset);
}
if (north != null) {
tryAddBoundaryWall(mc, north, walls, boundaryMasks, offset, yy, 0, offset, 15);
tryAddBoundaryWall(ownNorth[index], fromNorth[index], walls, boundaryMasks, offset, yy, 0);
}
if (south != null) {
tryAddBoundaryWall(mc, south, walls, boundaryMasks, offset, yy, 15, offset, 0);
tryAddBoundaryWall(ownSouth[index], fromSouth[index], walls, boundaryMasks, offset, yy, 15);
}
}
}
}
private void tryAddBoundaryWall(
MantleChunk<Matter> mc,
MantleChunk<Matter> neighborChunk,
MatterCavern current,
MatterCavern neighbor,
CarveWallBuffer walls,
CarveColumnMask[] boundaryMasks,
int localX,
int yy,
int localZ,
int neighborX,
int neighborZ
int localZ
) {
if (composedCavernAt(mc, localX, yy, localZ) != null) {
if (current != null || neighbor == null) {
return;
}
MatterCavern neighbor = composedCavernAt(neighborChunk, neighborX, yy, neighborZ);
if (neighbor == null) {
return;
}
walls.put(localX, yy, localZ, neighbor);
int columnIndex = PowerOfTwoCoordinates.packLocal16(localX, localZ);
boundaryMasks[columnIndex].add(yy);
@@ -30,11 +30,9 @@ import art.arcane.iris.generation.concurrent.BurstExecutor;
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import it.unimi.dsi.fastutil.ints.IntArrayList;
public class IrisPerfectionModifier extends EngineAssignedModifier<NativeBlockState> {
private static final BoundBlockState AIR = BoundBlockState.of("AIR");
@@ -86,84 +84,67 @@ public class IrisPerfectionModifier extends EngineAssignedModifier<NativeBlockSt
if (getDimension().isHideOresForHiddenOre()) {
hideOres(output, multicore);
}
AtomicBoolean changed = new AtomicBoolean(true);
BurstExecutor burst = burst().burst(multicore);
while (changed.get()) {
changed.set(false);
for (int i = 0; i < 16; i++) {
int finalI = i;
burst.queue(() -> {
List<Integer> surfaces = new ArrayList<>();
List<Integer> ceilings = new ArrayList<>();
for (int j = 0; j < 16; j++) {
surfaces.clear();
ceilings.clear();
int top = getHeight(output, finalI, j);
boolean inside = true;
surfaces.add(top);
for (int k = top; k >= 0; k--) {
NativeBlockState b = output.get(finalI, k, j);
if (IrisSpeleothems.isSpike(b)) {
b = normalizeSpike(b, output, finalI, j, k, AIR.get(), WATER.get());
}
boolean now = b != null && !(B.isAir(b) || B.isFluid(b));
if (now != inside) {
inside = now;
if (inside) {
surfaces.add(k);
} else {
ceilings.add(k + 1);
}
}
}
for (int k : surfaces) {
NativeBlockState tip = output.get(finalI, k, j);
if (tip == null) {
continue;
}
boolean remove = false;
boolean remove2 = false;
if (B.isDecorant(tip)) {
NativeBlockState bel = output.get(finalI, k - 1, j);
if (bel == null) {
remove = true;
} else if (!B.canPlaceOnto(tip, bel)) {
remove = true;
} else if (IrisProceduralBlocks.hasProperty(bel, "half")) {
NativeBlockState bb = output.get(finalI, k - 2, j);
if (bb == null || !B.canPlaceOnto(bel, bb)) {
remove = true;
remove2 = true;
}
}
if (remove) {
changed.set(true);
output.set(finalI, k, j, AIR.get());
if (remove2) {
output.set(finalI, k - 1, j, AIR.get());
}
}
}
}
}
});
}
burst.complete();
for (int index = 0; index < 16; index++) {
int columnX = index;
burst.queue(() -> perfectSlice(output, columnX));
}
burst.complete();
getEngine().getMetrics().getPerfection().put(p.getMilliseconds());
}
private void perfectSlice(Hunk<NativeBlockState> output, int x) {
IntArrayList surfaces = new IntArrayList();
for (int z = 0; z < 16; z++) {
boolean changed;
do {
surfaces.clear();
int top = getHeight(output, x, z);
boolean inside = true;
surfaces.add(top);
for (int y = top; y >= 0; y--) {
NativeBlockState block = output.get(x, y, z);
if (IrisSpeleothems.isSpike(block)) {
block = normalizeSpike(block, output, x, z, y, AIR.get(), WATER.get());
}
boolean now = block != null && !(B.isAir(block) || B.isFluid(block));
if (now != inside) {
inside = now;
if (inside) {
surfaces.add(y);
}
}
}
changed = false;
for (int index = 0; index < surfaces.size(); index++) {
int y = surfaces.getInt(index);
NativeBlockState tip = output.get(x, y, z);
if (!B.isDecorant(tip)) {
continue;
}
NativeBlockState below = output.get(x, y - 1, z);
boolean remove = below == null || !B.canPlaceOnto(tip, below);
boolean removeBelow = false;
if (!remove && IrisProceduralBlocks.hasProperty(below, "half")) {
NativeBlockState support = output.get(x, y - 2, z);
if (support == null || !B.canPlaceOnto(below, support)) {
remove = true;
removeBelow = true;
}
}
if (remove) {
changed = true;
output.set(x, y, z, AIR.get());
if (removeBelow) {
output.set(x, y - 1, z, AIR.get());
}
}
}
} while (changed);
}
}
static NativeBlockState normalizeSpike(NativeBlockState state, Hunk<NativeBlockState> output,
int x, int z, int y, NativeBlockState air, NativeBlockState water) {
if (IrisSpeleothems.isSupported(state, output, x, z, y)) {
@@ -53,7 +53,8 @@ public final class GenerationHistory {
GenerationHistoryStore store,
ChunkGenerationOwnership ownership,
GenerationKernelRegistry kernels,
Optional<FreshPublication> publication
Optional<FreshPublication> publication,
boolean unpublished
) throws IOException {
this.paths = Objects.requireNonNull(paths, "paths");
this.packs = Objects.requireNonNull(packs, "packs");
@@ -62,8 +63,8 @@ public final class GenerationHistory {
this.kernels = Objects.requireNonNull(kernels, "kernels");
this.boundaries = new GenerationBoundaryStore(paths.dimensionRoot());
this.terrainSignatures = new TerrainBoundarySignatureStore(paths.dimensionRoot());
this.semantics = GenerationSemanticIndex.loadRequired(paths.dimensionRoot());
this.savedBiomes = SavedBiomeStore.open(paths.dimensionRoot());
this.semantics = GenerationSemanticIndex.loadRequired(paths.dimensionRoot(), unpublished);
this.savedBiomes = SavedBiomeStore.open(paths.dimensionRoot(), unpublished);
this.admission = new GenerationAdmission(paths.dimensionRoot());
this.boundaryCache = boundedCache(MAXIMUM_CACHED_BOUNDARIES);
this.terrainSignatureCache = boundedCache(MAXIMUM_CACHED_TERRAIN_SIGNATURES);
@@ -108,6 +109,25 @@ public final class GenerationHistory {
GenerationKernelRegistry.Version version,
GenerationKernelRegistry kernels
) throws IOException {
return create(new FreshCreation(dimensionRoot, packSource, packFingerprint, worldSeed, dimensionContract, registryContract),
version, kernels, false);
}
public static GenerationHistory createUnpublished(FreshCreation creation) throws IOException {
Objects.requireNonNull(creation, "creation");
Files.createDirectory(creation.dimensionRoot());
GenerationKernelRegistry kernels = GenerationKernelRegistry.standard();
return create(creation, kernels.current(), kernels, true);
}
private static GenerationHistory create(FreshCreation creation, GenerationKernelRegistry.Version version,
GenerationKernelRegistry kernels, boolean unpublished) throws IOException {
Path dimensionRoot = creation.dimensionRoot();
Path packSource = creation.packSource();
String packFingerprint = creation.packFingerprint();
long worldSeed = creation.worldSeed();
GenerationEpoch.DimensionContract dimensionContract = creation.dimensionContract();
GenerationRegistryContract registryContract = creation.registryContract();
GenerationHistoryPaths paths = GenerationHistoryPaths.forDimension(dimensionRoot);
requireSafeStatePaths(paths);
if (Files.exists(paths.manifest(), LinkOption.NOFOLLOW_LINKS)
@@ -141,7 +161,7 @@ public final class GenerationHistory {
GenerationSemanticIndex.initialize(paths.dimensionRoot());
GenerationHistoryStore store = GenerationHistoryStore.initialize(paths.generationRoot(), epoch);
return new GenerationHistory(paths, packs, store, ownership, kernels,
Optional.of(new FreshPublication(publishedPack, epoch)));
Optional.of(new FreshPublication(publishedPack, epoch)), unpublished);
}
public static GenerationHistory open(Path dimensionRoot) throws IOException {
@@ -183,7 +203,7 @@ public final class GenerationHistory {
GenerationPackRepository packs = new GenerationPackRepository(paths.dimensionRoot());
GenerationHistoryStore store = GenerationHistoryStore.open(paths.generationRoot());
ChunkGenerationOwnership ownership = ChunkGenerationOwnership.load(paths.ownershipRoot());
return new GenerationHistory(paths, packs, store, ownership, kernels, Optional.empty());
return new GenerationHistory(paths, packs, store, ownership, kernels, Optional.empty(), false);
}
public static Optional<GenerationHistory> openIfPresent(Path dimensionRoot) throws IOException {
@@ -1344,4 +1364,15 @@ public final class GenerationHistory {
public interface BoundarySignatureCapture {
TerrainBoundarySignatureStore.SignatureSampler capture(GenerationBoundary boundary) throws IOException;
}
public record FreshCreation(Path dimensionRoot, Path packSource, String packFingerprint, long worldSeed,
GenerationEpoch.DimensionContract dimensionContract, GenerationRegistryContract registryContract) {
public FreshCreation {
Objects.requireNonNull(dimensionRoot, "dimensionRoot");
Objects.requireNonNull(packSource, "packSource");
Objects.requireNonNull(packFingerprint, "packFingerprint");
Objects.requireNonNull(dimensionContract, "dimensionContract");
Objects.requireNonNull(registryContract, "registryContract");
}
}
}
@@ -92,6 +92,7 @@ public final class GenerationSemanticIndex {
private final ShardPublisher publisher;
private final PointerPublisher pointerPublisher;
private final CatalogPublisher catalogPublisher;
private final boolean unpublished;
private long regionDecodeCount;
private volatile IOException journalFailure;
private long appendingRegionKey;
@@ -101,7 +102,8 @@ public final class GenerationSemanticIndex {
Path dimensionRoot,
ShardPublisher publisher,
PointerPublisher pointerPublisher,
CatalogPublisher catalogPublisher
CatalogPublisher catalogPublisher,
boolean unpublished
) {
this.dimensionRoot = dimensionRoot.toAbsolutePath().normalize();
directory = this.dimensionRoot.resolve("iris").resolve("generation").resolve("semantics");
@@ -115,6 +117,7 @@ public final class GenerationSemanticIndex {
this.publisher = publisher;
this.pointerPublisher = pointerPublisher;
this.catalogPublisher = catalogPublisher;
this.unpublished = unpublished;
}
public static GenerationSemanticIndex load(Path dimensionRoot) throws IOException {
@@ -126,7 +129,8 @@ public final class GenerationSemanticIndex {
Objects.requireNonNull(dimensionRoot, "dimensionRoot"),
RegionShard::publish,
ShardPointer::publish,
Catalog::publish
Catalog::publish,
false
);
index.ensureStorageDirectory();
Path catalog = index.directory.resolve(CATALOG_FILE_NAME);
@@ -138,7 +142,13 @@ public final class GenerationSemanticIndex {
}
public static GenerationSemanticIndex loadRequired(Path dimensionRoot) throws IOException {
GenerationSemanticIndex index = load(dimensionRoot);
return loadRequired(dimensionRoot, false);
}
static GenerationSemanticIndex loadRequired(Path dimensionRoot, boolean unpublished) throws IOException {
GenerationSemanticIndex index = new GenerationSemanticIndex(Objects.requireNonNull(dimensionRoot, "dimensionRoot"),
RegionShard::publish, ShardPointer::publish, Catalog::publish, unpublished);
index.loadShards();
Path catalog = index.directory.resolve(CATALOG_FILE_NAME);
if (!Files.isRegularFile(catalog, LinkOption.NOFOLLOW_LINKS)) {
throw new IOException("Generation semantic shard catalog is missing: " + catalog);
@@ -167,7 +177,8 @@ public final class GenerationSemanticIndex {
Objects.requireNonNull(dimensionRoot, "dimensionRoot"),
Objects.requireNonNull(publisher, "publisher"),
Objects.requireNonNull(pointerPublisher, "pointerPublisher"),
Objects.requireNonNull(catalogPublisher, "catalogPublisher")
Objects.requireNonNull(catalogPublisher, "catalogPublisher"),
false
);
index.loadShards();
return index;
@@ -254,7 +265,7 @@ public final class GenerationSemanticIndex {
appendingBase = baseRegion;
publicationLock.unlock();
try {
SemanticJournal.append(directory, regionX, regionZ, updates);
SemanticJournal.append(directory, regionX, regionZ, updates, unpublished);
} catch (JournalAppendFailure failure) {
journalFailure = failure;
throw failure;
@@ -1928,7 +1939,8 @@ public final class GenerationSemanticIndex {
Path directory,
int regionX,
int regionZ,
List<ChunkGenerationSemantics> claims
List<ChunkGenerationSemantics> claims,
boolean unpublished
) throws IOException {
Path file = directory.resolve(journalFileName(regionX, regionZ));
boolean created = !Files.exists(file, LinkOption.NOFOLLOW_LINKS);
@@ -1961,14 +1973,18 @@ public final class GenerationSemanticIndex {
channel.write(entry);
}
}
Durability.force(channel);
if (!unpublished) {
Durability.force(channel);
}
if (created) {
RegionShard.forceDirectory(directory);
}
} catch (IOException failure) {
try {
channel.truncate(size);
Durability.force(channel);
if (!unpublished) {
Durability.force(channel);
}
if (created) {
RegionShard.forceDirectory(directory);
}
@@ -49,14 +49,16 @@ public final class SavedBiomeStore {
private final Path dimensionRoot;
private final Path directory;
private final boolean unpublished;
private final WriteStripe[] regionLocks = new WriteStripe[64];
private final LinkedHashMap<Long, RegionIndex> regions = new LinkedHashMap<>(64, 0.75F, true);
private final LinkedHashMap<Long, Optional<SavedBiomeChunk>> chunks = new LinkedHashMap<>(128, 0.75F, true);
private long cachedBytes;
private volatile IOException writeFailure;
private SavedBiomeStore(Path dimensionRoot) throws IOException {
private SavedBiomeStore(Path dimensionRoot, boolean unpublished) throws IOException {
this.dimensionRoot = Objects.requireNonNull(dimensionRoot, "dimensionRoot").toAbsolutePath().normalize();
this.unpublished = unpublished;
directory = this.dimensionRoot.resolve("iris/generation/biomes");
requireSafeAncestors();
for (int index = 0; index < regionLocks.length; index++) {
@@ -65,7 +67,11 @@ public final class SavedBiomeStore {
}
public static SavedBiomeStore open(Path dimensionRoot) throws IOException {
return new SavedBiomeStore(dimensionRoot);
return open(dimensionRoot, false);
}
static SavedBiomeStore open(Path dimensionRoot, boolean unpublished) throws IOException {
return new SavedBiomeStore(dimensionRoot, unpublished);
}
public Path storageDirectory() {
@@ -195,11 +201,14 @@ public final class SavedBiomeStore {
RegionIndex region = region(first.chunkX(), first.chunkZ());
ensureRegionFile(region);
long offset = 0L;
boolean durable = false;
boolean appendCompleted = false;
try (RandomAccessFile output = new RandomAccessFile(region.path.toFile(), "rw")) {
offset = output.length();
long length = 0L;
ByteBuffer[] records = new ByteBuffer[claimed.size()];
int recordIndex = 0;
for (PendingWrite pending : claimed.values()) {
records[recordIndex++] = ByteBuffer.wrap(pending.record);
length += pending.record.length;
}
if (offset + length > MAXIMUM_REGION_BYTES) {
@@ -207,15 +216,24 @@ public final class SavedBiomeStore {
}
try {
output.seek(offset);
for (PendingWrite pending : claimed.values()) {
output.write(pending.record);
FileChannel channel = output.getChannel();
int firstBuffer = 0;
while (firstBuffer < records.length) {
channel.write(records, firstBuffer, records.length - firstBuffer);
while (firstBuffer < records.length && !records[firstBuffer].hasRemaining()) {
firstBuffer++;
}
}
output.getChannel().force(true);
durable = true;
if (!unpublished) {
output.getChannel().force(true);
}
appendCompleted = true;
} catch (IOException failure) {
try {
output.setLength(offset);
output.getChannel().force(true);
if (!unpublished) {
output.getChannel().force(true);
}
} catch (IOException rollback) {
failure.addSuppressed(rollback);
writeFailure = failure;
@@ -223,7 +241,7 @@ public final class SavedBiomeStore {
throw failure;
}
} catch (IOException failure) {
if (durable) {
if (appendCompleted) {
writeFailure = failure;
}
throw failure;