Repository navigation
[1.18.2] GeologySampler disagrees with generated geology at 3D biome seams #266
Description
Summary
On the local OreSpawn 4.0.11.118021 candidate, the public GeologySampler can disagree with the geology actually generated for the same (x, z) column and WORLD_SURFACE_WG height at a 3D biome seam.
CakeWorld found a cakeworld:mint_crystal that OreSpawn could only have placed into its exact cakeworld:peppermint_rock host. The surrounding generated rock confirms Peppermint Rock, but GeologySampler.sampleColumn(x, z, surfaceY) predicts cakeworld:biscuit_stone for that position. Sampling the runtime biome at ore Y instead resolves the Peppermint geome/rock, showing a vertical biome seam, but the public API and OreSpawn's column-generation contract both classify one column from the surface biome.
This is the only remaining failure in CakeWorld's 274-test fixed-seed suite. The earlier dynamic-biome issues #262 and #263 pass on this candidate.
Environment
- Minecraft 1.18.2
- Forge 40.3.0
- OreSpawn version:
4.0.11.118021(local candidate; not yet published) - Local branch:
feature/1.18.2-4.0.11-dynamic-biomes - Local commit:
e478d926dcd764e05fa0f286fe23276ea17b2b18 - Tested JAR SHA-256:
E012F1CDC2DCBE387BD72EE337197803DE0CA30A8205D20CB9ACDF722F9EC5BB - Integrated test mod: CakeWorld
- CakeWorld branch/HEAD:
master-1.18.2/0a3fb0dd6788d2fcad78f82d20154a772ff93d05 - Fixed world seed:
5059928472718672684 - Template:
cakeworld:edible_world
Provider rule that exposes the mismatch
CakeWorld's Mint Crystal uses a strict explicit host and cannot replace Biscuit Stone:
"cakeworld:ore/mint_crystal": {
"block": "cakeworld:mint_crystal",
"deep_output": "cakeworld:rock_candy_deposit",
"deep_output_max_y": -24,
"enabled": true,
"dimensions": {
"minecraft:overworld": {
"enabled": true,
"min_y": -56,
"max_y": 80,
"frequency": 1.0,
"quantity": 5,
"pattern": {
"type": "orespawn:precision",
"settings": {
"spread": 4,
"vertical_spread": 3,
"node_size": 2,
"length": 8
}
},
"height_distribution": "bottom_triangle",
"discard_chance_on_air_exposure": 0.65,
"host_blocks": ["cakeworld:peppermint_rock"],
"geomes": {
"cakeworld:peppermint_fold": 5.0,
"cakeworld:rock_candy_uplift": 2.5,
"cakeworld:cocoa_basin": 0.0
}
}
}
}Integrated reproduction
Build the local OreSpawn candidate, then from the CakeWorld 1.18.2 checkout run the suite against a new, unused run directory:
$env:JAVA_HOME='C:\Users\johnb\.jdks\temurin-17.0.1+12\jdk-17.0.1+12'
$env:Path="$env:JAVA_HOME\bin;$env:Path"
$env:GRADLE_USER_HOME='D:\CakeWorld\.gradle-verify-cache'
.\gradlew.bat runGameTestServer --no-daemon `
'-PcakeworldLocalOreSpawnJar=D:\MinecraftMineralogy\OS118\OreSpawn\build\libs\OreSpawn-4.0.11.118021.jar' `
-PcakeworldFreshWorldgenRuntime=true `
-PcakeworldFreshWorldgenRunDirectory=run-fresh-worldgen-os411-host-attributionRun the same command unchanged a second time for saved-world reload proof. The focused failing test is focusedexplicitorehostattributionaudit.
The audit preloads all surveyed chunks before creating the sampler, so this is not a stale dynamic-ID learning problem.
Expected
For a generated column, GeologySampler.sampleColumn(x, z, WORLD_SURFACE_WG).rockAt(y) should reproduce the pre-ore geology that OreSpawn used when generating that same column. A strict-host OreSpawn output should therefore agree with the sampler's predicted host at its Y coordinate, on both fresh generation and reload.
Actual
The fixed-seed audit observes 123 Mint Crystal outputs and two sampler disagreements. The first is:
position: BlockPos{x=-2536, y=-1, z=-892}
output: cakeworld:mint_crystal
WORLD_SURFACE_WG: 97
surface biome: cakeworld:candy_plains
surface geome: cakeworld:cocoa_basin
surface prediction: cakeworld:biscuit_stone
ore-Y biome: cakeworld:marshmallow_peaks
ore-Y geome: cakeworld:peppermint_fold
ore-Y prediction: cakeworld:peppermint_rock
neighbors:
down: cakeworld:peppermint_rock
up: cakeworld:peppermint_rock
north: cakeworld:biscuit_stone
south: cakeworld:mint_crystal
west: cakeworld:peppermint_rock
east: cakeworld:biscuit_stone
The final integrated result is:
274 GAME TESTS COMPLETE
1 required test failed:
- focusedexplicitorehostattributionaudit
The same mismatch was observed in the initial fresh-world pass and repeated saved-world reload passes.
Suspected source seam
The current local candidate has matching-looking entry points that nevertheless produce different results:
GeomeGeology.replaceStoneInChunkobtainsWORLD_SURFACE_WG, reads the biome at(x, surfaceY, z), then callsclassifyColumnonce for the generated column (GeomeGeology.java, approximately lines 89-112).OreSpawnGeologySampler.sampleColumnreads the biome at the caller-supplied(x, surfaceY, z)and passes it toGeomeGeology.sampleColumn(OreSpawnGeologySampler.java, approximately lines 58-67).- The public API documentation says this samples “exact production geology” and performs one biome/geome classification reused for every Y query (
docs/API.md, approximately lines 117-131).
At runtime, the sampler's surface lookup is Candy Plains/Cocoa Basin, while the generated Peppermint Rock and exact-host Mint Crystal show that the effective generation classification was Peppermint Fold. The ore-Y biome is Marshmallow Peaks/Peppermint Fold.
This suggests the surface biome/classification seen during terrain generation is not stable or equivalent to the later public sampler around a vertical biome boundary. Dynamic biome wrapping, lookup timing, or cached classification state may be involved; that is an inference from the integrated evidence, not yet a proven root cause.
Suggested regression coverage
- During an integrated fixed-seed generation test, record the biome key, geome and predicted rocks used by
replaceStoneInChunkfor selected columns. - After chunk completion, call
GeologySampler.sampleColumnwith the same(x, z, WORLD_SURFACE_WG)and assert identical biome/geome/rock predictions across representative Y values. - Include a column where the biome at ore Y differs from the biome at surface Y.
- Repeat after saving and reopening the world.
- Run with dynamic-registry custom biomes so the [1.18.2] Geome ID fallback drops biome-dictionary weights for dynamic biomes #262/[1.18.2] Ore biome filters reject dynamic-registry biomes by object identity #263 paths remain covered.
Acceptance criteria
- Public
GeologySampleroutput agrees with the geology actually generated for the same column and surface Y. - Agreement holds at vertical biome seams and for dynamic-registry custom biomes.
- Fresh generation and saved-world reload produce the same sampler attribution.
- CakeWorld's
focusedexplicitorehostattributionauditreports 123+ outputs with zero violations. - The fix keeps biome/geome classification baked and avoids registry lookup, configuration reads, logging, string construction, or avoidable allocation inside the terrain-generation hot path.
Activity
SkyBlade1978 commentedon Aug 29, 2026
Local CakeWorld verification is now green against the proposed OreSpawn fix.
Tested OreSpawn candidate:
feature/1.18.2-4.0.12-geology-sampler7c82ecc844ae9d241a108f4417c6c3b5b0bc29a2OreSpawn-4.0.12.118021.jar0478D611A96020DAAE794B72E64EFD677B49A5B63BCB6179330D63317B16D6A6CakeWorld results using that exact JAR:
outputs=123, violations=0counts={}in all three; bedrock is the explicit exception)This locally verifies the fix for the reported seam/sampler mismatch. I have left the issue open for the OreSpawn maintainer/coding agent to merge and publish the candidate through the normal release process.
SkyBlade1978 commentedon Aug 29, 2026
Correction to my earlier green result: a stricter family-host attribution regression still reproduces a deep sampler mismatch against the same exact 4.0.12 candidate.
Candidate:
Focused CakeWorld GameTest:
Fresh result:
Same-save reload reproduced the identical counts and the identical two deep violations.
Violations:
The current public contract says sampleColumn should receive the first-free result of Level.getHeight, subtracts one, and exactly matches chunk generation. StoneReplacer chooses its biome using the generation-time WORLD_SURFACE_WG height, but the final WORLD_SURFACE_WG height can be changed by later surface/decoration work. The public caller therefore cannot always reconstruct the generation-time column identity from the final Level height. OCEAN_FLOOR_WG happens to recover the expected identity for these two cells, but that is not the documented contract and should not be assumed generally.
Acceptance expectation: after world generation and after reload, the documented public sampler path must reproduce the biome/geome/geology classification actually used by StoneReplacer for deep natural cells, with zero family-host attribution mismatches. If a final caller-supplied height cannot guarantee that, the API needs an overload or another stable input/lookup that does. The issue should remain open; the previous 274-test green result did not exercise this stricter family-host invariant.
SkyBlade1978 commentedon Sep 9, 2026
Closing as completed. The remaining family-host attribution seam was resolved by the 4.0.15 portion of
4.0.16.118021in #270. Chunk geology and the public sampler now share the same direct quart/noise-biome lookup, with explicit stable biome IDs taking precedence over object aliases.The corrected fresh/reload regression reports zero generated-geology, sampler and family-host mismatches at 3D biome edges. The fix is merged on every target with three-dimensional biome attribution; older two-dimensional biome systems were explicitly audited as not applicable.