176 lines
5.8 KiB
Go
176 lines
5.8 KiB
Go
package gameserver
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"testing"
|
|
|
|
"gac-hkrpg-go/internal/common"
|
|
goproto "gac-hkrpg-go/protocol/proto"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func TestLightconeSwapAndUnequipPersistAssignments(t *testing.T) {
|
|
t.Chdir(t.TempDir())
|
|
writeEquipmentFixture(t, `{"lightcones":[{"item_id":23001,"internal_uid":1,"equip_avatar":1201},{"item_id":23002,"internal_uid":2,"equip_avatar":1202}],"relics":[]}`)
|
|
|
|
player := &common.FreesrData{
|
|
Avatars: map[uint32]*common.AvatarJson{
|
|
1201: {AvatarID: 1201},
|
|
1202: {AvatarID: 1202},
|
|
},
|
|
Lightcones: []common.Lightcone{
|
|
{ItemID: 23001, InternalUID: 1, EquipAvatar: 1201},
|
|
{ItemID: 23002, InternalUID: 2, EquipAvatar: 1202},
|
|
},
|
|
}
|
|
session := &Session{json: player}
|
|
|
|
update, err := setLightconeEquipper(session, 1201, 3002)
|
|
if err != nil {
|
|
t.Fatalf("equip Light Cone: %v", err)
|
|
}
|
|
if player.Lightcones[0].EquipAvatar != 1202 || player.Lightcones[1].EquipAvatar != 1201 {
|
|
t.Fatalf("Light Cone swap failed: %+v", player.Lightcones)
|
|
}
|
|
if len(update.EquipmentList) != 2 || len(update.AvatarSync.AvatarList) != 2 {
|
|
t.Fatalf("swap did not sync both Light Cones and avatars: %+v", update)
|
|
}
|
|
assertSavedEquipmentOwners(t, "lightcones", map[uint32]uint32{1: 1202, 2: 1201})
|
|
|
|
update, err = setLightconeEquipper(session, 1201, 0)
|
|
if err != nil {
|
|
t.Fatalf("unequip Light Cone: %v", err)
|
|
}
|
|
if player.Lightcones[1].EquipAvatar != 0 || len(update.EquipmentList) != 1 {
|
|
t.Fatalf("Light Cone unequip failed: items=%+v update=%+v", player.Lightcones, update)
|
|
}
|
|
assertSavedEquipmentOwners(t, "lightcones", map[uint32]uint32{1: 1202, 2: 0})
|
|
}
|
|
|
|
func TestRelicSwapUnequipAndSlotValidationPersistAssignments(t *testing.T) {
|
|
t.Chdir(t.TempDir())
|
|
writeEquipmentFixture(t, `{"lightcones":[],"relics":[{"relic_id":31012,"internal_uid":11,"equip_avatar":1201},{"relic_id":32012,"internal_uid":12,"equip_avatar":1202}]}`)
|
|
|
|
player := &common.FreesrData{
|
|
Avatars: map[uint32]*common.AvatarJson{
|
|
1201: {AvatarID: 1201},
|
|
1202: {AvatarID: 1202},
|
|
},
|
|
Relics: []common.Relic{
|
|
{RelicID: 31012, InternalUID: 11, EquipAvatar: 1201},
|
|
{RelicID: 32012, InternalUID: 12, EquipAvatar: 1202},
|
|
},
|
|
}
|
|
session := &Session{json: player}
|
|
|
|
wrongSlot, err := equipRelic(session, &goproto.DressRelicAvatarCsReq{
|
|
AvatarId: 1201,
|
|
SwitchList: []*goproto.DressRelicParam{{RelicType: 1, RelicUniqueId: 12}},
|
|
})
|
|
if err != nil || wrongSlot != nil {
|
|
t.Fatalf("mismatched Relic slot should be ignored: update=%+v err=%v", wrongSlot, err)
|
|
}
|
|
if player.Relics[0].EquipAvatar != 1201 || player.Relics[1].EquipAvatar != 1202 {
|
|
t.Fatalf("mismatched Relic slot changed ownership: %+v", player.Relics)
|
|
}
|
|
|
|
update, err := equipRelic(session, &goproto.DressRelicAvatarCsReq{
|
|
AvatarId: 1201,
|
|
SwitchList: []*goproto.DressRelicParam{{RelicType: 2, RelicUniqueId: 12}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("equip Relic: %v", err)
|
|
}
|
|
if player.Relics[0].EquipAvatar != 1202 || player.Relics[1].EquipAvatar != 1201 {
|
|
t.Fatalf("Relic swap failed: %+v", player.Relics)
|
|
}
|
|
if len(update.RelicList) != 2 || len(update.AvatarSync.AvatarList) != 2 {
|
|
t.Fatalf("swap did not sync both Relics and avatars: %+v", update)
|
|
}
|
|
assertSavedEquipmentOwners(t, "relics", map[uint32]uint32{11: 1202, 12: 1201})
|
|
|
|
update, err = unequipRelic(session, &goproto.TakeOffRelicCsReq{
|
|
AvatarId: 1201,
|
|
RelicTypeList: []uint32{2},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("unequip Relic: %v", err)
|
|
}
|
|
if player.Relics[1].EquipAvatar != 0 || len(update.RelicList) != 1 {
|
|
t.Fatalf("Relic unequip failed: items=%+v update=%+v", player.Relics, update)
|
|
}
|
|
assertSavedEquipmentOwners(t, "relics", map[uint32]uint32{11: 1202, 12: 0})
|
|
}
|
|
|
|
func TestEquipmentPickerAuxiliaryRequestsHaveTypedReplies(t *testing.T) {
|
|
for _, name := range []string{
|
|
"RelicPresetGetPlanCsReq",
|
|
"RelicSmartWearGetPlanCsReq",
|
|
"RelicSmartWearGetPinRelicCsReq",
|
|
"GetBigDataRecommendCsReq",
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
id, ok := goproto.CmdIDByName[name]
|
|
if !ok {
|
|
t.Fatalf("protocol table is missing %s", name)
|
|
}
|
|
if typedHandlers[uint16(id)] == nil {
|
|
t.Fatalf("%s is not registered as a typed handler", name)
|
|
}
|
|
})
|
|
}
|
|
|
|
avatarID := uint32(1201)
|
|
recommendation := emptyEquipmentRecommendation(avatarID, goproto.BigDataRecommendType_BIG_DATA_RECOMMEND_TYPE_AVATAR_RELIC)
|
|
responses := []proto.Message{
|
|
emptyRelicPresetPlans(avatarID),
|
|
emptyRelicSmartWearPlans(avatarID),
|
|
emptyPinnedRelics(avatarID),
|
|
&recommendation,
|
|
}
|
|
for _, response := range responses {
|
|
encoded, err := proto.Marshal(response)
|
|
if err != nil {
|
|
t.Fatalf("marshal %T: %v", response, err)
|
|
}
|
|
if len(encoded) == 0 {
|
|
t.Fatalf("%T encoded as an empty response", response)
|
|
}
|
|
}
|
|
if recommendation.EquipAvatar != avatarID || recommendation.BigDataRecommendType != goproto.BigDataRecommendType_BIG_DATA_RECOMMEND_TYPE_AVATAR_RELIC {
|
|
t.Fatalf("recommendation response lost request context: %+v", recommendation)
|
|
}
|
|
}
|
|
|
|
func writeEquipmentFixture(t *testing.T, contents string) {
|
|
t.Helper()
|
|
if err := os.WriteFile("freesr-data.json", []byte(contents), 0600); err != nil {
|
|
t.Fatalf("write fixture: %v", err)
|
|
}
|
|
}
|
|
|
|
func assertSavedEquipmentOwners(t *testing.T, collection string, expected map[uint32]uint32) {
|
|
t.Helper()
|
|
contents, err := os.ReadFile("freesr-data.json")
|
|
if err != nil {
|
|
t.Fatalf("read persisted equipment: %v", err)
|
|
}
|
|
var root map[string][]struct {
|
|
InternalUID uint32 `json:"internal_uid"`
|
|
EquipAvatar uint32 `json:"equip_avatar"`
|
|
}
|
|
if err := json.Unmarshal(contents, &root); err != nil {
|
|
t.Fatalf("decode persisted equipment: %v", err)
|
|
}
|
|
owners := make(map[uint32]uint32, len(root[collection]))
|
|
for _, entry := range root[collection] {
|
|
owners[entry.InternalUID] = entry.EquipAvatar
|
|
}
|
|
for uid, want := range expected {
|
|
if got, ok := owners[uid]; !ok || got != want {
|
|
t.Errorf("%s UID %d owner = %d (present %v), want %d", collection, uid, got, ok, want)
|
|
}
|
|
}
|
|
}
|