This commit is contained in:
Brian Neumann-Fopiano
2026-07-16 19:38:53 -04:00
parent e8dd4e1127
commit 0193f75daa
21 changed files with 272 additions and 180 deletions
@@ -70,10 +70,10 @@ public class CustomBiomeSource extends BiomeSource {
LinkedHashSet<Holder<Biome>> biomes = new LinkedHashSet<>();
for (IrisBiome i : engine.getAllBiomes()) {
Holder<Biome> vanillaHolder = NMSBinding.biomeToBiomeBase(registry, i.getVanillaDerivative());
Holder<Biome> vanillaHolder = resolveBiomeHolder(registry, i.getStructureDerivativeKey());
if (vanillaHolder == null) {
throw new IllegalStateException("Iris structure biome derivative '"
+ i.getVanillaDerivativeKey() + "' is not registered for biome '" + i.getLoadKey() + "'");
+ i.getStructureDerivativeKey() + "' is not registered for biome '" + i.getLoadKey() + "'");
}
biomes.add(vanillaHolder);
@@ -312,10 +312,10 @@ public class CustomBiomeSource extends BiomeSource {
throw new IllegalStateException("Iris returned no surface structure biome at block "
+ blockX + "," + blockZ);
}
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, irisBiome.getVanillaDerivative());
Holder<Biome> holder = resolveBiomeHolder(biomeRegistry, irisBiome.getStructureDerivativeKey());
if (holder == null) {
throw new IllegalStateException("Iris structure biome derivative '"
+ irisBiome.getVanillaDerivativeKey() + "' is not registered at block "
+ irisBiome.getStructureDerivativeKey() + "' is not registered at block "
+ blockX + "," + blockZ);
}
return holder;
@@ -371,10 +371,11 @@ public class CustomBiomeSource extends BiomeSource {
+ x + "," + y + "," + z);
}
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, resolution.irisBiome.getVanillaDerivative());
Holder<Biome> holder = resolveBiomeHolder(
biomeRegistry, resolution.irisBiome.getStructureDerivativeKey());
if (holder == null) {
throw new IllegalStateException("Iris structure biome derivative '"
+ resolution.irisBiome.getVanillaDerivativeKey() + "' is not registered at block "
+ resolution.irisBiome.getStructureDerivativeKey() + "' is not registered at block "
+ resolution.blockX + "," + resolution.blockY + "," + resolution.blockZ);
}
return holder;
@@ -505,6 +506,17 @@ public class CustomBiomeSource extends BiomeSource {
return optionalReferenceHolder.get();
}
private static Holder<Biome> resolveBiomeHolder(Registry<Biome> registry, String biomeKey) {
if (registry == null || biomeKey == null || biomeKey.isBlank()) {
return null;
}
Identifier identifier = Identifier.tryParse(biomeKey);
if (identifier == null) {
return null;
}
return registry.get(ResourceKey.create(Registries.BIOME, identifier)).orElse(null);
}
private static Holder<Biome> resolveFallbackBiome(Registry<Biome> registry, Registry<Biome> customRegistry) {
Holder<Biome> plains = NMSBinding.biomeToBiomeBase(registry, org.bukkit.block.Biome.PLAINS);
if (plains != null) {
@@ -3,7 +3,6 @@ package art.arcane.iris.core.nms.v26_2_R1;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.IrisStructureLocator;
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
import art.arcane.iris.core.structure.NativeStructureLocateCapability;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisNativeStructureDecision;
import art.arcane.iris.engine.object.IrisStructureStiltSettings;
@@ -174,7 +173,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
String key = id.toString();
IrisNativeStructureDecision decision = NativeStructureGenerationPolicy.resolve(engine,
key, NativeStructurePostProcessor.isUndergroundStep(holder.value().step()));
if (NativeStructureLocateCapability.isPaperUnavailable(key) || !decision.generate()) {
if (!decision.generate()) {
continue;
}
candidates.add(new NativeLocateCandidate(holder, key));
@@ -0,0 +1,22 @@
package art.arcane.iris.core.nms.v26_2_R1;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class CustomBiomeSourceStructureContractTest {
@Test
public void nativeStructuresUseTerrainSafeDerivativeAtEveryBiomeBoundary() throws IOException {
String source = Files.readString(Path.of(System.getProperty("iris.customBiomeSource")));
assertTrue(source.contains("resolveBiomeHolder(registry, i.getStructureDerivativeKey())"));
assertTrue(source.contains("resolveBiomeHolder(biomeRegistry, irisBiome.getStructureDerivativeKey())"));
assertTrue(source.contains("resolution.irisBiome.getStructureDerivativeKey()"));
assertFalse(source.contains("resolution.irisBiome.getVanillaDerivative()"));
}
}
@@ -17,7 +17,7 @@ import static org.junit.Assert.assertSame;
public class IrisChunkGeneratorMonumentLocateContractTest {
@Test
public void nativeLocateAllowsExplicitReplacementBeforeNativeCapabilityGate() throws IOException {
public void nativeLocateAllowsMonumentsAfterPolicyAndReachabilityChecks() throws IOException {
String source = Files.readString(Path.of(System.getProperty("iris.nmsChunkGeneratorSource")));
int findStart = source.indexOf("findNearestMapStructure(ServerLevel level");
assertTrue(findStart >= 0);
@@ -42,9 +42,9 @@ public class IrisChunkGeneratorMonumentLocateContractTest {
int reachabilityStart = source.indexOf("private Set<String> reachableStructureKeys", filterStart);
assertTrue(reachabilityStart > filterStart);
String filterMethod = source.substring(filterStart, reachabilityStart);
int monumentReject = filterMethod.indexOf("if (NativeStructureLocateCapability.isPaperUnavailable(key)");
int rejectContinue = filterMethod.indexOf("continue;", monumentReject);
int emptyNativePartition = filterMethod.indexOf("if (candidates.isEmpty())", rejectContinue);
int policyFilter = filterMethod.indexOf("if (!decision.generate())");
int filterContinue = filterMethod.indexOf("continue;", policyFilter);
int emptyNativePartition = filterMethod.indexOf("if (candidates.isEmpty())", filterContinue);
int reachabilityLookup = filterMethod.indexOf("reachableStructureKeys(level)", emptyNativePartition);
assertTrue(policyResolution >= 0);
@@ -58,10 +58,11 @@ public class IrisChunkGeneratorMonumentLocateContractTest {
assertTrue(nativeFilter >= 0);
assertTrue(delegateLocate > nativeFilter);
assertTrue(nearestSelection > delegateLocate);
assertTrue(monumentReject >= 0);
assertTrue(rejectContinue > monumentReject);
assertTrue(emptyNativePartition > rejectContinue);
assertTrue(policyFilter >= 0);
assertTrue(filterContinue > policyFilter);
assertTrue(emptyNativePartition > filterContinue);
assertTrue(reachabilityLookup > emptyNativePartition);
assertFalse(filterMethod.contains("NativeStructureLocateCapability"));
assertFalse(irisHelper.contains("NativeStructureLocateCapability.isPaperUnavailable(structureId)"));
assertTrue(irisHelper.contains("new BlockPos(result.originX(), result.baseY(), result.originZ())"));
}
@@ -173,6 +173,24 @@ public class NativeStructurePostProcessorSurfaceTerrainTest {
assertEquals(Blocks.GRASS_BLOCK.defaultBlockState(), state(raised, 0, 68, 0));
}
@Test
public void raisedSurfaceTerrainDoesNotSliceTreeBlocks() {
Map<BlockPos, BlockState> blocks = new HashMap<>();
BlockState log = Blocks.OAK_LOG.defaultBlockState();
BlockState leaves = Blocks.OAK_LEAVES.defaultBlockState();
put(blocks, 0, 63, 0, Blocks.DIRT.defaultBlockState());
put(blocks, 0, 64, 0, Blocks.GRASS_BLOCK.defaultBlockState());
put(blocks, 0, 66, 0, log);
put(blocks, 0, 68, 0, leaves);
NativeStructurePostProcessor.applySurfaceColumn(
world(blocks), new BlockPos.MutableBlockPos(),
0, 0, 64, 68, -64, 319);
assertEquals(log, state(blocks, 0, 66, 0));
assertEquals(leaves, state(blocks, 0, 68, 0));
}
@Test
public void loweredFluidColumnsRemainFluidFilled() {
Map<BlockPos, BlockState> blocks = new HashMap<>();
@@ -266,11 +284,18 @@ public class NativeStructurePostProcessorSurfaceTerrainTest {
}
@Test
public void vegetationCleanupUsesTheSameCircularTaperAsTerrain() {
BoundingBox piece = new BoundingBox(0, 60, 0, 4, 80, 4);
public void templateAirDoesNotEraseTreesInsideVillagePieces() throws Exception {
BlockPos origin = new BlockPos(0, 80, 0);
StructureTemplate template = template(List.of(
new StructureTemplate.StructureBlockInfo(BlockPos.ZERO, Blocks.AIR.defaultBlockState(), null)));
StructurePlaceSettings settings = new StructurePlaceSettings().setRotation(Rotation.NONE);
Map<BlockPos, BlockState> blocks = new HashMap<>();
BlockState log = Blocks.OAK_LOG.defaultBlockState();
blocks.put(origin, log);
assertTrue(NativeStructurePostProcessor.withinSurfaceTerrainRadius(16, 2, piece, 12));
assertFalse(NativeStructurePostProcessor.withinSurfaceTerrainRadius(16, 16, piece, 12));
NativeStructurePostProcessor.clearTemplateAir(world(blocks), template, origin, 80, settings);
assertEquals(log, blocks.get(origin));
}
private static NativeStructurePostProcessor.SurfaceAnchor anchor(int meetY, int strength) {
@@ -27,8 +27,8 @@ public class NativeStructurePostProcessorVegetationTest {
}
@Test
public void surfaceStructuresClearTheirEntireFootprintByDefault() {
assertTrue(NativeStructurePostProcessor.shouldClearEntireVegetationFootprint(
public void surfaceStructuresPreserveVegetationUnlessConfigured() {
assertFalse(NativeStructurePostProcessor.shouldClearEntireVegetationFootprint(
GenerationStep.Decoration.SURFACE_STRUCTURES, false));
assertTrue(NativeStructurePostProcessor.shouldClearEntireVegetationFootprint(
GenerationStep.Decoration.SURFACE_STRUCTURES, true));