154 lines
5.6 KiB
Go
154 lines
5.6 KiB
Go
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")
|
|
}
|