Column biome fallback

- Column biome hunk takes its fallback biome from the caller
- The fallback resolves on first unset read
- Bukkit chunk generator supplies plains
- Core keeps no new Bukkit coupling
This commit is contained in:
Brian Neumann-Fopiano
2026-09-29 01:12:16 -04:00
parent 08ffb96680
commit b7626ab23f
3 changed files with 16 additions and 11 deletions
@@ -18,26 +18,29 @@
package art.arcane.iris.generation.chunk;
import art.arcane.iris.platform.bukkit.BukkitBiome;
import art.arcane.volmlib.nativelib.terrain.NativeBiome;
import art.arcane.volmlib.util.hunk.HunkMutationSupport;
import art.arcane.volmlib.util.hunk.storage.StorageHunk;
import org.bukkit.block.Biome;
import java.util.function.Supplier;
/**
* Biome output for one Bukkit chunk, read back only by the generation stages. The biome actuator writes whole
* columns, so storage stays at one entry per column until a partial column write arrives; that write switches
* the hunk to full resolution. Reads, clamping and the plains fallback match {@link LinkedTerrainChunk}.
* the hunk to full resolution. Reads and clamping match {@link LinkedTerrainChunk}; unset cells read the
* caller's fallback biome, resolved on first use.
*/
public final class ColumnBiomeHunk extends StorageHunk<NativeBiome> {
private static final int CHUNK_SIZE = 16;
private final NativeBiome[] columns = new NativeBiome[CHUNK_SIZE * CHUNK_SIZE];
private NativeBiome[] cells;
private final Supplier<NativeBiome> fallback;
private volatile NativeBiome defaultBiome;
public ColumnBiomeHunk(int height) {
public ColumnBiomeHunk(int height, Supplier<NativeBiome> fallback) {
super(CHUNK_SIZE, height, CHUNK_SIZE);
this.fallback = fallback;
}
@Override
@@ -63,12 +66,12 @@ public final class ColumnBiomeHunk extends StorageHunk<NativeBiome> {
if (biome != null) {
return biome;
}
NativeBiome fallback = defaultBiome;
if (fallback == null) {
fallback = BukkitBiome.of(Biome.PLAINS);
defaultBiome = fallback;
NativeBiome resolved = defaultBiome;
if (resolved == null) {
resolved = fallback.get();
defaultBiome = resolved;
}
return fallback;
return resolved;
}
private void fillColumn(int x, int z, NativeBiome biome) {
@@ -74,6 +74,7 @@ import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.M;
import art.arcane.volmlib.util.hunk.Hunk;
import art.arcane.iris.generation.chunk.ColumnBiomeHunk;
import art.arcane.iris.platform.bukkit.BukkitBiome;
import art.arcane.iris.generation.chunk.ChunkDataHunkHolder;
import art.arcane.iris.generation.context.ChunkContext;
import art.arcane.iris.generation.context.IrisContext;
@@ -90,6 +91,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.block.Biome;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
@@ -1312,7 +1314,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
selected.generateChunk(engine, TerrainChunk.create(d), x, z);
} else {
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(d);
Hunk<NativeBiome> biomes = new ColumnBiomeHunk(d.getMaxHeight() - d.getMinHeight());
Hunk<NativeBiome> biomes = new ColumnBiomeHunk(d.getMaxHeight() - d.getMinHeight(), () -> BukkitBiome.of(Biome.PLAINS));
try (GenerationHistoryRuntimeRouter.CoordinateScope historyScope =
openGenerationHistoryCoordinateScope(engine, x << 4, z << 4);
GenerationSessionLease lease = engine.acquireGenerationLease("bukkit_terrain_stage");
@@ -121,7 +121,7 @@ public class LinkedTerrainChunkTest {
for (int trial = 0; trial < 12; trial++) {
Random random = new Random(9127L + trial);
TerrainChunkBiomeHunkView expected = new TerrainChunkBiomeHunkView(chunk());
ColumnBiomeHunk actual = new ColumnBiomeHunk(16);
ColumnBiomeHunk actual = new ColumnBiomeHunk(16, () -> plains);
int operations = 1 + random.nextInt(80);
for (int operation = 0; operation < operations; operation++) {
NativeBiome biome = palette[random.nextInt(palette.length)];