diff --git a/internal/world/ore_schedule_diagnostic_test.go b/internal/world/ore_schedule_diagnostic_test.go index 0d23228..31b9ebd 100644 --- a/internal/world/ore_schedule_diagnostic_test.go +++ b/internal/world/ore_schedule_diagnostic_test.go @@ -2,8 +2,10 @@ package world import ( "os" + "sort" "testing" + "regionio/internal/registry" "regionio/internal/worldgen" ) @@ -51,6 +53,48 @@ func TestOreScheduleDiagnostic(t *testing.T) { } } +func TestOreFeatureOrderDiagnostic(t *testing.T) { + if os.Getenv("REGIONIO_ORE_ORDER_DIAGNOSTIC") != "1" { + t.Skip("set REGIONIO_ORE_ORDER_DIAGNOSTIC=1 to compare biome orders") + } + set := mustFeatureSet(t) + orders := map[string][]string{ + "climate": append([]string(nil), possibleBiomeOrder()...), + "sorted": sortedBiomeNames(set), + "registry": registryBiomeOrder(), + } + for _, label := range []string{"climate", "registry", "sorted"} { + steps, err := set.FeatureSteps(orders[label]) + if err != nil { + t.Fatalf("%s order: %v", label, err) + } + for index, name := range steps[undergroundOresStage] { + placed := set.Placed[name] + if set.Configured[placed.Feature].Type == "minecraft:ore" { + t.Logf("%s %s=%d", label, name, index) + } + } + } +} + +func sortedBiomeNames(set *worldgen.FeatureSet) []string { + names := make([]string, 0, len(set.Biomes)) + for name := range set.Biomes { + names = append(names, name) + } + sort.Strings(names) + return names +} + +func registryBiomeOrder() []string { + for _, synced := range registry.Synced() { + if synced.Name == "minecraft:worldgen/biome" { + return append([]string(nil), synced.Entries...) + } + } + return nil +} + func localFeatureIndices(set *worldgen.FeatureSet, biomes []string, stage int, feature string) map[string]int { indices := make(map[string]int) for _, biomeName := range biomes { diff --git a/internal/world/region_ore_parity_test.go b/internal/world/region_ore_parity_test.go index 918400f..c425ca0 100644 --- a/internal/world/region_ore_parity_test.go +++ b/internal/world/region_ore_parity_test.go @@ -169,6 +169,69 @@ func TestRegionOreFeatureIndexDiagnostic(t *testing.T) { } } +func TestRegionOreBiomeOrderDiagnostic(t *testing.T) { + if os.Getenv("REGIONIO_ORE_ORDER_PARITY_DIAGNOSTIC") != "1" { + t.Skip("set REGIONIO_ORE_ORDER_PARITY_DIAGNOSTIC=1 to compare biome orders against the fixture") + } + 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()) + set := mustFeatureSet(t) + orders := map[string][]string{ + "climate": possibleBiomeOrder(), + "registry": registryBiomeOrder(), + "sorted": sortedBiomeNames(set), + } + clayState, ok := nameToStateID("minecraft:clay", nil) + if !ok { + t.Fatal("minecraft:clay state missing") + } + for _, label := range []string{"climate", "registry", "sorted"} { + mismatches, clayMismatches := 0, 0 + for _, fixture := range fixtures { + var chunks []*Chunk + for cx := fixture.x - 1; cx <= fixture.x+1; cx++ { + for cz := fixture.z - 1; cz <= fixture.z+1; cz++ { + chunks = append(chunks, generateVanillaWithoutDecoration(od, fluidPicker, veins, carver, seed, cx, cz)) + } + } + region, err := newDecorationRegion(chunks) + if err != nil { + t.Fatal(err) + } + if err := region.setSource(fixture.x, fixture.z); err != nil { + t.Fatal(err) + } + if err := region.placeScheduledOresWithOrder(seed, orders[label], 0); err != nil { + t.Fatal(err) + } + chunk := region.chunks[[2]int32{fixture.x, fixture.z}] + 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) + if got != want { + mismatches++ + if got == clayState || want == clayState { + clayMismatches++ + } + } + } + } + t.Logf("%s biome order: block mismatches %d, clay mismatches %d", label, mismatches, clayMismatches) + } +} + type oreFixtureChunk struct { x, z int32 blocks []uint16 diff --git a/internal/world/region_ores.go b/internal/world/region_ores.go index 4a216ca..fc105a4 100644 --- a/internal/world/region_ores.go +++ b/internal/world/region_ores.go @@ -3,15 +3,22 @@ package world import "regionio/internal/worldgen" func (r *decorationRegion) placeScheduledOres(seed int64) error { - return r.placeScheduledOresAtOffset(seed, 0) + return r.placeScheduledOresWithOrder(seed, possibleBiomeOrder(), 0) } func (r *decorationRegion) placeScheduledOresAtOffset(seed int64, featureIndexOffset int) error { + return r.placeScheduledOresWithOrder(seed, possibleBiomeOrder(), featureIndexOffset) +} + +func (r *decorationRegion) placeScheduledOresWithOrder(seed int64, biomeOrder []string, featureIndexOffset int) error { set, err := worldgen.LoadFeatureSet() if err != nil { return err } - schedule, err := r.scheduledFeatures(undergroundOresStage) + if err := r.ensureSourceNeighborhood(); err != nil { + return err + } + schedule, err := set.FeatureSchedule(biomeOrder, r.sourceBiomes(), undergroundOresStage) if err != nil { return err }