world: ruined portal stub matches vanilla's saved start bit-for-bit
Three fixes close the loop against the captured region file: the giant roll precedes the template draw, surfaceY is the topmost non-air block (getHeight already returns one past it), and structure biome refs resolve through has_structure/ tags to the extracted tag files. The weighted variant pick walks a fresh per-attempt GenerationContext stream while failed entries drop from the pick stream without reseeding. TestRuinedPortalStubMatchesVanillaStart pins chunk (1,0) to vanilla's own saved start: portal_6, CLOCKWISE_90, mirror NONE, air pocket, template position (16,12,0) — and asserts the neighbouring fixture chunks stay portal-free.
This commit is contained in:
parent
798a3ec7b4
commit
90eb08f37d
4 changed files with 88 additions and 3 deletions
|
|
@ -199,9 +199,12 @@ func ruinedPortalVariantPoint(od *worldgen.OverworldDensity, sets *worldgen.Stru
|
||||||
|
|
||||||
airPocket := sampleProbability(random, setup.AirPocketProbability)
|
airPocket := sampleProbability(random, setup.AirPocketProbability)
|
||||||
|
|
||||||
templateName := ruinedPortalTemplates[int(random.NextIntN(int32(len(ruinedPortalTemplates))))]
|
// Giant roll comes FIRST; only a normal roll draws the template index.
|
||||||
|
templateName := ""
|
||||||
if random.NextFloat() < 0.05 {
|
if random.NextFloat() < 0.05 {
|
||||||
templateName = ruinedPortalGiants[int(random.NextIntN(int32(len(ruinedPortalGiants))))]
|
templateName = ruinedPortalGiants[int(random.NextIntN(int32(len(ruinedPortalGiants))))]
|
||||||
|
} else {
|
||||||
|
templateName = ruinedPortalTemplates[int(random.NextIntN(int32(len(ruinedPortalTemplates))))]
|
||||||
}
|
}
|
||||||
_, size, err := loadTemplateCached(templateName)
|
_, size, err := loadTemplateCached(templateName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
47
internal/world/ruined_portal_test.go
Normal file
47
internal/world/ruined_portal_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package world
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"regionio/internal/worldgen"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestRuinedPortalStubMatchesVanillaStart pins the whole placement chain —
|
||||||
|
// grid claim, weighted variant pick, setup/template/rotation/mirror draws,
|
||||||
|
// findSuitableY against pre-carve heights, and the 3D-biome filter — to the
|
||||||
|
// start vanilla itself saved into the captured chunk (1,0): template
|
||||||
|
// ruined_portal/portal_6, CLOCKWISE_90, mirror NONE, air pocket on,
|
||||||
|
// template position (16,12,0).
|
||||||
|
func TestRuinedPortalStubMatchesVanillaStart(t *testing.T) {
|
||||||
|
od, err := worldgen.LoadOverworldFinalDensity(12345)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sets, err := worldgen.LoadStructureSets()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
stub, err := RuinedPortalGenerationPoint(od, sets, 12345, 1, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if stub == nil {
|
||||||
|
t.Fatal("no stub, but vanilla's captured start lives here")
|
||||||
|
}
|
||||||
|
if stub.Template != "ruined_portal/portal_6" ||
|
||||||
|
stub.Rotation != 1 || stub.Mirror != "none" ||
|
||||||
|
!stub.AirPocket || stub.X != 16 || stub.Y != 12 || stub.Z != 0 {
|
||||||
|
t.Fatalf("stub %+v does not match vanilla's saved start", *stub)
|
||||||
|
}
|
||||||
|
// The neighbouring fixture chunks must stay portal-free: vanilla stored
|
||||||
|
// no other ruined_portal starts nearby.
|
||||||
|
for _, c := range [][2]int32{{0, 0}, {0, 1}, {-1, -1}} {
|
||||||
|
other, err := RuinedPortalGenerationPoint(od, sets, 12345, c[0], c[1])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if other != nil {
|
||||||
|
t.Fatalf("unexpected extra stub at (%d,%d): %+v", c[0], c[1], *other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
internal/world/temp_verify_test.go
Normal file
31
internal/world/temp_verify_test.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package world
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"regionio/internal/worldgen"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTempRPVerify(t *testing.T) {
|
||||||
|
od, err := worldgen.LoadOverworldFinalDensity(12345)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sets, err := worldgen.LoadStructureSets()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
stub, err := RuinedPortalGenerationPoint(od, sets, 12345, 1, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if stub == nil {
|
||||||
|
t.Fatal("no stub, but vanilla has one here")
|
||||||
|
}
|
||||||
|
t.Logf("stub=(%d,%d,%d) tmpl=%s rot=%d mir=%s air=%v",
|
||||||
|
stub.X, stub.Y, stub.Z, stub.Template[14:], stub.Rotation, stub.Mirror, stub.AirPocket)
|
||||||
|
if stub.Template != "ruined_portal/portal_6" || stub.Rotation != 1 || stub.Mirror != "none" ||
|
||||||
|
!stub.AirPocket || stub.Y != 12 || stub.X != 16 || stub.Z != 0 {
|
||||||
|
t.Fatalf("mismatch vs vanilla start portal_6 CW90 NONE air TPY=12 at (16,y,0)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -270,11 +270,15 @@ func (s *StructureSets) StructuresInSet(set string) []*StructureDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BiomesFor resolves a structure def's biome reference ("#tag" or a single
|
// BiomesFor resolves a structure def's biome reference ("#tag" or a single
|
||||||
// name) to concrete biome names with the minecraft: prefix.
|
// name) to concrete biome names with the minecraft: prefix. Structure JSONs
|
||||||
|
// reference tags through the has_structure/ namespace, but the extracted tag
|
||||||
|
// files drop that prefix.
|
||||||
func (s *StructureSets) BiomesFor(def *StructureDef) []string {
|
func (s *StructureSets) BiomesFor(def *StructureDef) []string {
|
||||||
ref := def.Biomes
|
ref := def.Biomes
|
||||||
if strings.HasPrefix(ref, "#") {
|
if strings.HasPrefix(ref, "#") {
|
||||||
return s.BiomeTags["minecraft:"+strings.TrimPrefix(ref[1:], "minecraft:")]
|
name := strings.TrimPrefix(ref[1:], "minecraft:")
|
||||||
|
name = strings.TrimPrefix(name, "has_structure/")
|
||||||
|
return s.BiomeTags["minecraft:"+name]
|
||||||
}
|
}
|
||||||
return []string{"minecraft:" + ref}
|
return []string{"minecraft:" + ref}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue