RegionIO/internal/worldgen/features_test.go

145 lines
4.6 KiB
Go

package worldgen
import (
"encoding/json"
"reflect"
"testing"
)
func TestFeatureDatapackLoadsAndLinks(t *testing.T) {
set, err := LoadFeatureSet()
if err != nil {
t.Fatal(err)
}
placed, ok := set.Placed["minecraft:ore_diamond"]
if !ok {
t.Fatal("ore_diamond placed feature missing")
}
if placed.Feature != "minecraft:ore_diamond_small" || len(placed.Placement) != 4 {
t.Fatalf("ore_diamond = feature %q, %d modifiers", placed.Feature, len(placed.Placement))
}
configured := set.Configured[placed.Feature]
if configured.Type != "minecraft:ore" {
t.Fatalf("configured type = %q", configured.Type)
}
plains := set.Biomes["minecraft:plains"]
if len(plains.Features) != 11 || len(plains.Features[6]) < 20 {
t.Fatalf("plains stages=%d underground ores=%d", len(plains.Features), len(plains.Features[6]))
}
if len(set.BlockTags["minecraft:stone_ore_replaceables"]) == 0 {
t.Fatal("stone_ore_replaceables tag missing")
}
ore, err := set.Ore("minecraft:ore_diamond_small")
if err != nil || ore.Size != 4 || len(ore.Targets) != 2 {
t.Fatalf("diamond config = %+v, err=%v", ore, err)
}
plan, err := set.Placement("minecraft:ore_diamond")
if err != nil || plan.Count.Min != 7 || plan.Count.Max != 7 || plan.MinY.AboveBottom == nil {
t.Fatalf("diamond placement = %+v, err=%v", plan, err)
}
spring, err := set.Spring("minecraft:spring_water")
if err != nil || spring.State.Name != "minecraft:water" || spring.RockCount != 4 || spring.HoleCount != 1 {
t.Fatalf("spring water = %+v, err=%v", spring, err)
}
lavaPlan, err := set.Placement("minecraft:spring_lava")
if err != nil || lavaPlan.HeightDistribution != "minecraft:very_biased_to_bottom" {
t.Fatalf("spring lava placement = %+v, err=%v", lavaPlan, err)
}
}
func TestFeatureStepsAgainstVanillaRuntimeVectors(t *testing.T) {
set := &FeatureSet{Biomes: map[string]BiomeGeneration{
"a": {Features: [][]string{{"f1"}, {"f3", "f4"}}},
"b": {Features: [][]string{{"f2", "f1"}, {"f5", "f4"}}},
}}
for _, test := range []struct {
name string
order []string
want [][]string
}{
{"ab", []string{"a", "b"}, [][]string{{"f2", "f1"}, {"f5", "f3", "f4"}}},
{"ba", []string{"b", "a"}, [][]string{{"f2", "f1"}, {"f3", "f5", "f4"}}},
} {
t.Run(test.name, func(t *testing.T) {
got, err := set.FeatureSteps(test.order)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, test.want) {
t.Fatalf("steps = %v, want %v", got, test.want)
}
})
}
}
func TestFeatureStepsRejectsCycles(t *testing.T) {
set := &FeatureSet{Biomes: map[string]BiomeGeneration{
"a": {Features: [][]string{{"f1", "f2"}}},
"b": {Features: [][]string{{"f2", "f1"}}},
}}
if _, err := set.FeatureSteps([]string{"a", "b"}); err == nil {
t.Fatal("cyclic feature order succeeded")
}
}
func TestPlacementHeightDistributionsStayWithinInclusiveBounds(t *testing.T) {
r := NewLegacy(12345)
for _, distribution := range []string{"minecraft:trapezoid", "minecraft:very_biased_to_bottom", "minecraft:uniform"} {
plan := PlacementPlan{
HeightDistribution: distribution,
MinY: HeightProvider{Absolute: intPtr(-20)},
MaxY: HeightProvider{Absolute: intPtr(20)},
}
for i := 0; i < 1000; i++ {
got := plan.SampleY(r, -64, 384)
if got < -20 || got > 20 {
t.Fatalf("%s sample %d outside [-20,20]: %d", distribution, i, got)
}
}
}
}
func TestPlacementPositionsPreservesModifierOrder(t *testing.T) {
modifier := func(raw string) PlacementModifier {
var value PlacementModifier
value.Raw = json.RawMessage(raw)
if err := json.Unmarshal(value.Raw, &value); err != nil {
t.Fatal(err)
}
return value
}
set := &FeatureSet{Placed: map[string]PlacedFeature{
"test": {Placement: []PlacementModifier{
modifier(`{"type":"minecraft:count","count":3}`),
modifier(`{"type":"minecraft:in_square"}`),
modifier(`{"type":"minecraft:height_range","height":{"type":"minecraft:uniform","min_inclusive":{"absolute":-2},"max_inclusive":{"absolute":2}}}`),
modifier(`{"type":"minecraft:biome"}`),
}},
}}
r := NewLegacy(12345)
got, err := set.PlacementPositions("test", r, FeaturePosition{X: 32, Y: -64, Z: -16}, PlacementContext{
MinY: -64, Height: 384,
BiomeAllows: func(position FeaturePosition) bool { return position.Y >= 0 },
})
if err != nil {
t.Fatal(err)
}
wantRandom := NewLegacy(12345)
var want []FeaturePosition
for range 3 {
x := 32 + int(wantRandom.NextIntN(16))
z := -16 + int(wantRandom.NextIntN(16))
y := -2 + int(wantRandom.NextIntN(5))
position := FeaturePosition{
X: x,
Y: y,
Z: z,
}
if position.Y >= 0 {
want = append(want, position)
}
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("positions = %v, want %v", got, want)
}
}