fix: allow restoring the saved arena lobby

This commit is contained in:
2026-10-04 12:09:39 +08:00
parent 18520ad9b7
commit f567b46687
4 changed files with 81 additions and 30 deletions
+8 -5
View File
@@ -58,11 +58,14 @@ func TestEmptyPacketCodesReturnsCopy(t *testing.T) {
func TestStandaloneNativeDefaults(t *testing.T) {
for path, want := range map[string]int{
"/EventScheduleInfo": 163,
"/EquipInfo": 34,
"/TodayQuestInfo": 64,
"/UpdateAgeGate": 0,
"/ActiveMap": 0,
"/EventScheduleInfo": 163,
"/EquipInfo": 34,
"/TodayQuestInfo": 64,
"/UpdateAgeGate": 0,
"/ActiveMap": 0,
"/PvpBattleDeckInfo": 87,
"/PvpBattleHistory": 97,
"/PvpBattleOnceRewardInfo": 277,
} {
code, proto, ok, err := Handle(path, wire.AppendVarint(nil, 1, 55))
if err != nil || !ok || code != want || len(proto) != 0 {
+31 -25
View File
@@ -4,31 +4,37 @@ package feature
// features. An empty protobuf means the local account currently has no rows or
// no active server schedule; it is not copied from a captured response.
var standaloneDefaults = map[string]int{
"/EventScheduleInfo": 163,
"/LoginEvent": 0,
"/BalanceVersionCheck": 186,
"/ChargeCostInfo": 123,
"/EquipInfo": 34,
"/AchievementInfo": 166,
"/HuntDispatchInfo": 189,
"/EventMissionInfo": 127,
"/MissionInfo": 118,
"/EventRewardHistory": 0,
"/PackEventStoryInfo": 220,
"/PackEventBattleInfo": 214,
"/FishingItemInfo": 459,
"/MonsterHuntDeckInfo": 263,
"/Attendance": 0,
"/AttendanceInfo": 0,
"/PackPreviewInfo": 104,
"/TodayQuestInfo": 64,
"/WaypointInfo": 31,
"/FieldDeckInfo": 273,
"/HuntingGroundInfoList": 387,
"/FriendRecommend": 211,
"/SupporterStatus": 438,
"/SupporterBattleInfo": 439,
"/InnOpen": 109,
"/EventScheduleInfo": 163,
"/LoginEvent": 0,
"/BalanceVersionCheck": 186,
"/ChargeCostInfo": 123,
"/EquipInfo": 34,
"/AchievementInfo": 166,
"/HuntDispatchInfo": 189,
"/EventMissionInfo": 127,
"/MissionInfo": 118,
"/EventRewardHistory": 0,
"/PackEventStoryInfo": 220,
"/PackEventBattleInfo": 214,
"/FishingItemInfo": 459,
"/MonsterHuntDeckInfo": 263,
"/Attendance": 0,
"/AttendanceInfo": 0,
"/PackPreviewInfo": 104,
// No PvP decks, battle history or one-time reward claims have been saved.
// Their repeated-only protobufs encode these account states as empty, and
// the client's callbacks continue the arena-lobby entry sequence.
"/PvpBattleDeckInfo": 87,
"/PvpBattleHistory": 97,
"/PvpBattleOnceRewardInfo": 277,
"/TodayQuestInfo": 64,
"/WaypointInfo": 31,
"/FieldDeckInfo": 273,
"/HuntingGroundInfoList": 387,
"/FriendRecommend": 211,
"/SupporterStatus": 438,
"/SupporterBattleInfo": 439,
"/InnOpen": 109,
}
// commandSuccess contains idempotent local mutations whose response type is
@@ -32,6 +32,38 @@ func TestArenaPositionRestoresAcrossRestartWithoutStoryQuestOrRepurchase(t *test
if pack, err := s.LastPlayedPackID(); err != nil || pack != 3001 {
t.Fatalf("restored login pack=%d err=%v", pack, err)
}
s.fieldPacks[3002] = gamedata.FieldPack{ID: 3002, Type: 3, MapIDs: map[int]bool{30021: true}}
accountInfo := s.accountPackInfo()
arenaRows := 0
if err := wire.Walk(accountInfo, func(field wire.Field) error {
if field.Number == 1 {
id, _, _ := wire.Varint(field.Value, 1)
if id == 3002 {
t.Fatal("unvisited arena was exposed as purchased")
}
if id == 3001 {
arenaRows++
buy, _, _ := wire.Varint(field.Value, 8)
if buy != 1 {
t.Fatal("saved arena missing purchased marker")
}
if err := wire.Walk(field.Value, func(inner wire.Field) error {
if inner.Number != 1 && inner.Number != 8 {
t.Fatalf("saved arena fabricated field %d", inner.Number)
}
return nil
}); err != nil {
return err
}
}
}
return nil
}); err != nil {
t.Fatal(err)
}
if arenaRows != 1 {
t.Fatalf("saved arena rows=%d", arenaRows)
}
request = wire.AppendVarint(wire.AppendVarint(nil, 1, 1), 2, 3001)
code, body, handled, err := s.Handle("/PackInGameInfo", request)
if err != nil || !handled || code != 5 {
+10
View File
@@ -672,6 +672,16 @@ func (s *Service) packDBInfoRows() [][]byte {
}
packID = nextPackID
}
// A committed arena position is this account's prior-entry marker. Expose
// only that arena as purchased so the client restores its existing lobby
// without treating every independent arena as unlocked or rewarded.
if saved, found := s.state.Position(); found {
if pack, arena := s.fieldPacks[saved.PackID]; arena && pack.MapIDs[saved.Position.MapID] {
current := wire.AppendVarint(nil, 1, uint64(saved.PackID))
current = wire.AppendVarint(current, 8, 1)
rows = append(rows, current)
}
}
return rows
}