Files
GaCy-GO/internal/gameserver/scene_entrance_anchor_test.go
T

153 lines
5.6 KiB
Go
Raw Normal View History

package gameserver
import (
"encoding/json"
"path/filepath"
"strconv"
"testing"
"gac-hkrpg-go/internal/common"
goproto "gac-hkrpg-go/protocol/proto"
)
func TestSceneEntranceAnchorKeepsRoomsOnSameFloorDistinct(t *testing.T) {
res := &common.JsonConfig{
MapEntrances: map[uint32]common.MapEntranceEntry{
10: {FloorID: 20, StartAnchorID: 2},
11: {FloorID: 20, StartAnchorID: 2},
},
SceneAnchors: map[uint32][]common.AnchorItem{
10: {{ID: 1, Pos: common.Vector{X: 5}}, {ID: 2, Pos: common.Vector{Y: -15000}}},
11: {{ID: 2, Pos: common.Vector{X: 25}}},
},
SceneDefaultAnchors: map[uint32]common.AnchorItem{20: {ID: 1, Pos: common.Vector{X: 99}}},
}
first, ok := sceneEntranceAnchor(res, 10, 20)
if !ok || first.ID != 2 || first.Pos.Y != -15000 {
t.Fatalf("room must retain its selected anchor, including a negative height: %+v, %t", first, ok)
}
second, ok := sceneEntranceAnchor(res, 11, 20)
if !ok || second.Pos.X != 25 {
t.Fatalf("second room must use its own entrance anchor: %+v, %t", second, ok)
}
for _, pair := range [][2]uint32{{10, 21}, {12, 20}} {
if _, ok := sceneEntranceAnchor(res, pair[0], pair[1]); ok {
t.Fatalf("must reject an unknown entrance or mismatching floor: %v", pair)
}
}
res.MapEntrances[10] = common.MapEntranceEntry{FloorID: 20, StartAnchorID: 3}
if _, ok := sceneEntranceAnchor(res, 10, 20); ok {
t.Fatal("must not substitute another anchor when the requested anchor is absent")
}
res.MapEntrances[12] = common.MapEntranceEntry{FloorID: 20}
if anchor, ok := sceneEntranceAnchor(res, 12, 20); !ok || anchor.Pos.X != 99 {
t.Fatal("entrance without an explicit start anchor must use the captured floor default")
}
}
// Regression for the entrance reported by the Client, using the actual captured
// membership and placements rather than a second hand-written group list.
func TestTrainRoomScenePacketMatchesCapturedDimension(t *testing.T) {
chdirRepositoryRoot(t)
configPath, err := filepath.Abs("server.json")
if err != nil {
t.Fatal(err)
}
t.Setenv("GAC_CONFIG", configPath)
res, err := common.GameRes()
if err != nil {
t.Fatal(err)
}
const reportedEntrance uint32 = 100000352
entrance, exists := res.MapEntrances[reportedEntrance]
if !exists {
t.Fatal("reported train entrance missing from Client MapEntrance")
}
raw, err := common.ReadResourceFile("resources/SceneMetadata.json")
if err != nil {
t.Fatal(err)
}
var captured struct {
Floors map[string]struct {
DimensionID uint32 `json:"dimension_id"`
Groups map[string][]uint32 `json:"dimension_groups"`
Saved map[string]int32 `json:"saved_values"`
DefaultAnchor common.AnchorItem `json:"floor_default_anchor"`
} `json:"floors"`
}
if err := json.Unmarshal(raw, &captured); err != nil {
t.Fatal(err)
}
floor := captured.Floors[strconv.FormatUint(uint64(entrance.FloorID), 10)]
allowed := map[uint32]bool{}
for _, group := range floor.Groups[strconv.FormatUint(uint64(floor.DimensionID), 10)] {
allowed[group] = true
}
if len(allowed) == 0 {
t.Fatal("reported room has no captured dimension membership")
}
s := NewSession(func([]byte) error { t.Fatal("scene construction must not send or persist data"); return nil }, 1, 1)
s.SetJSON(&common.FreesrData{Lineups: map[uint32]uint32{0: 1001}})
scene, err := loadScene(s, reportedEntrance, true, false, nil, &goproto.SceneIdentifier{FloorId: entrance.FloorID})
if err != nil {
t.Fatal(err)
}
if scene.EntryId != reportedEntrance || scene.FloorId != entrance.FloorID || scene.DimensionId != floor.DimensionID {
t.Fatalf("wrong scene identity: %v", scene)
}
for _, group := range scene.EntityGroupList {
if group.GroupId != 0 && !allowed[group.GroupId] {
t.Fatalf("packet includes group %d from another dimension", group.GroupId)
}
}
for name, expected := range floor.Saved {
if value, present := scene.FloorSavedData[name]; !present || value != expected {
t.Fatalf("saved value %s: got %d/%t, expected %d", name, value, present, expected)
}
}
anchor, exists := sceneEntranceAnchor(res, reportedEntrance, entrance.FloorID)
if !exists {
t.Fatal("reported entrance has no resource anchor")
}
pos := s.JSON().Position
if pos.X != anchor.Pos.X || pos.Y != anchor.Pos.Y || pos.Z != anchor.Pos.Z || pos.RotY != anchor.Rot.Y {
t.Fatalf("room spawned at a floor checkpoint instead of its entrance anchor: %+v", pos)
}
if floor.DefaultAnchor.ID == 0 {
t.Fatal("train floor has no captured default anchor")
}
defaultEntryFound := false
for id, row := range res.MapEntrances {
if row.FloorID != entrance.FloorID || row.StartAnchorID != 0 || row.EntranceType != "Town" {
continue
}
defaultEntryFound = true
if _, err := loadScene(s, id, true, false, nil, nil); err != nil {
t.Fatal(err)
}
pos = s.JSON().Position
if pos.X != floor.DefaultAnchor.Pos.X || pos.Y != floor.DefaultAnchor.Pos.Y || pos.Z != floor.DefaultAnchor.Pos.Z {
t.Fatalf("default entrance %d spawned at a checkpoint instead of native floor start: %+v", id, pos)
}
}
if !defaultEntryFound {
t.Fatal("no default Town entrance tested")
}
_, config, exists := firstSceneOfEntry(res, reportedEntrance)
if !exists {
t.Fatal("reported entrance has no scene config")
}
for _, group := range config.Scenes {
for id, checkpoint := range group.Teleports {
if _, err := loadScene(s, reportedEntrance, true, false, &id, nil); err != nil {
t.Fatal(err)
}
pos = s.JSON().Position
if pos.X != checkpoint.Pos.X || pos.Y != checkpoint.Pos.Y || pos.Z != checkpoint.Pos.Z {
t.Fatal("explicit checkpoint teleport was replaced by an entrance anchor")
}
return
}
}
t.Fatal("reported room has no checkpoint to verify explicit teleport precedence")
}