Merge W2B-carving

This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-28 14:15:03 -04:00
commit f3b16b784b
22 files changed
+852 -203

No files matched your search

@@ -8,6 +8,7 @@ import art.arcane.iris.generation.runtime.EngineMetrics;
import art.arcane.iris.generation.hydrology.runtime.IrisHydrologyRuntime;
import art.arcane.iris.generation.biome.FloatingIslandBoundarySampler;
import art.arcane.iris.generation.biome.IrisBiome;
import art.arcane.iris.generation.mantle.CaveTerrainSnapshot;
import art.arcane.iris.world.history.FloatingBiomeOverlay;
import art.arcane.iris.generation.terrain.IrisRegion;
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
@@ -23,6 +24,7 @@ public class ChunkContext {
private boolean naturalTerrain = true;
private Hunk<NativeBiome> terrainBiomes;
private FloatingBiomeOverlay floatingBiomes;
private CaveTerrainSnapshot caveTerrain;
private final int x;
private final int z;
private final IrisComplex complex;
@@ -157,6 +159,14 @@ public class ChunkContext {
return floatingBiomes;
}
public CaveTerrainSnapshot getCaveTerrain() {
return caveTerrain;
}
public void setCaveTerrain(CaveTerrainSnapshot caveTerrain) {
this.caveTerrain = caveTerrain;
}
public void setNaturalBiome(int localX, int y, int localZ, NativeBiome biome) {
if (terrainBiomes != null) {
terrainBiomes.setRaw(localX, y, localZ, biome);
@@ -0,0 +1,210 @@
package art.arcane.iris.generation.mantle;
import art.arcane.iris.generation.hydrology.cave.HydrologyCaveCell;
import art.arcane.iris.world.storage.matter.PreObjectMatterCell;
import art.arcane.volmlib.util.hunk.bits.DataContainer;
import art.arcane.volmlib.util.hunk.storage.MappedHunk;
import art.arcane.volmlib.util.hunk.storage.PaletteOrHunk;
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
import art.arcane.volmlib.util.matter.Matter;
import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.volmlib.util.matter.MatterSlice;
import java.util.Map;
import java.util.Objects;
import java.util.function.IntFunction;
/**
* The terrain view of one mantle chunk's cavern and hydrology cells (journaled pre-object values win),
* copied once under the chunk monitor. Terrain components finish before any content write reaches a
* chunk and every mantle-writer write journals the value it replaces, so the view holds while the chunk
* generates; the raw writers that run after sCave (dimension stack clearing, continuation restore) drop
* it from the chunk context instead.
*/
public final class CaveTerrainSnapshot {
private static final int SECTION_VOLUME = 4096;
private final int chunkX;
private final int chunkZ;
private final MatterCavern[][] caverns;
private final HydrologyCaveCell[][] hydrology;
private boolean hydrologyPresent;
private CaveTerrainSnapshot(int chunkX, int chunkZ, int sections) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
caverns = new MatterCavern[sections][];
hydrology = new HydrologyCaveCell[sections][];
}
public static CaveTerrainSnapshot capture(MantleChunk<Matter> chunk, int chunkX, int chunkZ) {
Objects.requireNonNull(chunk, "Terrain mantle chunk");
synchronized (chunk) {
int sections = chunk.sectionCount();
CaveTerrainSnapshot snapshot = new CaveTerrainSnapshot(chunkX, chunkZ, sections);
for (int section = 0; section < sections; section++) {
if (!chunk.exists(section)) {
continue;
}
Matter matter = chunk.get(section);
if (matter != null) {
snapshot.captureSection(section, matter);
}
}
return snapshot;
}
}
public boolean covers(int chunkX, int chunkZ) {
return this.chunkX == chunkX && this.chunkZ == chunkZ;
}
public boolean hasHydrology() {
return hydrologyPresent;
}
public MatterCavern cavern(int x, int y, int z) {
if (y < 0) {
return null;
}
int section = y >> 4;
if (section >= caverns.length) {
return null;
}
MatterCavern[] values = caverns[section];
return values == null ? null : values[index(x, y, z)];
}
public HydrologyCaveCell hydrology(int x, int y, int z) {
if (!hydrologyPresent || y < 0) {
return null;
}
int section = y >> 4;
if (section >= hydrology.length) {
return null;
}
HydrologyCaveCell[] values = hydrology[section];
return values == null ? null : values[index(x, y, z)];
}
public MatterCavern composedCavern(int x, int y, int z) {
HydrologyCaveCell cell = hydrology(x, y, z);
return cell != null ? cell.asCavern() : cavern(x, y, z);
}
/**
* Visits every cell holding a cavern or a hydrology cell, section by section in slice position order.
*/
public void forEachCell(CellConsumer consumer) {
for (int section = 0; section < caverns.length; section++) {
MatterCavern[] sectionCaverns = caverns[section];
HydrologyCaveCell[] sectionHydrology = hydrologyPresent ? hydrology[section] : null;
if (sectionCaverns == null && sectionHydrology == null) {
continue;
}
int baseY = section << 4;
for (int position = 0; position < SECTION_VOLUME; position++) {
MatterCavern cavern = sectionCaverns == null ? null : sectionCaverns[position];
HydrologyCaveCell cell = sectionHydrology == null ? null : sectionHydrology[position];
if (cavern != null || cell != null) {
consumer.accept(position & 15, baseY + ((position >> 4) & 15), position >> 8, cavern, cell);
}
}
}
}
public MatterCavern[] composedFace(TerrainMatterView.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)];
for (int y = 0; y < height; y++) {
for (int offset = 0; offset < 16; offset++) {
result[y * 16 + offset] = composedCavern(face.x(offset), y, face.z(offset));
}
}
return result;
}
private void captureSection(int section, Matter matter) {
caverns[section] = copy(matter.getSlice(MatterCavern.class), MatterCavern[]::new);
hydrology[section] = copy(matter.getSlice(HydrologyCaveCell.class), HydrologyCaveCell[]::new);
MatterSlice<PreObjectMatterCell> journal = matter.getSlice(PreObjectMatterCell.class);
if (journal instanceof MappedHunk<?> mapped) {
@SuppressWarnings("unchecked")
Map<Integer, PreObjectMatterCell> entries = (Map<Integer, PreObjectMatterCell>) mapped.getData();
for (Map.Entry<Integer, PreObjectMatterCell> entry : entries.entrySet()) {
restoreOriginals(section, entry.getKey(), entry.getValue());
}
} else if (journal != null) {
for (int position = 0; position < SECTION_VOLUME; position++) {
PreObjectMatterCell cell = journal.get(position & 15, (position >> 4) & 15, position >> 8);
if (cell != null) {
restoreOriginals(section, position, cell);
}
}
}
if (hydrology[section] != null && containsAny(hydrology[section])) {
hydrologyPresent = true;
} else {
hydrology[section] = null;
}
}
private void restoreOriginals(int section, int position, PreObjectMatterCell cell) {
if (cell.cavernCaptured() && (caverns[section] != null || cell.cavern() != null)) {
if (caverns[section] == null) {
caverns[section] = new MatterCavern[SECTION_VOLUME];
}
caverns[section][position] = cell.cavern();
}
if (cell.hydrologyCaptured() && (hydrology[section] != null || cell.hydrology() != null)) {
if (hydrology[section] == null) {
hydrology[section] = new HydrologyCaveCell[SECTION_VOLUME];
}
hydrology[section][position] = cell.hydrology();
}
}
@SuppressWarnings("unchecked")
private static <T> T[] copy(MatterSlice<T> slice, IntFunction<T[]> allocator) {
if (slice == null) {
return null;
}
T[] values = allocator.apply(SECTION_VOLUME);
if (slice instanceof PaletteOrHunk<?> storage && storage.isPalette()
&& slice.getWidth() == 16 && slice.getHeight() == 16 && slice.getDepth() == 16) {
return ((DataContainer<T>) storage.palette()).copyPresent(values) == 0 ? null : values;
}
int width = Math.min(16, slice.getWidth());
int height = Math.min(16, slice.getHeight());
int depth = Math.min(16, slice.getDepth());
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
for (int z = 0; z < depth; z++) {
values[index(x, y, z)] = slice.get(x, y, z);
}
}
}
return values;
}
private static boolean containsAny(Object[] values) {
for (Object value : values) {
if (value != null) {
return true;
}
}
return false;
}
private static int index(int x, int y, int z) {
return ((z & 15) << 8) | ((y & 15) << 4) | (x & 15);
}
@FunctionalInterface
public interface CellConsumer {
void accept(int x, int y, int z, MatterCavern cavern, HydrologyCaveCell hydrology);
}
}
@@ -55,8 +55,12 @@ public interface MantleComponent extends Comparable<MantleComponent> {
return getInputRadius();
}
default boolean isInputGenerationLazy() {
return false;
/**
* The part of {@code inputRadius} generated before this component runs. Content writers generate the
* terrain of any chunk read beyond it on first access, so this sizes the eager window, not what may be read.
*/
default int getEagerInputRadius(int inputRadius) {
return inputRadius;
}
default IrisData getData() {
@@ -67,8 +67,8 @@ public final class MantleHydrologyComponent extends IrisMantleComponent {
}
@Override
public boolean isInputGenerationLazy() {
return true;
public int getEagerInputRadius(int inputRadius) {
return 0;
}
@Override
@@ -128,6 +128,11 @@ public class MantleObjectComponent extends IrisMantleComponent {
return calculateInputRadius(getRadius(), hasCollisionRules());
}
@Override
public int getEagerInputRadius(int inputRadius) {
return Math.min(inputRadius, calculateEagerInputRadius(getRadius(), hasCollisionRules()));
}
@Override
public void hotload() {
super.hotload();
@@ -272,6 +277,17 @@ public class MantleObjectComponent extends IrisMantleComponent {
return radius > 0 ? Math.ceilDiv(radius, 16) : 0;
}
/**
* Every replayed source chunk plus one chunk of placement footprint. Larger footprints read past it and
* get their terrain generated on first access.
*/
static int calculateEagerInputRadius(int radius, boolean sourceAnchoredCollisions) {
int normalizedRadius = Math.max(0, radius);
long sourceLegs = sourceAnchoredCollisions ? 2L : 1L;
long inputRadius = (sourceChunkRadius(normalizedRadius) * 16L * sourceLegs) + Math.min(normalizedRadius, 16) + 1L;
return inputRadius >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) inputRadius;
}
static int calculateInputRadius(int radius, boolean sourceAnchoredCollisions) {
int normalizedRadius = Math.max(0, radius);
long sourceChunkRadius = sourceChunkRadius(normalizedRadius);
@@ -35,10 +35,12 @@ import art.arcane.iris.world.history.TransitionGenerationPlan;
import art.arcane.iris.generation.noise.IrisGeneratorStyle;
import art.arcane.iris.pack.value.IrisPosition;
import art.arcane.iris.generation.block.TileData;
import art.arcane.iris.generation.context.ChunkContext;
import art.arcane.iris.generation.hydrology.cave.HydrologyCaveCell;
import art.arcane.volmlib.util.collection.KSet;
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
import art.arcane.volmlib.util.function.Function3;
import art.arcane.volmlib.util.mantle.flag.MantleFlag;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
import art.arcane.volmlib.util.math.RNG;
@@ -90,6 +92,11 @@ public class MantleWriter implements ObjectPassPlacer, AutoCloseable {
private final ThreadLocal<Integer> activeComponentPriority = new ThreadLocal<>();
@Getter(AccessLevel.NONE)
private final ThreadLocal<ObjectPlacementCapture> objectPlacementCapture = new ThreadLocal<>();
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
@EqualsAndHashCode.Exclude
@ToString.Exclude
private TerrainAccess terrainAccess;
public MantleWriter(EngineMantle engineMantle, Mantle<Matter> mantle, int x, int z, int radius, boolean multicore) {
this(engineMantle, mantle, x, z, radius, radius * 2, multicore);
@@ -104,17 +111,7 @@ public class MantleWriter implements ObjectPassPlacer, AutoCloseable {
int accessRadius,
boolean multicore
) {
this.engineMantle = engineMantle;
this.mantle = mantle;
this.radius = accessRadius;
this.x = x;
this.z = z;
IrisComplex complex = engineMantle.getComplex();
this.transitionGenerationPlan = complex == null ? null : complex.getTransitionGenerationPlan();
// Every coordinate acquireChunk accepts lives in this window, so a flat array replaces the
// boxed per-block map lookup on the placement and carve hot paths.
this.windowSide = (this.radius * 2) + 1;
this.window = new AtomicReferenceArray<>(windowSide * windowSide);
this(engineMantle, mantle, x, z, accessRadius);
final boolean foliaMaintenance = J.isFolia()
&& WorldMaintenance.isWorldMaintenanceActive(engineMantle.getEngine().getWorld().identity());
@@ -142,6 +139,41 @@ public class MantleWriter implements ObjectPassPlacer, AutoCloseable {
}
}
private MantleWriter(EngineMantle engineMantle, Mantle<Matter> mantle, int x, int z, int accessRadius) {
this.engineMantle = engineMantle;
this.mantle = mantle;
this.radius = accessRadius;
this.x = x;
this.z = z;
IrisComplex complex = engineMantle.getComplex();
this.transitionGenerationPlan = complex == null ? null : complex.getTransitionGenerationPlan();
// Every coordinate acquireChunk accepts lives in this window, so a flat array replaces the
// boxed per-block map lookup on the placement and carve hot paths.
this.windowSide = (this.radius * 2) + 1;
this.window = new AtomicReferenceArray<>(windowSide * windowSide);
}
/**
* A writer over one already loaded chunk, for generating that chunk's terrain components without a
* prefetch.
*/
static MantleWriter forChunk(EngineMantle engineMantle, Mantle<Matter> mantle, MantleChunk<Matter> chunk,
int chunkX, int chunkZ) {
MantleWriter writer = new MantleWriter(engineMantle, mantle, chunkX, chunkZ, 0);
writer.window.set(0, chunk.use());
return writer;
}
/**
* From now on every chunk this writer hands out has its terrain components generated first. Called once
* the terrain passes of the window are done and before any content pass reads or writes.
*/
void requireTerrainOnAccess(List<MantleComponent> terrainComponents, ChunkContext context, IrisComplex complex) {
terrainAccess = terrainComponents.isEmpty()
? null
: new TerrainAccess(terrainComponents.toArray(new MantleComponent[0]), context, complex);
}
static int resolvePrefetchParallelism(boolean foliaMaintenance, boolean multicore, int availableProcessors) {
if (foliaMaintenance) {
return 1;
@@ -844,20 +876,24 @@ public class MantleWriter implements ObjectPassPlacer, AutoCloseable {
return null;
}
while (true) {
MantleChunk<Matter> chunk = window.get(index);
if (chunk != null) {
return chunk;
}
MantleChunk<Matter> chunk = window.get(index);
while (chunk == null) {
// Losing this race must release our own use, never the winner's: the winner is already
// writing through the chunk it published.
MantleChunk<Matter> acquired = mantle.getChunk(cx, cz).use();
if (window.compareAndSet(index, null, acquired)) {
return acquired;
chunk = acquired;
} else {
acquired.release();
chunk = window.get(index);
}
acquired.release();
}
TerrainAccess access = terrainAccess;
if (access != null && !access.ready[index]) {
access.ensure(chunk, cx, cz);
access.ready[index] = true;
}
return chunk;
}
@ChunkCoordinates
@@ -1502,6 +1538,9 @@ public class MantleWriter implements ObjectPassPlacer, AutoCloseable {
@Override
public void close() {
for (int index = 0; index < window.length(); index++) {
if (window.get(index) == null) {
continue;
}
MantleChunk<Matter> chunk = window.getAndSet(index, null);
if (chunk != null) {
chunk.release();
@@ -1509,6 +1548,45 @@ public class MantleWriter implements ObjectPassPlacer, AutoCloseable {
}
}
private final class TerrainAccess {
private final MantleComponent[] components;
private final ChunkContext context;
private final IrisComplex complex;
private final boolean[] ready = new boolean[window.length()];
private TerrainAccess(MantleComponent[] components, ChunkContext context, IrisComplex complex) {
this.components = components;
this.context = context;
this.complex = complex;
}
private void ensure(MantleChunk<Matter> chunk, int chunkX, int chunkZ) {
if (chunk.isFlagged(MantleFlag.PLANNED) || complex != null && !complex.allowsMantleChunkWrite(chunkX, chunkZ)) {
return;
}
for (MantleComponent component : components) {
if (chunk.isFlagged(component.getFlag()) || !hasPrerequisites(chunk, component)) {
continue;
}
chunk.raiseFlagSuspend(component.getFlag(), () -> {
try (MantleWriter terrainWriter = forChunk(engineMantle, mantle, chunk, chunkX, chunkZ)) {
terrainWriter.withComponentPriority(component.getPriority(),
() -> component.generateLayer(terrainWriter, chunkX, chunkZ, context));
}
});
}
}
private static boolean hasPrerequisites(MantleChunk<Matter> chunk, MantleComponent component) {
for (MantleFlag prerequisite : component.getPrerequisiteFlags()) {
if (!chunk.isFlagged(prerequisite)) {
return false;
}
}
return true;
}
}
public final class ObjectPlacementCapture implements AutoCloseable {
private final ObjectContinuationBundle.PlacementKey key;
private final Long2ObjectOpenHashMap<Matter> fragments = new Long2ObjectOpenHashMap<>();
@@ -90,7 +90,7 @@ public interface MatterGenerator {
int prefetchRadius = passPlans[0].passChunkRadius();
LongOpenHashSet partialChunks = new LongOpenHashSet();
List<MantleComponent> requiredComponents = enabledComponents();
List<MantleFlag> terrainFlags = terrainFlags(requiredComponents);
boolean terrainOnAccess = false;
try (MantleWriter writer = new MantleWriter(
getEngine().getMantle(),
@@ -129,6 +129,10 @@ public interface MatterGenerator {
if (enabledComponentCount == 0) {
continue;
}
if (!terrainOnAccess && includesContent(enabledComponents, enabledComponentCount)) {
writer.requireTerrainOnAccess(terrainComponents(requiredComponents), context, complex);
terrainOnAccess = true;
}
// Every multicore generation claims its components through the in-flight map.
// A caller outside the pool spreads its window across the pool; a pool thread
@@ -185,9 +189,6 @@ public interface MatterGenerator {
continue;
}
if (phase == MatterGenerationPhase.CONTENT) {
requireTerrainPhase(chunk, passX, passZ, terrainFlags);
}
int eligibleComponentCount = 0;
for (int componentIndex = 0; componentIndex < enabledComponentCount; componentIndex++) {
MantleComponent component = enabledComponents[componentIndex];
@@ -303,9 +304,8 @@ public interface MatterGenerator {
: 0;
int componentInputRadius = component.getInputRadius(x, z, invocationChunkRadius, context);
passAccessInputRadius = Math.max(passAccessInputRadius, componentInputRadius);
if (!component.isInputGenerationLazy()) {
passGenerationInputRadius = Math.max(passGenerationInputRadius, componentInputRadius);
}
passGenerationInputRadius = Math.max(passGenerationInputRadius,
component.getEagerInputRadius(componentInputRadius));
}
int accessInvocationRadius = accessDownstreamBlockRadius + passBlockRadius;
int generationInvocationRadius = generationDownstreamBlockRadius + passBlockRadius;
@@ -332,24 +332,23 @@ public interface MatterGenerator {
return List.copyOf(components);
}
private static List<MantleFlag> terrainFlags(List<MantleComponent> components) {
List<MantleFlag> flags = new ArrayList<>();
for (MantleComponent component : components) {
if (component.getGenerationPhase() == MatterGenerationPhase.TERRAIN) {
flags.add(component.getFlag());
private static boolean includesContent(MantleComponent[] components, int count) {
for (int index = 0; index < count; index++) {
if (components[index].getGenerationPhase() == MatterGenerationPhase.CONTENT) {
return true;
}
}
return List.copyOf(flags);
return false;
}
private static void requireTerrainPhase(MantleChunk<Matter> chunk, int chunkX, int chunkZ,
List<MantleFlag> flags) {
for (MantleFlag flag : flags) {
if (!chunk.isFlagged(flag)) {
throw new IllegalStateException("Content generation at " + chunkX + "," + chunkZ
+ " requires completed terrain component " + flag.name());
private static List<MantleComponent> terrainComponents(List<MantleComponent> components) {
List<MantleComponent> terrain = new ArrayList<>();
for (MantleComponent component : components) {
if (component.getGenerationPhase() == MatterGenerationPhase.TERRAIN) {
terrain.add(component);
}
}
return terrain;
}
private static boolean hasCompletedComponents(MantleChunk<Matter> chunk, List<MantleComponent> components) {
@@ -134,8 +134,12 @@ public final class TerrainMatterView {
SOUTH(false, 15);
private final int[] positions = new int[256];
private final boolean fixedX;
private final int coordinate;
Face(boolean fixedX, int coordinate) {
this.fixedX = fixedX;
this.coordinate = coordinate;
for (int y = 0; y < 16; y++) {
for (int offset = 0; offset < 16; offset++) {
int x = fixedX ? coordinate : offset;
@@ -144,6 +148,14 @@ public final class TerrainMatterView {
}
}
}
int x(int offset) {
return fixedX ? coordinate : offset;
}
int z(int offset) {
return fixedX ? offset : coordinate;
}
}
public static <T> void iterate(MantleChunk<Matter> chunk, Class<T> type,
@@ -109,7 +109,7 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode {
registerTerrainStage(sCave);
registerTerrainStage(sPost);
registerTerrainStage(sFloatingTerrainSolid);
registerStage((x, z, k, p, m, c) -> cave.decorateNaturalCaves(x, z, k));
registerStage((x, z, k, p, m, c) -> cave.decorateNaturalCaves(x, z, k, c));
// Never burst these three: all of them write the same block hunk (and sDecorant reads
// the surface sInsertMatter writes), so parallel order is scheduler-dependent. The
// production path already runs them inline in this order; sequential registration
@@ -218,6 +218,9 @@ public interface EngineMode extends Staged {
IrisDimensionStackActuator.clearHostNaturalMetadata(getEngine(), x, z, biomes.getHeight(), ctx);
ctx.beginContent();
List<Matter> continuations = restoreObjectContinuations(x, z);
if (!continuations.isEmpty()) {
ctx.setCaveTerrain(null);
}
for (EngineStage i : stages) {
i.generate(x, z, blocks, biomes, multicore, ctx);
}
@@ -29,6 +29,7 @@ import art.arcane.iris.generation.runtime.IrisComplex;
import art.arcane.iris.generation.terrain.IrisDimension;
import art.arcane.volmlib.util.stream.ProceduralStream;
import art.arcane.iris.generation.runtime.EngineAssignedModifier;
import art.arcane.iris.generation.mantle.CaveTerrainSnapshot;
import art.arcane.iris.generation.mantle.TerrainMatterView;
import art.arcane.iris.generation.terrain.InferredType;
import art.arcane.iris.generation.biome.IrisBiome;
@@ -126,6 +127,10 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
MantleChunk<Matter> mantleChunk = mantle.getChunk(x, z).use();
try {
PrecisionStopwatch resolveStopwatch = PrecisionStopwatch.start();
CaveTerrainSnapshot terrain = CaveTerrainSnapshot.capture(mantleChunk, x, z);
if (context != null) {
context.setCaveTerrain(terrain);
}
int worldHeightSpan = getEngine().getWorld().maxHeight() - getEngine().getWorld().minHeight();
int caveLavaHeight = getEngine().getDimension().getCaveLavaHeight();
CarveResolutionContext resolutionContext = new CarveResolutionContext(
@@ -142,32 +147,20 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
chunkBlockZ
);
CarveResolver carveResolver = new CarveResolver(resolutionContext);
TerrainMatterView.iterate(mantleChunk, MatterCavern.class, (xx, yy, zz, cavern) -> carveResolver.apply(
xx,
yy,
zz,
cavern,
dataIfPresent(mantleChunk, xx, yy, zz, HydrologyCaveCell.class)
));
TerrainMatterView.iterate(mantleChunk, HydrologyCaveCell.class, (xx, yy, zz, hydrology) -> {
if (dataIfPresent(mantleChunk, xx, yy, zz, MatterCavern.class) == null) {
carveResolver.apply(xx, yy, zz, null, hydrology);
}
});
terrain.forEachCell(carveResolver::apply);
if (scratch.customCaveBiomePresent) {
addInternalWallsFromMantle(mantleChunk, walls, columnMasks);
addInternalWallsFromMantle(terrain, walls, columnMasks);
} else {
addInternalWallsFromMasks(walls, columnMasks);
}
addCrossChunkBoundaryWalls(mantle, mantleChunk, walls, boundaryMasks, x, z, surfaceHeights);
addCrossChunkBoundaryWalls(mantle, terrain, walls, boundaryMasks, x, z, surfaceHeights);
getEngine().getMetrics().getCarveResolve().put(resolveStopwatch.getMilliseconds());
PrecisionStopwatch applyStopwatch = PrecisionStopwatch.start();
try {
IrisData wallData = getData();
walls.forEach((rx, yy, rz, cavern) -> {
HydrologyCaveCell hydrology = dataIfPresent(
mantleChunk, rx, yy, rz, HydrologyCaveCell.class);
HydrologyCaveCell hydrology = terrain.hydrology(rx, yy, rz);
if (hydrology != null && hydrology.protectsPlacement()) {
return;
}
@@ -191,8 +184,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
for (int columnIndex = 0; columnIndex < 256; columnIndex++) {
processColumnFromMask(
output,
mantleChunk,
mantle,
terrain,
columnMasks[columnIndex],
columnIndex,
x,
@@ -209,7 +201,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
processBoundaryColumnFromMask(
output,
mantleChunk,
terrain,
boundaryMasks[columnIndex],
walls,
columnIndex,
@@ -472,7 +464,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
}
private void addInternalWallsFromMantle(MantleChunk<Matter> mc, CarveWallBuffer walls, CarveColumnMask[] columnMasks) {
private void addInternalWallsFromMantle(CaveTerrainSnapshot terrain, CarveWallBuffer walls, CarveColumnMask[] columnMasks) {
for (int columnIndex = 0; columnIndex < 256; columnIndex++) {
CarveColumnMask columnMask = columnMasks[columnIndex];
if (columnMask.isEmpty()) {
@@ -483,18 +475,18 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
int rz = columnIndex & 15;
int yy = columnMask.nextSetBit(0);
while (yy >= 0) {
MatterCavern cavern = composedCavernAt(mc, rx, yy, rz);
MatterCavern cavern = terrain.composedCavern(rx, yy, rz);
if (cavern != null) {
if (rz < 15 && composedCavernAt(mc, rx, yy, rz + 1) == null) {
if (rz < 15 && terrain.composedCavern(rx, yy, rz + 1) == null) {
walls.put(rx, yy, rz + 1, cavern);
}
if (rx < 15 && composedCavernAt(mc, rx + 1, yy, rz) == null) {
if (rx < 15 && terrain.composedCavern(rx + 1, yy, rz) == null) {
walls.put(rx + 1, yy, rz, cavern);
}
if (rz > 0 && composedCavernAt(mc, rx, yy, rz - 1) == null) {
if (rz > 0 && terrain.composedCavern(rx, yy, rz - 1) == null) {
walls.put(rx, yy, rz - 1, cavern);
}
if (rx > 0 && composedCavernAt(mc, rx - 1, yy, rz) == null) {
if (rx > 0 && terrain.composedCavern(rx - 1, yy, rz) == null) {
walls.put(rx - 1, yy, rz, cavern);
}
}
@@ -505,7 +497,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
private void addCrossChunkBoundaryWalls(
Mantle<Matter> mantle,
MantleChunk<Matter> mc,
CaveTerrainSnapshot terrain,
CarveWallBuffer walls,
CarveColumnMask[] boundaryMasks,
int chunkX,
@@ -534,10 +526,10 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
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[] ownWest = west == null ? null : terrain.composedFace(TerrainMatterView.Face.WEST, height);
MatterCavern[] ownEast = east == null ? null : terrain.composedFace(TerrainMatterView.Face.EAST, height);
MatterCavern[] ownNorth = north == null ? null : terrain.composedFace(TerrainMatterView.Face.NORTH, height);
MatterCavern[] ownSouth = south == null ? null : terrain.composedFace(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);
@@ -586,18 +578,9 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
return plate.get(chunkX & 31, chunkZ & 31);
}
private MatterCavern composedCavernAt(MantleChunk<Matter> mantleChunk, int x, int y, int z) {
return TerrainMatterView.getComposedCavern(mantleChunk, x, y, z);
}
private static <T> T dataIfPresent(MantleChunk<Matter> mantleChunk, int x, int y, int z, Class<T> type) {
return TerrainMatterView.get(mantleChunk, x, y, z, type);
}
private void processColumnFromMask(
Hunk<NativeBlockState> output,
MantleChunk<Matter> mc,
Mantle<Matter> mantle,
CaveTerrainSnapshot terrain,
CarveColumnMask columnMask,
int columnIndex,
int chunkX,
@@ -631,7 +614,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
zone.ceiling = buf;
} else {
if (zone.isValid(resolverState.height)) {
processZone(output, mc, mantle, zone, rx, rz, worldX, worldZ, resolverState,
processZone(output, terrain, zone, rx, rz, worldX, worldZ, resolverState,
caveBiomeCache, customBiomeCache);
}
zone = new CaveZone();
@@ -644,14 +627,14 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
if (zone.isValid(resolverState.height)) {
processZone(output, mc, mantle, zone, rx, rz, worldX, worldZ, resolverState,
processZone(output, terrain, zone, rx, rz, worldX, worldZ, resolverState,
caveBiomeCache, customBiomeCache);
}
}
private void processBoundaryColumnFromMask(
Hunk<NativeBlockState> output,
MantleChunk<Matter> mantleChunk,
CaveTerrainSnapshot terrain,
CarveColumnMask boundaryMask,
CarveWallBuffer walls,
int columnIndex,
@@ -678,7 +661,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
if (y == zoneCeiling + 1) {
zoneCeiling = y;
} else {
paintBoundaryZone(output, mantleChunk, walls, rx, rz, worldX, worldZ, zoneFloor, zoneCeiling,
paintBoundaryZone(output, terrain, walls, rx, rz, worldX, worldZ, zoneFloor, zoneCeiling,
resolverState, caveBiomeCache, customBiomeCache);
zoneFloor = y;
zoneCeiling = y;
@@ -686,13 +669,13 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
y = boundaryMask.nextSetBit(y + 1);
}
paintBoundaryZone(output, mantleChunk, walls, rx, rz, worldX, worldZ, zoneFloor, zoneCeiling,
paintBoundaryZone(output, terrain, walls, rx, rz, worldX, worldZ, zoneFloor, zoneCeiling,
resolverState, caveBiomeCache, customBiomeCache);
}
private void paintBoundaryZone(
Hunk<NativeBlockState> output,
MantleChunk<Matter> mantleChunk,
CaveTerrainSnapshot terrain,
CarveWallBuffer walls,
int rx,
int rz,
@@ -715,8 +698,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
if (floorBiome != null) {
HydrologyCaveCell floorHydrology = dataIfPresent(
mantleChunk, rx, zoneFloor, rz, HydrologyCaveCell.class);
HydrologyCaveCell floorHydrology = terrain.hydrology(rx, zoneFloor, rz);
IrisRiverMaterialConfig bedMaterial = undergroundBedMaterial();
KList<NativeBlockState> floorLayers = floorBiome.generateLayers(
resolverState.dimension, worldX, worldZ, rng, 3, zoneFloor, resolverState.data, resolverState.complex);
@@ -728,8 +710,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
if (floorY < 0) {
break;
}
HydrologyCaveCell hydrology = dataIfPresent(
mantleChunk, rx, floorY, rz, HydrologyCaveCell.class);
HydrologyCaveCell hydrology = terrain.hydrology(rx, floorY, rz);
if (hydrology != null
&& hydrology.protectsPlacement()
&& hydrology.action() != HydrologyCaveAction.SEAL_GUARD) {
@@ -764,8 +745,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
if (ceilingY >= worldMaxY) {
break;
}
HydrologyCaveCell hydrology = dataIfPresent(
mantleChunk, rx, ceilingY, rz, HydrologyCaveCell.class);
HydrologyCaveCell hydrology = terrain.hydrology(rx, ceilingY, rz);
if (hydrology != null
&& hydrology.protectsPlacement()
&& hydrology.action() != HydrologyCaveAction.SEAL_GUARD) {
@@ -800,7 +780,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
return (h & 15L) == 0L;
}
private void processZone(Hunk<NativeBlockState> output, MantleChunk<Matter> mc, Mantle<Matter> mantle,
private void processZone(Hunk<NativeBlockState> output, CaveTerrainSnapshot terrain,
CaveZone zone, int rx, int rz, int xx, int zz,
CaveInputs resolverState,
Long2ObjectOpenHashMap<IrisBiome> caveBiomeCache,
@@ -815,16 +795,15 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
output.setRaw(rx, zone.ceiling, rz, AIR);
}
IrisBiome floorBiome = resolveCaveBoundaryBiome(mc, rx, zone.floor, rz, xx, zz, resolverState, caveBiomeCache, customBiomeCache);
IrisBiome ceilingBiome = resolveCaveBoundaryBiome(mc, rx, zone.ceiling, rz, xx, zz, resolverState, caveBiomeCache, customBiomeCache);
IrisBiome floorBiome = resolveCaveBoundaryBiome(terrain, rx, zone.floor, rz, xx, zz, resolverState, caveBiomeCache, customBiomeCache);
IrisBiome ceilingBiome = resolveCaveBoundaryBiome(terrain, rx, zone.ceiling, rz, xx, zz, resolverState, caveBiomeCache, customBiomeCache);
if (floorBiome == null && ceilingBiome == null) {
normalizeCaveZoneWaterlogging(output, mc, zone, rx, rz, xx, zz);
normalizeCaveZoneWaterlogging(output, terrain, zone, rx, rz, xx, zz);
return;
}
if (floorBiome != null) {
HydrologyCaveCell floorHydrology = dataIfPresent(
mc, rx, zone.floor, rz, HydrologyCaveCell.class);
HydrologyCaveCell floorHydrology = terrain.hydrology(rx, zone.floor, rz);
IrisRiverMaterialConfig bedMaterial = undergroundBedMaterial();
KList<NativeBlockState> floorBlocks = floorBiome.generateLayers(resolverState.dimension, xx, zz, rng, 3, zone.floor, resolverState.data, resolverState.complex);
for (int i = 0; i < zone.floor - 1; i++) {
@@ -832,7 +811,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
break;
}
int y = zone.floor - i - 1;
HydrologyCaveCell hydrology = dataIfPresent(mc, rx, y, rz, HydrologyCaveCell.class);
HydrologyCaveCell hydrology = terrain.hydrology(rx, y, rz);
if (hydrology != null
&& hydrology.protectsPlacement()
&& hydrology.action() != HydrologyCaveAction.SEAL_GUARD) {
@@ -865,7 +844,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
if (cy >= maxY) {
break;
}
HydrologyCaveCell hydrology = dataIfPresent(mc, rx, cy, rz, HydrologyCaveCell.class);
HydrologyCaveCell hydrology = terrain.hydrology(rx, cy, rz);
if (hydrology != null
&& hydrology.protectsPlacement()
&& hydrology.action() != HydrologyCaveAction.SEAL_GUARD) {
@@ -884,64 +863,71 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
}
normalizeCaveZoneWaterlogging(output, mc, zone, rx, rz, xx, zz);
normalizeCaveZoneWaterlogging(output, terrain, zone, rx, rz, xx, zz);
}
public void decorateNaturalCaves(int blockX, int blockZ, Hunk<NativeBlockState> output) {
public void decorateNaturalCaves(int blockX, int blockZ, Hunk<NativeBlockState> output, ChunkContext context) {
Mantle<Matter> mantle = getEngine().getMantle().getMantle();
MantleChunk<Matter> chunk = mantle.getChunk(blockX >> 4, blockZ >> 4).use();
CaveInputs resolver = new CaveInputs(getEngine());
CaveTerrainSnapshot terrain = context == null ? null : context.getCaveTerrain();
if (context != null) {
context.setCaveTerrain(null);
}
if (terrain == null || !terrain.covers(blockX >> 4, blockZ >> 4)) {
MantleChunk<Matter> chunk = mantle.getChunk(blockX >> 4, blockZ >> 4).use();
try {
terrain = CaveTerrainSnapshot.capture(chunk, blockX >> 4, blockZ >> 4);
} finally {
chunk.release();
}
}
CaveInputs resolver = CaveInputs.forContentChunk(getEngine(), blockX >> 4, blockZ >> 4);
Long2ObjectOpenHashMap<IrisBiome> caveBiomes = new Long2ObjectOpenHashMap<>(256);
Map<String, IrisBiome> customBiomes = new HashMap<>();
try {
int width = output.getWidth();
int depth = output.getDepth();
int height = output.getHeight();
ColumnExtent extent = output instanceof ColumnExtent columnExtent ? columnExtent : null;
for (int localX = 0; localX < width; localX++) {
for (int localZ = 0; localZ < depth; localZ++) {
int worldX = blockX + localX;
int worldZ = blockZ + localZ;
int floor = -1;
int top = extent == null ? height - 1 : extent.highestStoredY(localX, localZ);
for (int y = 1; y < height; y++) {
if (y > top) {
break;
}
NativeBlockState state = output.getRaw(localX, y, localZ);
if (B.isSolid(state)) {
if (floor >= 0) {
CaveZone zone = new CaveZone();
zone.setFloor(floor);
zone.setCeiling(y - 1);
if (zone.isValid(resolver.height)
&& !getComplex().isTerrain3DOpening(worldX, floor, worldZ)) {
if (markerRoll(worldX, zone.ceiling, worldZ, 0x9E3779B97F4A7C15L)) {
mantle.set(worldX, zone.ceiling, worldZ, MarkerMatter.CAVE_CEILING);
}
if (markerRoll(worldX, zone.floor, worldZ, 0xC2B2AE3D27D4EB4FL)) {
mantle.set(worldX, zone.floor, worldZ, MarkerMatter.CAVE_FLOOR);
}
IrisBiome floorBiome = resolveCaveBoundaryBiome(chunk, localX, floor, localZ,
worldX, worldZ, resolver, caveBiomes, customBiomes);
IrisBiome ceilingBiome = resolveCaveBoundaryBiome(chunk, localX, y - 1, localZ,
worldX, worldZ, resolver, caveBiomes, customBiomes);
decorateZone(output, zone, localX, localZ, worldX, worldZ,
floorBiome, ceilingBiome);
if (extent != null) {
top = extent.highestStoredY(localX, localZ);
}
int width = output.getWidth();
int depth = output.getDepth();
int height = output.getHeight();
ColumnExtent extent = output instanceof ColumnExtent columnExtent ? columnExtent : null;
for (int localX = 0; localX < width; localX++) {
for (int localZ = 0; localZ < depth; localZ++) {
int worldX = blockX + localX;
int worldZ = blockZ + localZ;
int floor = -1;
int top = extent == null ? height - 1 : extent.highestStoredY(localX, localZ);
for (int y = 1; y < height; y++) {
if (y > top) {
break;
}
NativeBlockState state = output.getRaw(localX, y, localZ);
if (B.isSolid(state)) {
if (floor >= 0) {
CaveZone zone = new CaveZone();
zone.setFloor(floor);
zone.setCeiling(y - 1);
if (zone.isValid(resolver.height)
&& !getComplex().isTerrain3DOpening(worldX, floor, worldZ)) {
if (markerRoll(worldX, zone.ceiling, worldZ, 0x9E3779B97F4A7C15L)) {
mantle.set(worldX, zone.ceiling, worldZ, MarkerMatter.CAVE_CEILING);
}
if (markerRoll(worldX, zone.floor, worldZ, 0xC2B2AE3D27D4EB4FL)) {
mantle.set(worldX, zone.floor, worldZ, MarkerMatter.CAVE_FLOOR);
}
IrisBiome floorBiome = resolveCaveBoundaryBiome(terrain, localX, floor, localZ,
worldX, worldZ, resolver, caveBiomes, customBiomes);
IrisBiome ceilingBiome = resolveCaveBoundaryBiome(terrain, localX, y - 1, localZ,
worldX, worldZ, resolver, caveBiomes, customBiomes);
decorateZone(output, zone, localX, localZ, worldX, worldZ,
floorBiome, ceilingBiome);
if (extent != null) {
top = extent.highestStoredY(localX, localZ);
}
floor = -1;
}
} else if (floor < 0 && B.isSolid(output.getRaw(localX, y - 1, localZ))) {
floor = y;
floor = -1;
}
} else if (floor < 0 && B.isSolid(output.getRaw(localX, y - 1, localZ))) {
floor = y;
}
}
}
} finally {
chunk.release();
}
}
@@ -966,7 +952,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
private void normalizeCaveZoneWaterlogging(
Hunk<NativeBlockState> output,
MantleChunk<Matter> mantleChunk,
CaveTerrainSnapshot terrain,
CaveZone zone,
int localX,
int localZ,
@@ -976,13 +962,11 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
int minimumY = Math.max(0, zone.floor - 1);
int maximumY = Math.min(output.getHeight() - 1, zone.ceiling + 1);
for (int y = minimumY; y <= maximumY; y++) {
HydrologyCaveCell hydrology = dataIfPresent(
mantleChunk, localX, y, localZ, HydrologyCaveCell.class);
HydrologyCaveCell hydrology = terrain.hydrology(localX, y, localZ);
if (hydrology == null) {
continue;
}
MatterCavern baseline = dataIfPresent(
mantleChunk, localX, y, localZ, MatterCavern.class);
MatterCavern baseline = terrain.cavern(localX, y, localZ);
NativeBlockState current = output.getRaw(localX, y, localZ);
NativeBlockState columnFluid = getComplex().resolveHydrologyFluid(
hydrology.fluidProfileKey(),
@@ -1001,8 +985,8 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
}
IrisBiome resolveCaveBoundaryBiome(MantleChunk<Matter> mantleChunk, int x, int y, int z, int worldX, int worldZ, CaveInputs resolverState, Long2ObjectOpenHashMap<IrisBiome> caveBiomeCache, Map<String, IrisBiome> customBiomeCache) {
MatterCavern cavern = composedCavernAt(mantleChunk, x, y, z);
IrisBiome resolveCaveBoundaryBiome(CaveTerrainSnapshot terrain, int x, int y, int z, int worldX, int worldZ, CaveInputs resolverState, Long2ObjectOpenHashMap<IrisBiome> caveBiomeCache, Map<String, IrisBiome> customBiomeCache) {
MatterCavern cavern = terrain == null ? null : terrain.composedCavern(x, y, z);
return resolveCaveBoundaryBiome(
cavern, worldX, y, worldZ, resolverState, caveBiomeCache, customBiomeCache);
}
@@ -1179,19 +1163,39 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
private final ProceduralStream<IrisBiome> caveBiomes;
private final ProceduralStream<Double> heights;
private final CaveColumn[] columns;
private final boolean chunkLimited;
private final int chunkX;
private final int chunkZ;
CaveInputs(Engine engine) {
this(engine, false, 0, 0);
}
/**
* Inputs for the content stage of one chunk. A coordinate inside that chunk resolves under the chunk's
* own generation route, exactly the binding the natural terrain stage samples with, so it takes the
* captured column path; any other coordinate keeps the per-coordinate history dispatch.
*/
static CaveInputs forContentChunk(Engine engine, int chunkX, int chunkZ) {
return new CaveInputs(engine, true, chunkX, chunkZ);
}
private CaveInputs(Engine engine, boolean contentChunk, int chunkX, int chunkZ) {
this.engine = engine;
complex = engine.getComplex();
dimension = engine.getDimension();
data = engine.getData();
height = engine.getHeight();
IrisContext context = IrisContext.get();
boolean scoped = engine instanceof IrisEngine irisEngine
boolean generating = engine instanceof IrisEngine irisEngine
&& irisEngine.hasGenerationRuntimeScope() && !engine.getPlatformHooks().isMainThread()
&& context != null && context.getChunkContext() != null
&& context.getChunkContext().getComplex() == complex
&& context.getChunkContext().isNaturalTerrain();
&& context.getChunkContext().getComplex() == complex;
boolean natural = generating && context.getChunkContext().isNaturalTerrain();
boolean scoped = natural || generating && contentChunk;
this.chunkLimited = !natural;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
snapshot = scoped ? IrisDimensionCarvingResolver.snapshot(engine) : null;
minimumY = scoped ? engine.getWorld().minHeight() : 0;
stack = scoped ? engine.getDimensionStackContext() : null;
@@ -1202,7 +1206,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
IrisBiome resolve(int x, int y, int z) {
if (snapshot == null) {
if (snapshot == null || chunkLimited && ((x >> 4) != chunkX || (z >> 4) != chunkZ)) {
return engine.getCaveBiome(x, y, z, state);
}
IrisBiome configured = snapshot.resolveBiome(x, y + minimumY, z);
@@ -110,6 +110,7 @@ public final class IrisDimensionStackActuator extends EngineAssignedActuator<Nat
if (!context.hasDimensionStack() || !context.getComplex().allowsMantleChunkWrite(x >> 4, z >> 4)) {
return;
}
context.setCaveTerrain(null);
MantleChunk<Matter> chunk = engine.getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
try {
synchronized (chunk) {