Deferred saved biome updates

- Defers a chunk update pass while saved biome information is loading and retries it on a later pass
- Forgets only the updates already applied so a retry never refills a chest
- Propagates engine failures from loot application instead of marking the chunk done
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-29 06:50:24 -04:00
1 parent 259f885238
commit 5cadd9b8c4
2 files changed
+127 -5

No files matched your search

@@ -30,6 +30,7 @@ import art.arcane.iris.studio.view.PregeneratorJob;
import art.arcane.iris.integration.Identifier;
import art.arcane.iris.generation.cache.Cache;
import art.arcane.iris.generation.runtime.Engine;
import art.arcane.iris.generation.runtime.GenerationFailures;
import art.arcane.iris.generation.block.TileData;
import art.arcane.iris.modded.IrisModdedChunkGenerator;
import art.arcane.iris.modded.ModdedBlockResolution;
@@ -38,6 +39,7 @@ import art.arcane.iris.modded.ModdedTileData;
import art.arcane.iris.modded.api.ModdedCustomContentRegistry;
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeBlockPlacement;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.world.history.SavedBiomeUnavailableException;
import art.arcane.iris.world.storage.matter.TileWrapper;
import art.arcane.volmlib.util.mantle.flag.MantleFlag;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
@@ -47,6 +49,7 @@ import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.volmlib.util.matter.MatterUpdate;
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedServer;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -195,6 +198,11 @@ public final class ModdedChunkUpdateService implements ModdedTickableService {
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, () -> runCustomPass(engine, level, chunkX, chunkZ, chunk));
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, () -> runUpdatePass(engine, level, chunkX, chunkZ, chunk));
});
} catch (SavedBiomeUnavailableException unavailable) {
if (!unavailable.isLoading() || unavailable.getSuppressed().length != 0) {
throw unavailable;
}
IrisLogging.debug("Iris chunk update deferred at " + chunkX + "," + chunkZ + ": saved biomes loading");
} finally {
chunk.release();
}
@@ -315,15 +323,40 @@ public final class ModdedChunkUpdateService implements ModdedTickableService {
}
}
chunk.iterate(MatterUpdate.class, (Integer x, Integer yf, Integer z, MatterUpdate v) -> {
if (v != null && v.isUpdate()) {
update(engine, level, x, yf + minHeight, z, baseX, baseZ, chunk);
}
});
IntArrayList completed = new IntArrayList();
try {
chunk.iterate(MatterUpdate.class, (Integer x, Integer yf, Integer z, MatterUpdate v) -> {
if (v != null && v.isUpdate()) {
update(engine, level, x, yf + minHeight, z, baseX, baseZ, chunk);
completed.add((yf << 8) | ((x & 15) << 4) | (z & 15));
}
});
} catch (RuntimeException | Error failure) {
forgetCompletedUpdates(chunk, completed, failure);
throw failure;
}
chunk.deleteSlices(MatterUpdate.class);
engine.getMetrics().getUpdates().put(stopwatch.getMilliseconds());
}
private static void forgetCompletedUpdates(MantleChunk<Matter> chunk, IntArrayList completed, Throwable failure) {
try {
for (int index = 0; index < completed.size(); index++) {
int position = completed.getInt(index);
int y = position >>> 8;
Matter section = chunk.get(y >> 4);
if (section != null && section.hasSlice(MatterUpdate.class)) {
section.<MatterUpdate>getSlice(MatterUpdate.class)
.set((position >> 4) & 15, y & 15, position & 15, null);
}
}
} catch (RuntimeException | Error cleanupFailure) {
if (cleanupFailure != failure) {
failure.addSuppressed(cleanupFailure);
}
}
}
private void update(Engine engine, NativeWorld level, int x, int y, int z, int baseX, int baseZ, MantleChunk<Matter> chunk) {
if (y < level.minHeight() || y >= level.maxHeight() - 1) {
return;
@@ -338,6 +371,7 @@ public final class ModdedChunkUpdateService implements ModdedTickableService {
try {
ModdedLootApplier.apply(engine, level, pos, state, chunk);
} catch (Throwable e) {
GenerationFailures.rethrowEngineFailure(e);
IrisLogging.reportError(e);
}
} else {