world: port ruined portal generation point and expose pre-carve terrain

generateBaseTerrain now factors the noise+surface stage out of chunk
generation so structure placement can read pre-carve heights exactly
like vanilla's STRUCTURE_STARTS stage. RuinedPortalGenerationPoint
replays the ruined_portals set: the weighted pick across all seven
variants on its own stream, each attempt's setup/template/rotation/
mirror draws on a fresh GenerationContext stream (makeRandom reseeds
per attempt, confirmed from bytecode), findSuitableY with corner-column
settle scan against those heights, and the post-draw 3D-biome filter at
quart-snapped coordinates.

Known gap, documented in STRUCTURE_NOTES.md: no variant is accepted in
the window around the fixture's portal yet while vanilla placed one;
the biome/surface inputs need a vanilla-side probe to bisect. Not wired
into the production replay until that closes.
This commit is contained in:
Daniar Mannanov 2026-08-26 13:56:51 +03:00
parent 6e04bd8bbc
commit 798a3ec7b4
6 changed files with 454 additions and 31 deletions

View file

@ -112,6 +112,28 @@ func generateVanillaWithoutDecoration(od *worldgen.OverworldDensity, fluidPicker
}
func generateVanillaDecorated(od *worldgen.OverworldDensity, fluidPicker worldgen.FluidPicker, veins *worldgen.OreVeinifier, carver *worldgen.Carver, seed int64, cx, cz int32, withDecoration bool) *Chunk {
data := generateBaseTerrain(od, fluidPicker, veins, carver, seed, cx, cz)
c := data.c
surfTop, grass := data.surfTop, data.grass
if withDecoration {
decorate(c, od, cx, cz, seed, surfTop, grass, data.biomeName)
}
return c
}
// baseTerrain is everything the noise/surface/carve stages produce, kept
// together so structure placement can read pre-carve heights exactly the way
// vanilla's STRUCTURE_STARTS stage does.
type baseTerrain struct {
c *Chunk
columns *[16][16][WorldHeight]uint16
worldSurface *[16][16]int // topmost non-air Y before carving
surfTop *[16][16]int
grass *[16][16]bool
biomeName *[16][16]string
}
func generateBaseTerrain(od *worldgen.OverworldDensity, fluidPicker worldgen.FluidPicker, veins *worldgen.OreVeinifier, carver *worldgen.Carver, seed int64, cx, cz int32) baseTerrain {
c := NewChunk(cx, cz, BiomePlains) // per-cell biomes override below
baseX, baseZ := int(cx)*16, int(cz)*16
@ -240,10 +262,11 @@ func generateVanillaDecorated(od *worldgen.OverworldDensity, fluidPicker worldge
}
}
fillBiomes3D(c, od, s2D, baseX, baseZ)
if withDecoration {
decorate(c, od, cx, cz, seed, &surfTop, &grass, &biomeName)
return baseTerrain{
c: c, columns: &columns,
worldSurface: &worldSurface, surfTop: &surfTop,
grass: &grass, biomeName: &biomeName,
}
return c
}
// fillBiomes3D assigns a per-cell 4×4×4 biome to every section of the chunk.