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%.
86 lines
2.9 KiB
Go
86 lines
2.9 KiB
Go
package world
|
|
|
|
import "testing"
|
|
|
|
// Ore-vein block states, from OreVeinifier.VeinType. Copper's ore is the plain
|
|
// stone variant and iron's is the deepslate one; neither switches with depth.
|
|
const (
|
|
StateGranite uint16 = 2
|
|
StateDeepslateIronOre uint16 = 132
|
|
StateTuff uint16 = 23452
|
|
StateCopperOre uint16 = 25313
|
|
StateRawIronBlock uint16 = 29577
|
|
StateRawCopperBlock uint16 = 29578
|
|
)
|
|
|
|
// TestOreVeins checks the mega-veins the noise router has always described and
|
|
// nothing has ever read: copper in granite between y=0 and y=50, iron in tuff
|
|
// between y=-60 and y=-8, with a rare raw-ore block inside each.
|
|
//
|
|
// The Y windows are the sharpest assertion available. A vein's type comes from
|
|
// the sign of the veininess noise but its window comes from the type, so a
|
|
// single block outside a window means the guard is wrong.
|
|
func TestOreVeins(t *testing.T) {
|
|
gen := NewVanillaGenerator(12345)
|
|
counts := map[uint16]int{}
|
|
lowest := map[uint16]int{}
|
|
highest := map[uint16]int{}
|
|
interesting := []uint16{StateCopperOre, StateRawCopperBlock, StateGranite,
|
|
StateDeepslateIronOre, StateRawIronBlock, StateTuff}
|
|
isVein := map[uint16]bool{}
|
|
for _, id := range interesting {
|
|
isVein[id] = true
|
|
}
|
|
for cx := int32(-60); cx <= 60; cx += 20 {
|
|
for cz := int32(-60); cz <= 60; cz += 20 {
|
|
ch := gen(cx, cz)
|
|
for wy := MinY; wy < 60; wy++ {
|
|
for lx := 0; lx < 16; lx++ {
|
|
for lz := 0; lz < 16; lz++ {
|
|
b := ch.GetBlock(lx, wy, lz)
|
|
if !isVein[b] {
|
|
continue
|
|
}
|
|
if counts[b] == 0 {
|
|
lowest[b], highest[b] = wy, wy
|
|
}
|
|
counts[b]++
|
|
lowest[b] = min(lowest[b], wy)
|
|
highest[b] = max(highest[b], wy)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, c := range []struct {
|
|
state uint16
|
|
name string
|
|
minY, maxY int
|
|
wantAtLeast int
|
|
}{
|
|
{StateCopperOre, "copper ore", 0, 50, 50},
|
|
{StateGranite, "copper vein filler", 0, 50, 100},
|
|
{StateDeepslateIronOre, "deepslate iron ore", -60, -8, 50},
|
|
{StateTuff, "iron vein filler", -60, -8, 100},
|
|
} {
|
|
if counts[c.state] < c.wantAtLeast {
|
|
t.Errorf("%s: %d blocks, want at least %d", c.name, counts[c.state], c.wantAtLeast)
|
|
continue
|
|
}
|
|
if lowest[c.state] < c.minY || highest[c.state] > c.maxY {
|
|
t.Errorf("%s spans y %d..%d, outside its window %d..%d",
|
|
c.name, lowest[c.state], highest[c.state], c.minY, c.maxY)
|
|
}
|
|
}
|
|
t.Logf("copper %d (raw %d) in granite %d; iron %d (raw %d) in tuff %d",
|
|
counts[StateCopperOre], counts[StateRawCopperBlock], counts[StateGranite],
|
|
counts[StateDeepslateIronOre], counts[StateRawIronBlock], counts[StateTuff])
|
|
|
|
// A raw-ore block replaces an ore block with probability 0.02, so a few
|
|
// hundred ore blocks should turn up a handful. Zero means the third draw is
|
|
// never reached.
|
|
if counts[StateRawCopperBlock]+counts[StateRawIronBlock] == 0 {
|
|
t.Error("no raw ore blocks anywhere; the raw-ore roll is unreachable")
|
|
}
|
|
}
|