Ore veins from the noise router
The router has carried vein_toggle, vein_ridged and vein_gap since the whole of it was parsed, and nothing read them. So the copper and iron mega-veins -- the long branching sheets that run through the deepslate and the copper band, not the small scattered ore blobs -- did not exist. OreVeinifier is not a decoration feature. It is the second entry of the same MaterialRuleList the aquifer heads: the aquifer answers first, and only where it says the position is solid rock does the veinifier get a turn at what would otherwise be plain stone. That is why a vein never opens into a cave, and it is why this lands in the density pass rather than in decorate. Three random draws per position, in a fixed order, from a factory hashed off "minecraft:ore": solidness, then richness, then the rare raw-ore block. Reordering them or hoisting the vein_gap compute above the second draw would change every vein in the world, so the code follows the bytecode's order rather than the one that reads better. The Y windows are the sharp edge worth knowing about: a vein's type comes from the sign of the veininess noise, but its window comes from the type, so veininess <= 0 anywhere outside -60..-8 is simply not a vein. Over 49 sampled chunks copper lands in 0..49 and iron in -57..-8, and raw ore comes out at 1.9% of ore blocks against vanilla's 2%.
This commit is contained in:
parent
e0fdddd887
commit
0f76058db6
5 changed files with 220 additions and 15 deletions
|
|
@ -31,12 +31,13 @@ func NewVanillaGenerator(seed int64) Generator {
|
|||
panic("world: loading overworld density: " + err.Error())
|
||||
}
|
||||
fluidPicker := worldgen.OverworldFluidPicker(od.SeaLevel)
|
||||
veins := worldgen.NewOreVeinifier(od)
|
||||
return func(cx, cz int32) *Chunk {
|
||||
return generateVanilla(od, fluidPicker, seed, cx, cz)
|
||||
return generateVanilla(od, fluidPicker, veins, seed, cx, cz)
|
||||
}
|
||||
}
|
||||
|
||||
func generateVanilla(od *worldgen.OverworldDensity, fluidPicker worldgen.FluidPicker, seed int64, cx, cz int32) *Chunk {
|
||||
func generateVanilla(od *worldgen.OverworldDensity, fluidPicker worldgen.FluidPicker, veins *worldgen.OreVeinifier, seed int64, cx, cz int32) *Chunk {
|
||||
c := NewChunk(cx, cz, BiomePlains) // per-cell biomes override below
|
||||
baseX, baseZ := int(cx)*16, int(cz)*16
|
||||
|
||||
|
|
@ -108,7 +109,7 @@ func generateVanilla(od *worldgen.OverworldDensity, fluidPicker worldgen.FluidPi
|
|||
interp := make([]float64, len(od.Interpolated))
|
||||
for lz := 0; lz < 16; lz++ {
|
||||
surfTop[lx][lz], worldSurface[lx][lz], grass[lx][lz] =
|
||||
fillVanillaColumn(od, aq, fluidPicker, grids, interp, &columns[lx][lz], baseX+lx, baseZ+lz, lx, lz)
|
||||
fillVanillaColumn(od, aq, fluidPicker, veins, grids, interp, &columns[lx][lz], baseX+lx, baseZ+lz, lx, lz)
|
||||
}
|
||||
}(lx)
|
||||
}
|
||||
|
|
@ -189,7 +190,7 @@ func fillBiomes3D(c *Chunk, od *worldgen.OverworldDensity, s2D [16][16]worldgen.
|
|||
// then does the surface rule tree walk the finished column. Doing it the other
|
||||
// way round is what forced the old unconditional "flood everything under sea
|
||||
// level" pass, which left every cave below y=63 underwater.
|
||||
func fillVanillaColumn(od *worldgen.OverworldDensity, aq *worldgen.Aquifer, fluidPicker worldgen.FluidPicker, grids []cornerGrid, interp []float64, out *[WorldHeight]uint16, wx, wz, lx, lz int) (top, worldSurface int, grass bool) {
|
||||
func fillVanillaColumn(od *worldgen.OverworldDensity, aq *worldgen.Aquifer, fluidPicker worldgen.FluidPicker, veins *worldgen.OreVeinifier, grids []cornerGrid, interp []float64, out *[WorldHeight]uint16, wx, wz, lx, lz int) (top, worldSurface int, grass bool) {
|
||||
cx0 := lx / cellWidth
|
||||
cz0 := lz / cellWidth
|
||||
fx := float64(lx%cellWidth) / cellWidth
|
||||
|
|
@ -205,9 +206,9 @@ func fillVanillaColumn(od *worldgen.OverworldDensity, aq *worldgen.Aquifer, flui
|
|||
y := MinY + i
|
||||
ctx := worldgen.FunctionContext{X: float64(wx), Y: float64(y), Z: float64(wz)}.WithInterp(interp)
|
||||
density := od.Final.Compute(ctx)
|
||||
state, isDefaultBlock := substance(aq, fluidPicker, wx, y, wz, density)
|
||||
state, solid := substance(aq, fluidPicker, veins, ctx, wx, y, wz, density)
|
||||
out[i] = state
|
||||
if isDefaultBlock {
|
||||
if solid {
|
||||
top = i
|
||||
}
|
||||
if state != StateAir {
|
||||
|
|
@ -239,23 +240,35 @@ func steepAt(worldSurface *[16][16]int, lx, lz int) bool {
|
|||
return worldSurface[west][lz] >= worldSurface[east][lz]+4
|
||||
}
|
||||
|
||||
// substance resolves one position to the block the terrain pass leaves behind:
|
||||
// the default block where the density is solid, otherwise whatever the aquifer
|
||||
// puts there — air, water or lava. The second result says which of the two
|
||||
// happened, so the caller can track the top solid block without re-testing.
|
||||
func substance(aq *worldgen.Aquifer, fluidPicker worldgen.FluidPicker, x, y, z int, density float64) (state uint16, isDefaultBlock bool) {
|
||||
// substance resolves one position to the block the terrain pass leaves behind,
|
||||
// mirroring vanilla's MaterialRuleList: the aquifer answers first and, where it
|
||||
// says the position is solid rock, the ore veinifier gets a turn before the
|
||||
// default block is used. The second result says whether the position ended up
|
||||
// solid, so the caller can track the top solid block without re-testing.
|
||||
func substance(aq *worldgen.Aquifer, fluidPicker worldgen.FluidPicker, veins *worldgen.OreVeinifier, ctx worldgen.FunctionContext, x, y, z int, density float64) (state uint16, solid bool) {
|
||||
if aq == nil {
|
||||
// aquifers_enabled=false: Aquifer.createDisabled, the global fluid rule
|
||||
// with no cells and no barriers.
|
||||
if density > 0 {
|
||||
return StateStone, true
|
||||
return veinOrDefault(veins, ctx, x, y, z), true
|
||||
}
|
||||
return fluidPicker(x, y, z).At(y), false
|
||||
}
|
||||
if s, ok := aq.ComputeSubstance(x, y, z, density); ok {
|
||||
return s, false
|
||||
}
|
||||
return StateStone, true
|
||||
return veinOrDefault(veins, ctx, x, y, z), true
|
||||
}
|
||||
|
||||
// veinOrDefault is the tail of the rule list: an ore vein if one reaches here,
|
||||
// otherwise the settings' default block.
|
||||
func veinOrDefault(veins *worldgen.OreVeinifier, ctx worldgen.FunctionContext, x, y, z int) uint16 {
|
||||
if veins != nil {
|
||||
if s, ok := veins.Calculate(ctx, x, y, z); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return StateStone
|
||||
}
|
||||
|
||||
// applySurfaceRule walks the finished column from the top down, applying the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue