Hydrology Fix, and V+

This commit is contained in:
Brian Neumann-Fopiano
2026-09-15 23:01:56 -04:00
parent dfb3748059
commit 1e1eaa96aa
137 changed files with 8842 additions and 711 deletions
+1
View File
@@ -21,6 +21,7 @@ dependencies {
implementation(project(':core'))
compileOnly(libs.spigot)
testImplementation('junit:junit:4.13.2')
testImplementation(libs.gson)
testImplementation(testFixtures(project(':core')))
testImplementation(volmLibCoordinate) {
transitive = false
@@ -3078,7 +3078,7 @@ public final class HydrologyPackProbe {
deepCourses++;
}
}
for (HydrologyDiagnosticCandidate candidate : tile.diagnosticCandidates()) {
for (HydrologyDiagnosticCandidate candidate : runtime.diagnosticCandidates(tile.key())) {
RejectionKey rejection = new RejectionKey(
candidate.kind(),
candidate.projectedType(),
@@ -3738,7 +3738,6 @@ public final class HydrologyPackProbe {
surfaceBiome,
engine,
engine.getSeedManager().getBiome(),
engine.getDimension().getLoadKey(),
position.x(),
position.z()
);
@@ -3759,7 +3758,6 @@ public final class HydrologyPackProbe {
IrisBiome biome,
Engine engine,
long biomeSeed,
String dimensionKey,
int x,
int z
) {
@@ -3778,7 +3776,7 @@ public final class HydrologyPackProbe {
if (custom == null || custom.getId() == null || custom.getId().isBlank()) {
throw new IllegalStateException("Generated custom surface Iris biome resolved no custom biome id.");
}
return IrisDimension.customBiomeKey(dimensionKey, custom.getId());
return engine.getData().customBiomeResourceKey(engine.getDimension(), custom);
}
private static void verifyCaveWitness(
@@ -89,7 +89,7 @@ public final class HydrologyPlannerProbe {
warmTimings[seedIndex],
tile.courses().size(),
tile.features().size(),
tile.diagnosticCandidates().size(),
cache.diagnosticCandidates(tile.key()).size(),
counts
);
cache.close();
@@ -224,7 +224,8 @@ public final class RiverTransectProbe {
tile.cavePlan(course.id()).map((plan) -> plan.accepted() ? "accepted" : "rejected").orElse("none")));
}
for (String line : rejectionLines(tile)) {
List<HydrologyDiagnosticCandidate> diagnostics = runtime.diagnosticCandidates(key);
for (String line : rejectionLines(diagnostics)) {
System.out.println(PREFIX + " " + line);
}
writeTileDiagnostics(new File(configuration.output(), "tile-diagnostics.png"), tile, complex, runtime, seaLevel);
@@ -253,7 +254,7 @@ public final class RiverTransectProbe {
System.out.println(PREFIX + " " + detail);
}
}
writeSummary(new File(configuration.output(), "summary.txt"), configuration, tile, summaries);
writeSummary(new File(configuration.output(), "summary.txt"), configuration, tile, summaries, diagnostics);
boolean pass = !summaries.isEmpty() && summaries.stream().allMatch(CourseSummary::passes);
System.out.println(PREFIX + " " + (pass ? "PASS" : "FAIL")
+ " surfaceCourses=" + summaries.size()
@@ -262,10 +263,10 @@ public final class RiverTransectProbe {
}
}
static List<String> rejectionLines(HydrologyTile tile) {
static List<String> rejectionLines(List<HydrologyDiagnosticCandidate> candidates) {
TreeMap<String, Integer> counts = new TreeMap<>();
TreeMap<String, ArrayList<Integer>> details = new TreeMap<>();
for (HydrologyDiagnosticCandidate candidate : tile.diagnosticCandidates()) {
for (HydrologyDiagnosticCandidate candidate : candidates) {
String key = "rejected " + candidate.kind() + " " + candidate.projectedType() + " " + candidate.rejection();
counts.merge(key, 1, Integer::sum);
if (candidate.detail() != 0) {
@@ -652,7 +653,7 @@ public final class RiverTransectProbe {
}
}
}
for (HydrologyDiagnosticCandidate candidate : tile.diagnosticCandidates()) {
for (HydrologyDiagnosticCandidate candidate : runtime.diagnosticCandidates(tile.key())) {
int rgb = switch (candidate.rejection()) {
case NO_DRAINAGE_PATH -> 0xFF2020;
case COURSE_TOO_SHORT -> 0xFFB000;
@@ -846,7 +847,8 @@ public final class RiverTransectProbe {
File file,
Configuration configuration,
HydrologyTile tile,
List<CourseSummary> summaries
List<CourseSummary> summaries,
List<HydrologyDiagnosticCandidate> diagnostics
) throws IOException {
StringBuilder text = new StringBuilder();
text.append("tile=").append(tile.key().tileX()).append(',').append(tile.key().tileZ())
@@ -855,7 +857,7 @@ public final class RiverTransectProbe {
.append(" courses=").append(tile.courses().size())
.append(" surfaceCourses=").append(summaries.size())
.append('\n');
for (String line : rejectionLines(tile)) {
for (String line : rejectionLines(diagnostics)) {
text.append(line).append('\n');
}
int maximumCut = 0;
@@ -14,6 +14,10 @@ import art.arcane.iris.generation.hydrology.cave.CavePosition;
import art.arcane.iris.generation.hydrology.cave.HydrologyCaveAction;
import art.arcane.iris.generation.biome.IrisBiome;
import art.arcane.iris.generation.biome.IrisBiomeCustom;
import art.arcane.iris.generation.runtime.Engine;
import art.arcane.iris.generation.terrain.IrisDimension;
import art.arcane.iris.pack.loading.IrisData;
import art.arcane.iris.world.history.GenerationRegistryContractFactory;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.iris.spi.PlatformBiome;
import art.arcane.iris.spi.PlatformBlockState;
@@ -25,6 +29,7 @@ import org.junit.rules.TemporaryFolder;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.Proxy;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
@@ -37,6 +42,7 @@ import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -222,6 +228,7 @@ public final class HydrologyPackProbeTest {
List.of(),
List.of(),
List.of(),
Set.of(),
List.of(),
List.of(),
new RiverFootprint(Map.of(
@@ -265,7 +272,6 @@ public final class HydrologyPackProbeTest {
biome,
null,
19L,
"overworld",
32,
-48
)
@@ -273,21 +279,32 @@ public final class HydrologyPackProbeTest {
}
@Test
public void generatedCustomSurfaceBiomeUsesRecursiveDimensionRegistryPath() {
IrisBiome biome = new IrisBiome()
.setCustomDerivitives(new KList<>(new IrisBiomeCustom().setId("Aurora")));
public void generatedCustomSurfaceBiomeUsesPhysicalRegistryIdentity() throws Exception {
IrisData data = IrisData.openDatapackCompiler(temporaryFolder.newFolder("custom-biome-identity"));
IrisDimension dimension = new IrisDimension();
dimension.setLoadKey("layers/sky");
Engine engine = (Engine) Proxy.newProxyInstance(Engine.class.getClassLoader(), new Class<?>[]{Engine.class},
(proxy, method, arguments) -> switch (method.getName()) {
case "getData" -> data;
case "getDimension" -> dimension;
default -> throw new UnsupportedOperationException(method.getName());
});
try {
IrisBiomeCustom first = new IrisBiomeCustom().setId("aurora").setGrassColor("#114422");
IrisBiomeCustom second = new IrisBiomeCustom().setId("aurora").setGrassColor("#BBCCDD");
IrisBiome firstBiome = new IrisBiome().setCustomDerivitives(new KList<>(first));
IrisBiome secondBiome = new IrisBiome().setCustomDerivitives(new KList<>(second));
String firstKey = HydrologyPackProbe.generatedSurfaceBiomeKey(firstBiome, engine, 19L, 32, -48);
String secondKey = HydrologyPackProbe.generatedSurfaceBiomeKey(secondBiome, engine, 19L, 32, -48);
assertEquals(
"layers:sky/aurora",
HydrologyPackProbe.generatedSurfaceBiomeKey(
biome,
null,
19L,
"Layers/Sky",
32,
-48
)
);
assertEquals(GenerationRegistryContractFactory.customBiomeResourceKey("layers/sky", first), firstKey);
assertEquals(GenerationRegistryContractFactory.customBiomeResourceKey("layers/sky", second), secondKey);
assertTrue(firstKey.startsWith("iris:biomes/"));
assertNotEquals(IrisDimension.customBiomeKey("layers/sky", "aurora"), firstKey);
assertNotEquals(firstKey, secondKey);
} finally {
data.close();
}
}
@Test
@@ -16,14 +16,14 @@ public final class HydrologyPlannerProbeTest {
@Test
public void coastalFixturePublishesAnAcceptedOceanMouth() {
HydrologyTile tile = HydrologyPlannerProbe.surfaceMouthTile();
assertTrue(tile.diagnosticCandidates().stream().limit(16).toList().toString(),
assertTrue(tile.localDiagnosticCandidates().stream().limit(16).toList().toString(),
tile.features().stream().anyMatch(feature -> feature.type() == HydrologyFeatureType.MOUTH));
}
@Test
public void inlandFixturePublishesAContainedWaterfall() {
HydrologyTile tile = HydrologyPlannerProbe.surfaceWaterfallTile();
assertTrue(tile.diagnosticCandidates().stream().limit(16).toList().toString(),
assertTrue(tile.localDiagnosticCandidates().stream().limit(16).toList().toString(),
tile.features().stream().anyMatch(feature -> feature.type() == HydrologyFeatureType.WATERFALL));
assertTrue(tile.courses().stream().anyMatch(course -> course.segments().stream().anyMatch(segment -> segment.fallingFluid()
&& segment.type() == HydrologyFeatureType.WATERFALL)