Skip to content

[1.18.2] GeologySampler disagrees with generated geology at 3D biome seams #266

Description

@SkyBlade1978

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-attribution

Run 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.replaceStoneInChunk obtains WORLD_SURFACE_WG, reads the biome at (x, surfaceY, z), then calls classifyColumn once for the generated column (GeomeGeology.java, approximately lines 89-112).
  • OreSpawnGeologySampler.sampleColumn reads the biome at the caller-supplied (x, surfaceY, z) and passes it to GeomeGeology.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

  1. During an integrated fixed-seed generation test, record the biome key, geome and predicted rocks used by replaceStoneInChunk for selected columns.
  2. After chunk completion, call GeologySampler.sampleColumn with the same (x, z, WORLD_SURFACE_WG) and assert identical biome/geome/rock predictions across representative Y values.
  3. Include a column where the biome at ore Y differs from the biome at surface Y.
  4. Repeat after saving and reopening the world.
  5. 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 GeologySampler output 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 focusedexplicitorehostattributionaudit reports 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions