diff --git a/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs b/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs index dec7263..fe63bbb 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/MyPageController.cs @@ -100,6 +100,13 @@ public class MyPageController : SVSimController }, BasicPuzzle = new Models.Dtos.Common.BadgeFlag { IsDisplayBadge = false }, // TODO(mypage-stub): viewer practice-puzzle progress IsBattlePassPeriod = rotation.IsBattlePassPeriod, + // The client's MyPageTask.Parse (line 155-163) does `_userItemDict.Clear();` whenever + // user_item_list is present in the response — not when it's non-empty — and then + // repopulates from the wire. Emitting [] here wipes the inventory the client populated + // from /load/index, which makes PackChildGachaInfo.CostGoodsCount return 0 and filters + // out is_hide=1 tutorial packs (the legendary starter 99047) via PackConfig.EnableBuyPack. + // Populate from viewer.Items so the client's dict stays in sync with the DB. + UserItemList = viewer.Items.Select(i => new UserItem(i)).ToList(), SpecialCrystalInfo = new(), // TODO(mypage-stub): same shape/source as /load/index // CompetitionInfo, ShopNotification, StoryNotification, GuildNotification, GatheringInfo, // IsHiddenBossAppeared, SubBanner/SubBannerList/HomeDialogList/UserOfflineEvent/UserItemList, diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs index 7a1d329..c042f57 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/MyPageIndexResponse.cs @@ -267,8 +267,14 @@ public class MyPageIndexResponse // ── Per-viewer / event state ─────────────────────────────────────────── /// - /// Updated item counts. Empty list = "no items to update" (client iterates 0 times, no UI change). - /// Per-viewer state — populate from viewer.Items when that wiring lands. + /// Full snapshot of the viewer's owned items — NOT a delta. The client's + /// MyPageTask.Parse (line 155-163) clears _userItemDict the moment it sees + /// this key, then re-populates from the wire list. Emitting [] wipes whatever + /// /load/index populated, breaking any client logic that reads from the dict — most + /// load-bearingly PackChildGachaInfo.CostGoodsCount, which gates tutorial-pack + /// visibility via PackConfig.EnableBuyPack. Controllers MUST populate the full + /// owned-items snapshot from viewer.Items; an empty list is correct only when the + /// viewer genuinely owns nothing. /// [JsonPropertyName("user_item_list")] [Key("user_item_list")]