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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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