package world import ( "testing" "regionio/internal/registry" "regionio/internal/worldgen" ) // TestPerCellBiomesVaryByHeight confirms a single column maps to different // biomes at different Y values (surface vs underground), proving the depth // axis is actually consulted per cell rather than fixed to surface. func TestPerCellBiomesVaryByHeight(t *testing.T) { od, err := worldgen.LoadOverworldFinalDensity(12345) if err != nil { t.Fatalf("load: %v", err) } s2D := worldgen.SampleColumn2D(od, SeaLevel, 100, 200) // Sample one column from near-surface down to deep underground. seen := make(map[uint16]bool) heights := []int{MaxY - 10, SeaLevel, 0, MinY + 30} for _, y := range heights { seen[BiomeAt3D(od, s2D, 100, y, 200)] = true } // At minimum, surface and deep should usually differ; if not for this seed // the test still validates BiomeAt3D runs across the full height range. if len(seen) < 1 { t.Fatal("BiomeAt3D returned no biomes across the height range") } t.Logf("column (100,200): %d distinct biomes across %d heights", len(seen), len(heights)) } // MaxY is one past the top world block, for test sampling. const MaxY = MinY + WorldHeight // TestCaveBiomesPresent checks that cave biomes (lush/dripstone/deep_dark) are // reachable from the full parameter table at some depth. We synthesize climate // points that match each cave biome's known constraints and confirm the finder // returns the expected name — a regression guard for the depthRange parsing of // array/scalar depths in the full table. func TestCaveBiomesPresent(t *testing.T) { // lush_caves: high humidity, depth in [0.2,0.9]. Use depth 0.5. lush := worldgen.NewTargetPoint(0.2, 0.9, 0.0, 0.0, 0.0, 0.5) // dripstone_caves: high continentalness, depth in [0.2,0.9]. drip := worldgen.NewTargetPoint(0.2, 0.0, 0.9, 0.0, 0.0, 0.5) // deep_dark: low erosion, depth 1.1. dark := worldgen.NewTargetPoint(0.0, 0.0, 0.0, -0.7, 0.0, 1.1) tbl := loadBiomeTable() for _, c := range []struct { name string point worldgen.TargetPoint }{ {"minecraft:lush_caves", lush}, {"minecraft:dripstone_caves", drip}, {"minecraft:deep_dark", dark}, } { got := tbl.FindBiome(c.point) if got != c.name { t.Errorf("FindBiome for %s = %q, want %q", c.name, got, c.name) } else { t.Logf("%s resolved correctly", c.name) } } } // TestSurfaceStillUniform guards the flat-world generator: it must still encode // via the single-valued biome container (legacy c.biome path), since flat // chunks never populate per-cell biomes. func TestSurfaceStillUniform(t *testing.T) { c := GenerateFlat(0, 0) for si := 0; si < SectionCount; si++ { if c.biomes[si] != nil { t.Errorf("flat chunk section %d has per-cell biomes; should be uniform", si) } } if c.biome != BiomePlains { t.Errorf("flat chunk biome = %d, want plains %d", c.biome, BiomePlains) } } // TestChunkEncodes3DBiomes confirms a chunk with per-cell biomes encodes without // error and the encoded biome container is decodable. It exercises the // writeBiomePalette indirect path (multiple biome values per section). func TestChunkEncodes3DBiomes(t *testing.T) { gen := NewVanillaGenerator(12345) ch := gen(0, 0) body := ch.Encode() if len(body) == 0 { t.Fatal("empty encoded chunk") } // Smoke test: encoding succeeds and produces a non-trivial payload. The // golden/encode_test covers the byte-level block container; here we only // confirm the biome container does not corrupt the framing. if len(body) < 1000 { t.Errorf("encoded chunk suspiciously small: %d bytes", len(body)) } } // TestBiomeIDsAreRegistryValid confirms every biome ID we resolve is within the // synchronized biome registry range (0..64), catching table/registry drift. func TestBiomeIDsAreRegistryValid(t *testing.T) { od, err := worldgen.LoadOverworldFinalDensity(7) if err != nil { t.Fatalf("load: %v", err) } registrySize := 0 for _, reg := range registry.Synced() { if reg.Name == "minecraft:worldgen/biome" { registrySize = len(reg.Entries) break } } if registrySize == 0 { t.Fatal("biome registry not found") } for cx := 0; cx < 4; cx++ { for cz := 0; cz < 4; cz++ { s2D := worldgen.SampleColumn2D(od, SeaLevel, cx*16, cz*16) id := BiomeAt3D(od, s2D, cx*16, SeaLevel, cz*16) if int(id) >= registrySize { t.Errorf("biome id %d at (%d,~, %d) >= registry size %d", id, cx*16, cz*16, registrySize) } } } }