Measure single-chunk ore transition
This commit is contained in:
parent
798016b055
commit
a2ee6f6a8f
1 changed files with 113 additions and 0 deletions
|
|
@ -2,6 +2,7 @@ package world
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -324,6 +325,118 @@ func TestRegionOreFeatureContributionDiagnostic(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSingleChunkScheduledOreParityDiagnostic(t *testing.T) {
|
||||||
|
if os.Getenv("REGIONIO_SINGLE_CHUNK_ORE_DIAGNOSTIC") != "1" {
|
||||||
|
t.Skip("set REGIONIO_SINGLE_CHUNK_ORE_DIAGNOSTIC=1 to measure the transition ore path")
|
||||||
|
}
|
||||||
|
fixtures, seed := loadOreFixtureChunks(t)
|
||||||
|
od, err := worldgen.LoadOverworldFinalDensity(seed)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fluidPicker := worldgen.OverworldFluidPicker(od.SeaLevel)
|
||||||
|
veins := worldgen.NewOreVeinifier(od)
|
||||||
|
carver, err := worldgen.NewCarver(od, seed)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
initCarverReplaceable(carver.ReplaceableBlocks())
|
||||||
|
var exact, total, oreMismatches int
|
||||||
|
for _, fixture := range fixtures {
|
||||||
|
chunk := generateVanillaWithoutDecoration(od, fluidPicker, veins, carver, seed, fixture.x, fixture.z)
|
||||||
|
if err := placeScheduledOresInChunk(chunk, seed); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for index, want := range fixture.blocks {
|
||||||
|
y := MinY + index/(16*16)
|
||||||
|
column := index % (16 * 16)
|
||||||
|
z, x := column/16, column%16
|
||||||
|
got := chunk.GetBlock(x, y, z)
|
||||||
|
total++
|
||||||
|
if got == want {
|
||||||
|
exact++
|
||||||
|
} else if isOreState(got) || isOreState(want) {
|
||||||
|
oreMismatches++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("single-chunk scheduled ore block exact %d/%d (%.3f%%), ore mismatches %d", exact, total, percent(exact, total), oreMismatches)
|
||||||
|
}
|
||||||
|
|
||||||
|
func placeScheduledOresInChunk(c *Chunk, seed int64) error {
|
||||||
|
set, err := worldgen.LoadFeatureSet()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
schedule, err := set.FeatureSchedule(possibleBiomeOrder(), chunkBiomeNames(c), undergroundOresStage)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
random, decorationSeed := worldgen.DecorationRandom(seed, int(c.X), int(c.Z))
|
||||||
|
origin := worldgen.FeaturePosition{X: int(c.X) << 4, Y: MinY, Z: int(c.Z) << 4}
|
||||||
|
context := worldgen.PlacementContext{MinY: MinY, Height: WorldHeight}
|
||||||
|
for _, scheduled := range schedule {
|
||||||
|
placed := set.Placed[scheduled.Name]
|
||||||
|
if set.Configured[placed.Feature].Type != "minecraft:ore" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
config, err := set.Ore(placed.Feature)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
targets, ok := resolveOreTargets(set, config)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
random.SetFeatureSeed(decorationSeed, scheduled.Index, undergroundOresStage)
|
||||||
|
context.BiomeAllows = func(position worldgen.FeaturePosition) bool {
|
||||||
|
if int32(position.X>>4) != c.X || int32(position.Z>>4) != c.Z || position.Y < MinY || position.Y >= MinY+WorldHeight {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return biomeHasFeature(set, c.GetBiome(position.X&15, position.Y, position.Z&15), undergroundOresStage, scheduled.Name)
|
||||||
|
}
|
||||||
|
if err := set.ForEachPlacementPosition(scheduled.Name, random, origin, context, func(position worldgen.FeaturePosition) error {
|
||||||
|
placeOreEllipsoid(c, random, position.X, position.Y, position.Z, config.Size, config.DiscardAirExposure, targets)
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("place %s: %w", scheduled.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func chunkBiomeNames(c *Chunk) []string {
|
||||||
|
seen := make(map[uint16]bool)
|
||||||
|
var names []string
|
||||||
|
for si := 0; si < SectionCount; si++ {
|
||||||
|
for bx := 0; bx < biomeCellsXZ; bx++ {
|
||||||
|
for by := 0; by < biomeCellsXZ; by++ {
|
||||||
|
for bz := 0; bz < biomeCellsXZ; bz++ {
|
||||||
|
id := c.GetBiome(bx*biomeCellSize, MinY+si*16+by*biomeCellSize, bz*biomeCellSize)
|
||||||
|
if !seen[id] {
|
||||||
|
seen[id] = true
|
||||||
|
names = append(names, biomeNameByID(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func biomeHasFeature(set *worldgen.FeatureSet, biomeID uint16, stage int, feature string) bool {
|
||||||
|
biome, ok := set.Biomes[biomeNameByID(biomeID)]
|
||||||
|
if !ok || stage < 0 || stage >= len(biome.Features) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, name := range biome.Features[stage] {
|
||||||
|
if name == feature {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type oreFixtureChunk struct {
|
type oreFixtureChunk struct {
|
||||||
x, z int32
|
x, z int32
|
||||||
blocks []uint16
|
blocks []uint16
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue