From 6813da149a927ab0d6b661008c271c9e4efcb88a Mon Sep 17 00:00:00 2001 From: "Liubing\\LB" Date: Wed, 30 Sep 2026 19:19:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(upserver):=20=E4=BF=9D=E5=AD=98M2=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AFKV=E8=BF=81=E7=A7=BB=E8=87=B3=E6=9C=AC?= =?UTF-8?q?=E4=BA=BA=E7=BB=9F=E8=AE=A1=E5=86=99=E6=A3=80=E6=9F=A5=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 保存独立KV用户服务、固定会话存档与原业务接线,以及C3d资料缓存和C3e本人统计写。 保留原PF/AGG路线、业务公式和时序;榜单读取、好友资料、公告、匹配及首场景闸仍待完成。 验证:ServiceHost两条件各33组646断言;Unity CLI Loop编译0错误269警告。 包含相关方案、评审裁决、测试及状态文档。未操作服务器、正式账号或打包。 --- AGENTS.md | 9 + Client/Assets/Scripts/AOTScripts/Boostrap.cs | 2 +- .../Activity/Data/EventDataRepository.cs | 10 +- .../Activity/Services/EventTokenService.cs | 8 +- .../Aquarium/DataCenter/AquariumManager.cs | 23 +- Client/Assets/Scripts/Camp/CampDataMM.cs | 12 +- Client/Assets/Scripts/Core/CustomServerMgr.cs | 76 +- Client/Assets/Scripts/Core/KVMgr.cs | 52 + Client/Assets/Scripts/Core/KVMgr.cs.meta | 11 + Client/Assets/Scripts/Core/PlayFabMgr.cs | 49 +- .../Scripts/DataCenter/BargainPackData.cs | 8 +- .../Scripts/DataCenter/BattlePassData.cs | 3 +- .../Scripts/DataCenter/BuffDataCenter.cs | 18 +- .../DataCenter/DataCenter.FishingEventData.cs | 52 +- .../DataCenter/DataCenter.GuideData.cs | 16 +- .../DataCenter/DataCenter.LeadboardData.cs | 23 + .../DataCenter/DataCenter.PlayerData.cs | 17 +- .../DataCenter/DataCenter.PlayerFishData.cs | 21 +- .../DataCenter/DataCenter.PlayerItemData.cs | 2 +- .../DataCenter/DataCenter.PlayerShopData.cs | 55 +- .../DataCenter/DataCenter.SignupData.cs | 8 +- .../DataCenter/DataCenter.SmallGame.cs | 7 +- .../DataCenter/DataCenter.TriggerPackData.cs | 26 +- .../Scripts/DataCenter/EventPackData.cs | 5 +- .../DataCenter/EventPartnerGatherManager.cs | 6 +- .../DataCenter/EventPinballDataManager.cs | 3 +- .../DataCenter/EventPotionDataManager.cs | 3 +- .../EventScratchTicketDataManager.cs | 3 +- .../DataCenter/FishingChallengeManager.cs | 12 +- .../DataCenter/FishingEventData_OneOne.cs | 6 +- .../DataCenter/FishingEventData_OneTwo.cs | 6 +- .../DataCenter/FishingEvent_PVPData.cs | 13 +- .../DataCenter/OfferChainsChestManager.cs | 4 +- .../DataCenter/OfferDiscoPartyManager.cs | 4 +- .../Scripts/DataCenter/PiggyBankPackData.cs | 5 +- .../Scripts/DataCenter/PlayerFishDataRod.cs | 6 +- .../DataCenter/PlayerItemData_Inflation.cs | 2 +- .../DataCenter/TotalRechargeManager.cs | 8 +- Client/Assets/Scripts/DebugFunc.cs | 4 +- .../Scripts/Duel/UI/EventFishingDuelPanel.cs | 18 +- .../Assets/Scripts/Event/AEventDataManager.cs | 15 +- .../Scripts/EventBingo/EventBingoData.cs | 8 +- .../Scripts/EventBreak/EventBreakData.cs | 6 +- .../Assets/Scripts/EventCan/EventCanData.cs | 6 +- .../Data/EventCubeMeltManager.cs | 6 +- .../EventGatherCore/EventGatherCoreData.cs | 8 +- .../EventLuckGame/EventLuckyGameModel.cs | 8 +- .../EventOfferJourneyData.cs | 8 +- .../EventOfferJourneyLvlTriggerData.cs | 8 +- .../EventStrikeLucky/EventLuckMagicData.cs | 6 +- .../EventWelcomeBackManager.cs | 8 +- .../GampPlay/FishingB/FishingBehaviorB.cs | 7 +- .../InfiniteBuilding/InfiniteBuildingData.cs | 6 +- .../LuckyTask/UI/LuckyADTaskPopupPanel.cs | 15 +- .../Scripts/LuckyTask/UI/LuckyTaskBtn.cs | 7 +- .../Scripts/LuckyTask/UI/LuckyTaskPanel.cs | 16 +- .../Scripts/MatchGame/MatchGameManager.cs | 8 +- .../MiniBP/MiniBattlePassDataProvider.cs | 9 +- .../Scripts/SandDig/model/DiggingGameModel.cs | 18 +- Client/Assets/Scripts/Services/ChatService.cs | 2 +- Client/Assets/Scripts/Services/ClubService.cs | 73 +- .../Services/DeferredRewardStashService.cs | 8 +- .../Scripts/Services/FootPrintService.cs | 12 +- .../Assets/Scripts/Services/FriendService.cs | 7 +- .../Services/ILocalNotificationService.cs | 100 +- .../Scripts/Services/InGameMailHandler.cs | 2 +- .../Assets/Scripts/Services/KVUserService.cs | 341 + .../Scripts/Services/KVUserService.cs.meta | 2 + .../Services/PlayerData/IKVUserLifecycle.cs | 12 + .../PlayerData/IKVUserLifecycle.cs.meta | 11 + .../PlayerData/IKVUserLoadReceiver.cs | 11 + .../PlayerData/IKVUserLoadReceiver.cs.meta | 11 + .../Services/PlayerData/IPlayerSaveStore.cs | 62 + .../PlayerData/IPlayerSaveStore.cs.meta | 11 + .../PlayerKVControlledLoadCapability.cs | 30 +- .../PlayerKVEditorValidationHost.cs | 4 +- .../PlayerData/PlayerKVGameLoadCoordinator.cs | 73 +- .../PlayerData/PlayerKVGameplayBindings.cs | 10 +- .../PlayerData/PlayerKVLoginContext.cs | 84 +- .../PlayerData/PlayerKVRuntimeSelection.cs | 45 + .../PlayerKVRuntimeSelection.cs.meta | 2 + .../PlayerKVSaveRouteEditorValidationHost.cs | 36 +- .../Services/PlayerData/PlayerSaveStores.cs | 199 + .../PlayerData/PlayerSaveStores.cs.meta | 11 + .../Assets/Scripts/Services/SettingService.cs | 83 +- .../Assets/Scripts/Services/SurveyService.cs | 16 +- .../Services/UserService.KVFishingReward.cs | 4 +- .../UserService.KVFishingRewardValidation.cs | 16 +- .../UserService.KVFishingValidation.cs | 22 +- .../Services/UserService.KVGameplayLoop.cs | 24 +- .../Scripts/Services/UserService.KVLoad.cs | 13 + Client/Assets/Scripts/Services/UserService.cs | 9 +- Client/Assets/Scripts/Stages/FishingStage.cs | 54 +- Client/Assets/Scripts/Stages/LoginStage.cs | 21 +- Client/Assets/Scripts/Stages/PFLoginAct.cs | 29 +- Client/Assets/Scripts/Stages/QuitAct.cs | 4 +- Client/Assets/Scripts/SubBoostrap.cs | 38 +- .../Scripts/TimeManager/TimeRefreshManager.cs | 16 +- .../Scripts/UI/AdWheel/AdWheelManager.cs | 8 +- .../Assets/Scripts/UI/Advert/AdvertPanel.cs | 7 +- Client/Assets/Scripts/UI/DeBugPanel.cs | 7 +- .../Scripts/UI/Friends/EventInviteFriends.cs | 2 +- .../UI/JigsawPuzzle/JigsawPuzzleManager.cs | 8 +- .../OfferStoryChain/OfferStoryChainManager.cs | 8 +- .../UI/OfferSweep/OfferSweepManager.cs | 8 +- .../OfferTreasureAscentManager.cs | 8 +- .../UI/PartnerFishBowl/EventPartnerData.cs | 11 +- .../EventPartnerEntryButton.cs | 8 +- .../EventPartnerStatuePlayfabData.cs | 7 +- .../EventPartnerStatueTokenExchangeData.cs | 8 +- .../PinataPack/EventPinataPackDataManager.cs | 6 +- .../PinballUncountableManager.cs | 8 +- .../UI/Setting/BindAccountPopupPanel.cs | 10 +- .../UI/Setting/PlayerHeadPopupPanel.cs | 8 +- .../SettingNotificationsGradePopupPanel.cs | 36 +- .../Setting/SettingNotificationsPopupPanel.cs | 39 +- .../Scripts/UI/Setting/SettingPopupPanel.cs | 16 +- .../Assets/Scripts/UI/Setting/SurveyPanel.cs | 2 +- .../UI/ShootingRange/ShootingRangeData.cs | 6 +- .../Scripts/UI/Shop/BlackFridayCouponData.cs | 11 +- .../UI/Shop/ChainPackWithProgressData.cs | 4 +- .../Assets/Scripts/UI/Shop/GiftNoticePanel.cs | 30 +- .../Scripts/UI/Shop/ThanksGivingPackData.cs | 11 +- .../Scripts/UI/Social/FishingSocialPanel.cs | 13 +- .../UI/Social/Friend/FishingFriendAddPanel.cs | 7 +- .../UI/SocialRush/SocialRushArchitecture.cs | 8 +- .../UI/Turntable/FishingTurntablePanel.cs | 8 +- .../B3BatchMigration/M2/C2d-封存与核证.py.txt | 35 + .../M2/C2d-按核证基线核减.py.txt | 93 + .../M2/C2d-活动原流程核减.py.txt | 52 + .../000-EventDataRepository.cs.txt | 68 + .../001-EventTokenService.cs.txt | 329 + .../C2d修改前快照/002-AquariumManager.cs.txt | 700 + .../M2/C2d修改前快照/003-CampDataMM.cs.txt | 790 + .../M2/C2d修改前快照/004-PlayFabMgr.cs.txt | 358 + .../C2d修改前快照/005-BargainPackData.cs.txt | 321 + .../C2d修改前快照/006-BattlePassData.cs.txt | 923 ++ .../C2d修改前快照/007-BuffDataCenter.cs.txt | 596 + .../008-DataCenter.FishingEventData.cs.txt | 2771 ++++ .../009-DataCenter.GuideData.cs.txt | 740 + .../010-DataCenter.PlayerData.cs.txt | 1526 ++ .../011-DataCenter.PlayerFishData.cs.txt | 1516 ++ .../012-DataCenter.PlayerItemData.cs.txt | 1651 ++ .../013-DataCenter.PlayerShopData.cs.txt | 1426 ++ .../014-DataCenter.SignupData.cs.txt | 232 + .../015-DataCenter.SmallGame.cs.txt | 706 + .../016-DataCenter.TriggerPackData.cs.txt | 657 + .../M2/C2d修改前快照/017-EventPackData.cs.txt | 118 + .../018-EventPartnerGatherManager.cs.txt | 1755 +++ .../019-EventPinballDataManager.cs.txt | 993 ++ .../020-EventPotionDataManager.cs.txt | 1352 ++ .../021-EventScratchTicketDataManager.cs.txt | 957 ++ .../022-FishingChallengeManager.cs.txt | 1114 ++ .../023-FishingEventData_OneOne.cs.txt | 84 + .../024-FishingEventData_OneTwo.cs.txt | 165 + .../025-FishingEvent_PVPData.cs.txt | 282 + .../026-OfferChainsChestManager.cs.txt | 573 + .../027-OfferDiscoPartyManager.cs.txt | 588 + .../028-PiggyBankPackData.cs.txt | 247 + .../029-PlayerFishDataRod.cs.txt | 681 + .../030-PlayerItemData_Inflation.cs.txt | 258 + .../031-TotalRechargeManager.cs.txt | 183 + .../M2/C2d修改前快照/032-DebugFunc.cs.txt | 942 ++ .../033-EventFishingDuelPanel.cs.txt | 829 + .../034-AEventDataManager.cs.txt | 146 + .../C2d修改前快照/035-EventBingoData.cs.txt | 567 + .../C2d修改前快照/036-EventBreakData.cs.txt | 406 + .../M2/C2d修改前快照/037-EventCanData.cs.txt | 564 + .../038-EventCubeMeltManager.cs.txt | 1744 +++ .../039-EventGatherCoreData.cs.txt | 350 + .../040-EventLuckyGameModel.cs.txt | 329 + .../041-EventOfferJourneyData.cs.txt | 354 + .../042-EventOfferJourneyLvlTriggerData.cs.txt | 209 + .../043-EventLuckMagicData.cs.txt | 741 + .../044-EventWelcomeBackManager.cs.txt | 239 + .../C2d修改前快照/045-FishingBehaviorB.cs.txt | 2581 +++ .../046-InfiniteBuildingData.cs.txt | 88 + .../047-LuckyADTaskPopupPanel.cs.txt | 344 + .../M2/C2d修改前快照/048-LuckyTaskBtn.cs.txt | 111 + .../C2d修改前快照/049-LuckyTaskPanel.cs.txt | 259 + .../C2d修改前快照/050-MatchGameManager.cs.txt | 499 + .../051-MiniBattlePassDataProvider.cs.txt | 1195 ++ .../C2d修改前快照/052-DiggingGameModel.cs.txt | 518 + .../M2/C2d修改前快照/053-ChatService.cs.txt | 706 + .../M2/C2d修改前快照/054-ClubService.cs.txt | 1018 ++ .../055-DeferredRewardStashService.cs.txt | 230 + .../C2d修改前快照/056-FootPrintService.cs.txt | 74 + .../M2/C2d修改前快照/057-FriendService.cs.txt | 461 + .../058-InGameMailHandler.cs.txt | 519 + .../M2/C2d修改前快照/059-KVUserService.cs.txt | 310 + .../C2d修改前快照/060-IKVUserLifecycle.cs.txt | 12 + .../061-IKVUserLoadReceiver.cs.txt | 11 + .../C2d修改前快照/062-IPlayerSaveStore.cs.txt | 62 + .../063-PlayerKVGameLoadCoordinator.cs.txt | 251 + .../064-PlayerKVGameplayBindings.cs.txt | 60 + .../C2d修改前快照/065-PlayerSaveStores.cs.txt | 272 + .../M2/C2d修改前快照/066-SurveyService.cs.txt | 139 + ...67-UserService.KVFishingRewardValidation.cs.txt | 557 + .../068-UserService.KVFishingValidation.cs.txt | 330 + .../069-UserService.KVLoad.cs.txt | 123 + .../M2/C2d修改前快照/070-UserService.cs.txt | 914 ++ .../M2/C2d修改前快照/071-FishingStage.cs.txt | 648 + .../M2/C2d修改前快照/072-LoginStage.cs.txt | 131 + .../M2/C2d修改前快照/073-PFLoginAct.cs.txt | 372 + .../M2/C2d修改前快照/074-QuitAct.cs.txt | 103 + .../M2/C2d修改前快照/075-SubBoostrap.cs.txt | 459 + .../076-TimeRefreshManager.cs.txt | 164 + .../C2d修改前快照/077-AdWheelManager.cs.txt | 300 + .../M2/C2d修改前快照/078-AdvertPanel.cs.txt | 182 + .../M2/C2d修改前快照/079-DeBugPanel.cs.txt | 674 + .../080-EventInviteFriends.cs.txt | 156 + .../081-JigsawPuzzleManager.cs.txt | 317 + .../082-OfferStoryChainManager.cs.txt | 303 + .../083-OfferSweepManager.cs.txt | 219 + .../084-OfferTreasureAscentManager.cs.txt | 447 + .../C2d修改前快照/085-EventPartnerData.cs.txt | 1432 ++ .../086-EventPartnerEntryButton.cs.txt | 179 + .../087-EventPartnerStatuePlayfabData.cs.txt | 112 + .../088-EventPartnerStatueTokenExchangeData.cs.txt | 345 + .../089-EventPinataPackDataManager.cs.txt | 204 + .../090-PinballUncountableManager.cs.txt | 296 + .../091-BindAccountPopupPanel.cs.txt | 268 + .../092-PlayerHeadPopupPanel.cs.txt | 279 + .../M2/C2d修改前快照/093-SurveyPanel.cs.txt | 72 + .../094-ShootingRangeData.cs.txt | 397 + .../095-BlackFridayCouponData.cs.txt | 99 + .../096-ChainPackWithProgressData.cs.txt | 36 + .../097-ThanksGivingPackData.cs.txt | 385 + .../098-FishingFriendAddPanel.cs.txt | 711 + .../099-SocialRushArchitecture.cs.txt | 157 + .../100-FishingTurntablePanel.cs.txt | 1019 ++ .../101-M2MergedContractTests.cs.txt | 349 + .../102-M2MergedGameplayTests.cs.txt | 163 + .../M2/C2d修改前快照/103-Program.cs.txt | 267 + .../M2/C2d修改前快照/104-Stubs.cs.txt | 232 + .../M2/C2d修改前快照/index.json | 527 + .../M2MergedGameplayTests.cs.txt | 162 + .../M2/C3b修改前快照/ServiceHost.csproj.txt | 43 + .../M2/C3b修改前快照/Stubs.cs.txt | 232 + .../M2/C3b修改前快照/index.json | 17 + .../M2/CP1-before/KVGameLoadTests.csproj.txt | 32 + .../PlayerKVGameLoadCoordinator.cs.txt | 202 + .../M2/CP1-before/PlayerKVLoginContext.cs.txt | 472 + .../M2/CP1-final-verification.json | 394 + .../M2/CP1-scope-verification.json | 188 + .../B3BatchMigration/M2/CP1-source-diff.patch | 192 + .../M2/CP1-unity-compile.json | 8 + .../B3BatchMigration/M2/CP1-unity-errors.json | 15 + .../M2/CP1-unity-final-state.json | 14 + .../M2/CP1-unity-loaded-api.json | 15 + .../B3BatchMigration/M2/CP1-unity-state.json | 14 + .../M2/CP3A-prompt-validation.cs.txt | 3 + ...-C2c差异方案业务流程保留补充-2026-09-30.md | 21 + ...2c补单保留原异步存档流程修订-2026-09-30.md | 22 + .../M2/M2-C2d-after-timeout-state.json | 14 + .../M2/M2-C2d-debugconfig恢复记录.json | 9 + .../M2/M2-C2d-final-compile.json | 1354 ++ .../M2/M2-C2d-final-consume.json | 14 + .../M2/M2-C2d-final-modules.json | 15 + .../M2/M2-C2d-final-reward.json | 14 + .../M2/M2-C2d-final-state.json | 14 + .../M2/M2-C2d-fixture-compile.json | 1354 ++ .../M2/M2-C2d-fixture-regression-retry.json | 0 .../M2/M2-C2d-fixture-regression.cs.txt | 7 + .../M2/M2-C2d-fixture-regression.json | 15 + .../M2/M2-C2d-pure-port-compile.json | 1369 ++ .../M2/M2-C2d-合并CLI超时核对.json | 17 + .../M2/M2-C3a-ExitEnum.cs.txt | 4 + .../M2/M2-C3a-ExitInputs.targets | 1 + .../M2/M2-C3a-FactoryInputs.targets | 1 + .../B3BatchMigration/M2/M2-C3a-equipment.json | 14 + .../M2/M2-C3a-final-state.json | 14 + .../M2/M2-C3a验证证据hash.json | 149 + .../M2/M2-C3a验证边界与执行记录-2026-09-30.md | 50 + .../M2/M2-C3b-UserID兼容交付hash.json | 92 + ...UserID兼容接线裁决与执行记录-2026-09-30.md | 56 + .../M2/M2-C3c-KV跨账号实测增量hash.json | 25 + .../M2-C3c-KV跨账号读取实测-2026-09-30.json | 281 + .../M2-C3c-KV跨账号读取实测结论-2026-09-30.md | 34 + ...c-SearchFriend正式只读实测-2026-09-30.json | 182 + .../M2-C3c-SearchFriend正式实测增量hash.json | 42 + .../M2/M2-C3c剩余SDK差异受审hash.json | 165 + ...2-C3c剩余SDK接线独立差异审查-2026-09-30.md | 231 + ...‰©余SDK接线集中差异与待审方案-2026-09-30.md | 94 + .../M2/M2-C3c只读核查记录.json | 26 + .../M2-C3c好友列表线上事实补充-2026-09-30.md | 29 + ...M2-C3c好友列表线上只读探测-2026-09-30.json | 31 + ...好友列表线上只读探测-final-2026-09-30.json | 39 + .../M2/M2-C3c好友线上事实增量hash.json | 25 + .../M2-C3c完整审核前待确定事项-2026-09-30.md | 25 + ...Ÿ¥主会话裁决与资料缓存实施边界-2026-09-30.md | 41 + .../M2/M2-C3c审核更新复核检查点.json | 12 + .../M2/M2-C3c客户端KV分支扫描.txt | 53 + .../M2/M2-C3c客户端剩余SDK扫描.txt | 29 + ...c客户端剩余核查与统计独立实施受审hash.json | 117 + .../M2/M2-C3c客户端剩余核查源码基线.json | 8490 ++++++++++ .../M2/M2-C3c客户端剩余核查验证.json | 15 + ...余项核查与本人统计独立实施待裁决-2026-09-30.md | 96 + .../M2-C3c当前待设计与接线清单-2026-09-30.md | 58 + .../M2-C3c当前待设计与接线清单受审hash.json | 98 + .../M2/M2-C3c既有裁决与接口证据增量hash.json | 39 + ...M2-C3c既有裁决与接口证据复核-2026-09-30.md | 41 + .../M2-C3c服务端接口事实确认单-2026-09-30.md | 60 + .../M2/M2-C3c本人统计KV暂存增量hash.json | 98 + ...M2-C3c本人统计KV暂存实施增量-2026-09-30.md | 105 + .../M2/M2-C3c本人统计KV暂存方案检查点.json | 13 + .../M2/M2-C3c正式互加好友实测-2026-09-30.json | 32 + ...-C3c正式互加好友实测-final-2026-09-30.json | 200 + .../M2-C3c正式互加好友执行边界-2026-09-30.md | 19 + ...3c正式互加好友结果与字段差异-2026-09-30.md | 47 + .../M2/M2-C3c正式好友操作增量hash.json | 41 + .../M2/M2-C3c正式好友样例验证.ps1 | 89 + ...ºŒ轮裁决核验与SearchFriend实测-2026-09-30.md | 31 + .../M2/M2-C3c第五轮状态核验hash.json | 30 + ...第五轮状态核验与缓存联动边界-2026-09-30.md | 51 + .../M2/M2-C3c第四轮裁决核验检查点.json | 16 + .../M2/M2-C3c纯平移统一审查入口-2026-09-30.md | 107 + .../M2/M2-C3c纯平移统一审查基线.json | 153 + ...M2-C3c隔离边界修订与复审确认-2026-09-30.md | 61 + .../M2/M2-C3c隔离边界复审增量hash.json | 59 + .../M2/M2-C3d-Unity实际程序集时间.json | 10 + .../M2/M2-C3d-Unity最终CSharp错误.json | 9 + .../M2/M2-C3d-Unity最终强制编译.json | 8 + .../M2/M2-C3d-Unity最终错误日志.json | 510 + .../B3BatchMigration/M2/M2-C3d-Unity编译.json | 8 + .../M2/M2-C3d-Unity编译前状态.json | 14 + .../M2/M2-C3d-Unity编译后状态.json | 14 + .../M2/M2-C3d-Unity首次编译类型差异.json | 1360 ++ .../M2/M2-C3d交付与验证hash.json | 104 + .../M2/M2-C3d开工源码基线.json | 8497 ++++++++++ ...3d资料缓存用户澄清与实施记录-2026-09-30.md | 46 + .../B3BatchMigration/M2/M2-C3e-Unity编译.json | 1354 ++ .../M2/M2-C3e-Unity编译后状态.json | 14 + .../M2/M2-C3e交付与验证hash.json | 115 + ...-C3e本人统计写裁决与实施记录-2026-09-30.md | 59 + .../M2/M2-C3e源码范围核验.json | 15 + .../B3BatchMigration/M2/M2-C3e生产差异.patch | 44 + .../M2/M2-CP1主会话关闭核验.json | 16 + .../B3BatchMigration/M2/M2-CP1交付hash.json | 481 + .../M2/M2-CP1原ZCode独立实施复核提示词.md | 36 + .../M2/M2-CP1实施交付与CP2输入-2026-09-29.md | 41 + .../B3BatchMigration/M2/M2-CP1独立实施复核.md | 46 + ...«‹实施复核主会话裁决与限定关闭-2026-09-29.md | 24 + .../M2/M2-CP2-D1源码事实基线.json | 156 + .../M2/M2-CP2A-C15补审后交付hash.json | 108 + .../M2/M2-CP2A-Editor编译核验.json | 11 + ...Player条件编译补审实施与核验-2026-09-29.md | 19 + .../M2/M2-CP2A-Player编译阻断受审基线.json | 26 + ...-CP2A-Player编译阻断补审方案-待独立审查.md | 17 + .../M2/M2-CP2A-受审基线变化范围核验.json | 21 + .../M2/M2-CP2A-实施自验hash.json | 104 + .../M2/M2-CP2A主会话hash核验.json | 159 + .../M2/M2-CP2A原ZCode独立实施预复核提示词.md | 7 + .../M2/M2-CP2A原ZCode独立方案审查提示词.md | 16 + .../B3BatchMigration/M2/M2-CP2A受审基线.json | 191 + .../M2-CP2A实施自验与待复核边界-2026-09-29.md | 17 + ...正式登录与原句柄交接完整方案-待独立审查.md | 57 + .../M2/M2-CP2A独立实施预复核.md | 80 + ...CP2A独立实施预复核主会话裁决-2026-09-29.md | 15 + .../M2/M2-CP2A独立方案审查.md | 69 + ...«‹方案审查主会话裁决与实施边界-2026-09-29.md | 38 + .../M2/M2-CP2B-T-Editor编译核验.json | 9 + .../M2/M2-CP2B-T交付hash.json | 51 + .../M2/M2-CP2B-T交付与待终审-2026-09-29.md | 28 + ...2B-T原ZCode一次性批末独立实施复核提示词.md | 13 + ...2-CP2B-T原ZCode一次性批级方案审查提示词.md | 23 + .../M2/M2-CP2B-T受审基线.json | 41 + ...Œ整审查主会话裁决与实施白名单-2026-09-29.md | 30 + ...£式KV普通业务请求恢复完整方案-待独立审查.md | 43 + .../M2/M2-CP2B-T独立实施复核.md | 57 + ...«‹实施复核主会话裁决与限定关闭-2026-09-29.md | 28 + .../M2/M2-CP2B-T独立方案审查.md | 117 + ...½®独立报告主会话裁决与补审边界-2026-09-29.md | 28 + ...客户端首场景线上合同待核矩阵-2026-09-29.md | 38 + .../M2-CP2B首场景依赖增量核查-2026-09-29.md | 13 + ...P2正式接线设计输入与新增阻断-2026-09-29.md | 38 + .../M2/M2-CP2现状源码基线-待设计.json | 81 + .../M2/M2-CP2首场景自动依赖核查-2026-09-29.md | 16 + .../M2/M2-CP3A-C11交付hash.json | 56 + .../M2/M2-CP3A-C11交付与待终审-2026-09-29.md | 24 + .../M2/M2-CP3A-C5实施快照hash.json | 46 + ...M2-CP3A-Editor直开入口原ZCode补审提示词.md | 5 + ...-CP3A-Editor直开入口最小补审-2026-09-29.md | 13 + .../M2/M2-CP3A-Editor直开入口独立补审.md | 46 + ...¼€入口补审主会话裁决与实施边界-2026-09-29.md | 12 + .../M2/M2-CP3A-Editor直开入口补审基线.json | 31 + .../B3BatchMigration/M2/M2-CP3A-受审基线.json | 97 + .../M2-CP3A原ZCode一次性批级方案审查提示词.md | 9 + .../M2-CP3A原ZCode批末独立实施复核提示词.md | 5 + ...£式业务发布与B01提示接线完整方案-待独立审查.md | 73 + .../M2/M2-CP3A独立实施复核.md | 74 + ...«‹实施复核主会话裁决与限定关闭-2026-09-29.md | 19 + .../M2/M2-CP3A独立方案审查.md | 69 + ...�ˆ独立审查主会话裁决与实施边界-2026-09-29.md | 24 + .../M2-DP1原ZCode一次性完整方案审查提示词.md | 19 + .../B3BatchMigration/M2/M2-DP1受审基线.json | 96 + .../B3BatchMigration/M2/M2-DP1独立方案审查.md | 167 + .../M2/M2-KVMgr层级依赖纠偏意见-待审.md | 41 + .../M2/M2-KV命名一致性只读盘点-2026-09-29.md | 17 + .../M2/M2-KV替代范围重申-规则增量hash.json | 41 + ...£范围重申与剩余SDK接线集中核查-2026-09-30.md | 56 + .../M2/M2-LevelB与LastLogin只读证据hash.json | 61 + ...LastLogin服务器只读核查及建议-2026-09-30.md | 93 + ...-LevelB保持PlayFab原语义裁决-2026-09-30.md | 31 + ...2-PlayFab移植修改清单-分模块-2026-09-30.md | 84 + ...¢1独立审查主会话裁决与新增阻断-2026-09-29.md | 23 + .../M2/M2-修订2主会话hash核验.json | 161 + ...‹¬立复审主会话裁决与CP1实施边界-2026-09-29.md | 40 + .../M2/M2-先存KV后联调方案增量hash.json | 10 + ...2-先存KV后联调的阶段移植方案-2026-09-30.md | 67 + .../M2/M2-先移植后优化受审基线-修订1.json | 81 + ...2-先移植后优化完整方案-修订1-待独立审查.md | 79 + .../M2/M2-先移植后优化独立方案审查-修订1.md | 87 + ...M2-先移植后优化独立方案审查提示词-修订1.md | 22 + ...双Agent并行方案主会话可行性裁决-2026-09-29.md | 27 + ...‹¬立KV用户服务抽离方案-待完整评审-2026-09-29.md | 53 + ...›方用户服务切换与KV独立实现约束-2026-09-29.md | 52 + .../M2/M2-合批-C1-unity-compile.json | 1354 ++ .../M2/M2-合批-C1检查点与交付hash.json | 147 + .../M2/M2-合批-C2a-unity-compile.json | 1369 ++ .../M2/M2-合批-C2a实施记录-2026-09-29.md | 31 + .../M2/M2-合批-C2a检查点与交付hash.json | 178 + .../M2/M2-合批-C2a自验汇总.json | 27 + .../M2/M2-合批-C2b-unity-compile.json | 1369 ++ .../M2/M2-合批-C2b实施记录-2026-09-29.md | 30 + .../M2/M2-合批-C2b检查点与交付hash.json | 268 + .../M2/M2-合批-C2b自验汇总.json | 26 + .../M2/M2-合批-C2c-unity-compile.json | 1369 ++ .../M2/M2-合批-C2c-固定验证.cs.txt | 4 + .../M2/M2-合批-C2c-固定验证结果.json | 15 + .../M2/M2-合批-C2c-旧奖励回归.cs.txt | 2 + .../M2/M2-合批-C2c-旧奖励回归结果.json | 16 + .../M2/M2-合批-C2c-旧奖励首败日志.json | 15 + .../M2/M2-合批-C2c-旧消耗首败.cs.txt | 3 + .../M2/M2-合批-C2c-旧消耗首败结果.json | 15 + .../M2/M2-合批-C2c-旧装备消耗回归.cs.txt | 8 + .../M2/M2-合批-C2c-旧装备消耗回归结果.json | 15 + .../M2/M2-合批-C2c-退出状态.cs.txt | 1 + .../M2/M2-合批-C2c-退出状态结果.json | 14 + .../M2/M2-合批-C2c实施记录-2026-09-29.md | 35 + .../M2/M2-合批-C2c检查点与交付hash.json | 728 + .../M2/M2-合批-C2c集中边界差异hash.json | 25 + ...集中边界差异与后续连续开发方案-2026-09-29.md | 35 + .../M2/M2-合批-C2d检查点与交付hash.json | 775 + .../M2/M2-合批-C2调用迁移进度.json | 3029 ++++ ...ˆ批修订复核裁决与正式前审边界-2026-09-29.md | 33 + .../M2/M2-合批动态配置投影.json | 1969 +++ ...批原ZCode一次性正式前审提示词-2026-09-29.md | 43 + .../M2/M2-合批存档调用实施台账.json | 2857 ++++ .../M2/M2-合批实施方案工作稿-2026-09-29.md | 118 + .../M2/M2-合批审核节奏纠偏-2026-09-29.md | 27 + .../M2-合批工作稿修订版独立复核-2026-09-29.md | 42 + .../M2-合批工作稿独立预审意见-2026-09-29.md | 73 + .../M2/M2-合批正式候选白名单.json | 1041 ++ .../M2/M2-合批正式前审包自核.json | 19 + .../M2/M2-合批正式受审基线.json | 13011 ++++++++++++++++ ...-合批正式实施方案-待完整审查-2026-09-29.md | 135 + ...‰¹正式审查主会话裁决与实施记录-2026-09-29.md | 24 + .../M2/M2-合批正式独立方案审查-2026-09-29.md | 57 + .../M2/M2-合批预审主会话裁决-2026-09-29.md | 31 + ...Fab能力迁移-服务端开发对接文档-2026-09-30.md | 344 + .../M2/M2-四项服务端开发对接文档受审hash.json | 95 + .../M2/M2-好友KV资料接口设计受审hash.json | 41 + ...V资料服务端接口设计-待完整审核-2026-09-30.md | 119 + ...ˆ·端致服务端线上合同集中问题单-2026-09-29.md | 30 + .../M2-当前开发进度与执行TODO-2026-09-30.md | 133 + ...-当前状态独立审核-防跑偏核查-2026-09-30.md | 36 + .../M2/M2-当前调用矩阵-待核证.json | 6213 ++++++++ .../M2/M2-接手时已有Client改动hash.json | 97 + .../M2/M2-新主会话接手卡-2026-09-29.md | 94 + .../M2/M2-旧方法与调用方合并设计底稿.md | 60 + ...š关前临时门控与忽略路径清理清单-2026-09-29.md | 48 + ...LevelB与登录时间KV存储用户裁决-2026-09-30.md | 17 + .../M2-架构复审裁决与修复顺序-2026-09-29.md | 82 + .../M2/M2-正式接线依赖受审基线-修订2.json | 101 + .../M2/M2-正式接线依赖独立复审-修订2.md | 101 + .../M2/M2-正式接线依赖补审提示词-修订2.md | 20 + .../M2-正式接线依赖补审方案-修订2-待评审.md | 49 + .../M2/M2-等级榜接口设计受审hash.json | 74 + ...¦œ设计范围纠正-LevelB沿用原逻辑-2026-09-30.md | 17 + .../M2/M2-等级榜设计范围纠正hash.json | 25 + ...�–与本人统计键接口设计-待完整审核-2026-09-30.md | 129 + .../M2-管理器同生态位替代策略-2026-09-29.md | 72 + .../M2/M2-纠偏与底稿独立审查.md | 79 + ...º¯平移主会话裁决与C2d实施记录-2026-09-30.md | 53 + .../M2/M2-纯平移核减基线核对-2026-09-30.json | 181 + ...³移用户审查确认与C2d实施边界-2026-09-30.json | 35 + .../M2/M2-纯平移继续前核证记录-2026-09-30.md | 18 + ...¹³移范围纠偏与既有改动核减清单-2026-09-30.md | 37 + .../M2/current-scan/calls.json | 12472 +++++++++++++++ .../M2/current-scan/source-hashes.json | 2111 +++ .../upserver/B3BatchMigration/执行TodoList.md | 118 +- .../CP2AExistingArchiveTests.cs | 136 + .../CP2ARuntimeSelectionTests.cs | 51 + .../KVGameLoadTests/CoordinatorTests.cs | 13 + .../KVGameLoadTests/GameHandoffTests.cs | 141 + .../KVGameLoadTests/KVGameLoadTests.csproj | 3 + .../KVGameLoadTests/M2MergedContractTests.cs | 257 + .../upserver/KVGameLoadTests/Program.cs | 45 + .../RegressionSupport/Dependencies.targets | 15 + .../C3IdentityCompatibilityTests.cs | 135 + .../ServiceHost/C3ProfileCacheTests.cs | 183 + .../ServiceHost/C3StatisticsWriteTests.cs | 230 + .../ServiceHost/M2MergedGameplayTests.cs | 186 + .../KVGameLoadTests/ServiceHost/Program.cs | 107 +- .../ServiceHost/ServiceHost.csproj | 24 +- .../KVGameLoadTests/ServiceHost/Stubs.cs | 138 +- CodexOutput/upserver/TODO.md | 2548 ++- CodexOutput/upserver/开发日志.md | 782 + CodexOutput/upserver/开发状态.md | 1296 +- CodexOutput/upserver/接手入口.md | 1188 +- 511 files changed, 151858 insertions(+), 2376 deletions(-) create mode 100644 AGENTS.md create mode 100644 Client/Assets/Scripts/Core/KVMgr.cs create mode 100644 Client/Assets/Scripts/Core/KVMgr.cs.meta create mode 100644 Client/Assets/Scripts/Services/KVUserService.cs create mode 100644 Client/Assets/Scripts/Services/KVUserService.cs.meta create mode 100644 Client/Assets/Scripts/Services/PlayerData/IKVUserLifecycle.cs create mode 100644 Client/Assets/Scripts/Services/PlayerData/IKVUserLifecycle.cs.meta create mode 100644 Client/Assets/Scripts/Services/PlayerData/IKVUserLoadReceiver.cs create mode 100644 Client/Assets/Scripts/Services/PlayerData/IKVUserLoadReceiver.cs.meta create mode 100644 Client/Assets/Scripts/Services/PlayerData/IPlayerSaveStore.cs create mode 100644 Client/Assets/Scripts/Services/PlayerData/IPlayerSaveStore.cs.meta create mode 100644 Client/Assets/Scripts/Services/PlayerData/PlayerKVRuntimeSelection.cs create mode 100644 Client/Assets/Scripts/Services/PlayerData/PlayerKVRuntimeSelection.cs.meta create mode 100644 Client/Assets/Scripts/Services/PlayerData/PlayerSaveStores.cs create mode 100644 Client/Assets/Scripts/Services/PlayerData/PlayerSaveStores.cs.meta create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d-封存与核证.py.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d-按核证基线核减.py.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d-活动原流程核减.py.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/000-EventDataRepository.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/001-EventTokenService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/002-AquariumManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/003-CampDataMM.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/004-PlayFabMgr.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/005-BargainPackData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/006-BattlePassData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/007-BuffDataCenter.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/008-DataCenter.FishingEventData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/009-DataCenter.GuideData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/010-DataCenter.PlayerData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/011-DataCenter.PlayerFishData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/012-DataCenter.PlayerItemData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/013-DataCenter.PlayerShopData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/014-DataCenter.SignupData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/015-DataCenter.SmallGame.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/016-DataCenter.TriggerPackData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/017-EventPackData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/018-EventPartnerGatherManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/019-EventPinballDataManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/020-EventPotionDataManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/021-EventScratchTicketDataManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/022-FishingChallengeManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/023-FishingEventData_OneOne.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/024-FishingEventData_OneTwo.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/025-FishingEvent_PVPData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/026-OfferChainsChestManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/027-OfferDiscoPartyManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/028-PiggyBankPackData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/029-PlayerFishDataRod.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/030-PlayerItemData_Inflation.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/031-TotalRechargeManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/032-DebugFunc.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/033-EventFishingDuelPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/034-AEventDataManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/035-EventBingoData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/036-EventBreakData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/037-EventCanData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/038-EventCubeMeltManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/039-EventGatherCoreData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/040-EventLuckyGameModel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/041-EventOfferJourneyData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/042-EventOfferJourneyLvlTriggerData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/043-EventLuckMagicData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/044-EventWelcomeBackManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/045-FishingBehaviorB.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/046-InfiniteBuildingData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/047-LuckyADTaskPopupPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/048-LuckyTaskBtn.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/049-LuckyTaskPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/050-MatchGameManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/051-MiniBattlePassDataProvider.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/052-DiggingGameModel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/053-ChatService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/054-ClubService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/055-DeferredRewardStashService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/056-FootPrintService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/057-FriendService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/058-InGameMailHandler.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/059-KVUserService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/060-IKVUserLifecycle.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/061-IKVUserLoadReceiver.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/062-IPlayerSaveStore.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/063-PlayerKVGameLoadCoordinator.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/064-PlayerKVGameplayBindings.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/065-PlayerSaveStores.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/066-SurveyService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/067-UserService.KVFishingRewardValidation.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/068-UserService.KVFishingValidation.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/069-UserService.KVLoad.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/070-UserService.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/071-FishingStage.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/072-LoginStage.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/073-PFLoginAct.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/074-QuitAct.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/075-SubBoostrap.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/076-TimeRefreshManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/077-AdWheelManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/078-AdvertPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/079-DeBugPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/080-EventInviteFriends.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/081-JigsawPuzzleManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/082-OfferStoryChainManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/083-OfferSweepManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/084-OfferTreasureAscentManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/085-EventPartnerData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/086-EventPartnerEntryButton.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/087-EventPartnerStatuePlayfabData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/088-EventPartnerStatueTokenExchangeData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/089-EventPinataPackDataManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/090-PinballUncountableManager.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/091-BindAccountPopupPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/092-PlayerHeadPopupPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/093-SurveyPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/094-ShootingRangeData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/095-BlackFridayCouponData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/096-ChainPackWithProgressData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/097-ThanksGivingPackData.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/098-FishingFriendAddPanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/099-SocialRushArchitecture.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/100-FishingTurntablePanel.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/101-M2MergedContractTests.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/102-M2MergedGameplayTests.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/103-Program.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/104-Stubs.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C2d修改前快照/index.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/M2MergedGameplayTests.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/ServiceHost.csproj.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/Stubs.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/index.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-before/KVGameLoadTests.csproj.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-before/PlayerKVGameLoadCoordinator.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-before/PlayerKVLoginContext.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-final-verification.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-scope-verification.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-source-diff.patch create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-unity-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-unity-errors.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-unity-final-state.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-unity-loaded-api.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP1-unity-state.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/CP3A-prompt-validation.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2c差异方案业务流程保留补充-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2c补单保留原异步存档流程修订-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-after-timeout-state.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-debugconfig恢复记录.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-final-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-final-consume.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-final-modules.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-final-reward.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-final-state.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-fixture-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-fixture-regression-retry.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-fixture-regression.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-fixture-regression.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-pure-port-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C2d-合并CLI超时核对.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3a-ExitEnum.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3a-ExitInputs.targets create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3a-FactoryInputs.targets create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3a-equipment.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3a-final-state.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3a验证证据hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3a验证边界与执行记录-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3b-UserID兼容交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3b-UserID兼容接线裁决与执行记录-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c-KV跨账号实测增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c-KV跨账号读取实测-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c-KV跨账号读取实测结论-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c-SearchFriend正式只读实测-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c-SearchFriend正式实测增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c剩余SDK差异受审hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c剩余SDK接线独立差异审查-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c剩余SDK接线集中差异与待审方案-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c只读核查记录.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c好友列表线上事实补充-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c好友列表线上只读探测-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c好友列表线上只读探测-final-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c好友线上事实增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c完整审核前待确定事项-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c审查主会话裁决与资料缓存实施边界-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c审核更新复核检查点.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c客户端KV分支扫描.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c客户端剩余SDK扫描.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c客户端剩余核查与统计独立实施受审hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c客户端剩余核查源码基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c客户端剩余核查验证.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c客户端剩余项核查与本人统计独立实施待裁决-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c当前待设计与接线清单-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c当前待设计与接线清单受审hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c既有裁决与接口证据增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c既有裁决与接口证据复核-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c服务端接口事实确认单-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c本人统计KV暂存增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c本人统计KV暂存实施增量-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c本人统计KV暂存方案检查点.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c正式互加好友实测-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c正式互加好友实测-final-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c正式互加好友执行边界-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c正式互加好友结果与字段差异-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c正式好友操作增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c正式好友样例验证.ps1 create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c第二轮裁决核验与SearchFriend实测-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c第五轮状态核验hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c第五轮状态核验与缓存联动边界-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c第四轮裁决核验检查点.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c纯平移统一审查入口-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c纯平移统一审查基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c隔离边界修订与复审确认-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3c隔离边界复审增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity实际程序集时间.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity最终CSharp错误.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity最终强制编译.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity最终错误日志.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity编译.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity编译前状态.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity编译后状态.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d-Unity首次编译类型差异.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d交付与验证hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d开工源码基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3d资料缓存用户澄清与实施记录-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3e-Unity编译.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3e-Unity编译后状态.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3e交付与验证hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3e本人统计写裁决与实施记录-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3e源码范围核验.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-C3e生产差异.patch create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP1主会话关闭核验.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP1交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP1原ZCode独立实施复核提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP1实施交付与CP2输入-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP1独立实施复核.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP1独立实施复核主会话裁决与限定关闭-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2-D1源码事实基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A-C15补审后交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A-Editor编译核验.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A-Player条件编译补审实施与核验-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A-Player编译阻断受审基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A-Player编译阻断补审方案-待独立审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A-受审基线变化范围核验.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A-实施自验hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A主会话hash核验.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A原ZCode独立实施预复核提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A原ZCode独立方案审查提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A受审基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A实施自验与待复核边界-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A正式登录与原句柄交接完整方案-待独立审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A独立实施预复核.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A独立实施预复核主会话裁决-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A独立方案审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A独立方案审查主会话裁决与实施边界-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T-Editor编译核验.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T交付与待终审-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T原ZCode一次性批末独立实施复核提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T原ZCode一次性批级方案审查提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T受审基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T完整审查主会话裁决与实施白名单-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T正式KV普通业务请求恢复完整方案-待独立审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T独立实施复核.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T独立实施复核主会话裁决与限定关闭-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T独立方案审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B-T首轮独立报告主会话裁决与补审边界-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B客户端首场景线上合同待核矩阵-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2B首场景依赖增量核查-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2正式接线设计输入与新增阻断-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2现状源码基线-待设计.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP2首场景自动依赖核查-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-C11交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-C11交付与待终审-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-C5实施快照hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-Editor直开入口原ZCode补审提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-Editor直开入口最小补审-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-Editor直开入口独立补审.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-Editor直开入口补审主会话裁决与实施边界-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-Editor直开入口补审基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A-受审基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A原ZCode一次性批级方案审查提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A原ZCode批末独立实施复核提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A原句柄正式业务发布与B01提示接线完整方案-待独立审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A独立实施复核.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A独立实施复核主会话裁决与限定关闭-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A独立方案审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-CP3A联合独立审查主会话裁决与实施边界-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-DP1原ZCode一次性完整方案审查提示词.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-DP1受审基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-DP1独立方案审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-KVMgr层级依赖纠偏意见-待审.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-KV命名一致性只读盘点-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-KV替代范围重申-规则增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-KV替代范围重申与剩余SDK接线集中核查-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-LevelB与LastLogin只读证据hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-LevelB与LastLogin服务器只读核查及建议-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-LevelB保持PlayFab原语义裁决-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-PlayFab移植修改清单-分模块-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-修订1独立审查主会话裁决与新增阻断-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-修订2主会话hash核验.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-修订2独立复审主会话裁决与CP1实施边界-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-先存KV后联调方案增量hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-先存KV后联调的阶段移植方案-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-先移植后优化受审基线-修订1.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-先移植后优化完整方案-修订1-待独立审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-先移植后优化独立方案审查-修订1.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-先移植后优化独立方案审查提示词-修订1.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-加速与双Agent并行方案主会话可行性裁决-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-双提供方独立KV用户服务抽离方案-待完整评审-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-双提供方用户服务切换与KV独立实现约束-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C1-unity-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C1检查点与交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2a-unity-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2a实施记录-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2a检查点与交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2a自验汇总.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2b-unity-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2b实施记录-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2b检查点与交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2b自验汇总.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-unity-compile.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-固定验证.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-固定验证结果.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-旧奖励回归.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-旧奖励回归结果.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-旧奖励首败日志.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-旧消耗首败.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-旧消耗首败结果.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-旧装备消耗回归.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-旧装备消耗回归结果.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-退出状态.cs.txt create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c-退出状态结果.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c实施记录-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c检查点与交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c集中边界差异hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2c集中边界差异与后续连续开发方案-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2d检查点与交付hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批-C2调用迁移进度.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批修订复核裁决与正式前审边界-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批动态配置投影.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批原ZCode一次性正式前审提示词-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批存档调用实施台账.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批实施方案工作稿-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批审核节奏纠偏-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批工作稿修订版独立复核-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批工作稿独立预审意见-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批正式候选白名单.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批正式前审包自核.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批正式受审基线.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批正式实施方案-待完整审查-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批正式审查主会话裁决与实施记录-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批正式独立方案审查-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-合批预审主会话裁决-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-四项PlayFab能力迁移-服务端开发对接文档-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-四项服务端开发对接文档受审hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-好友KV资料接口设计受审hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-好友KV资料服务端接口设计-待完整审核-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-客户端致服务端线上合同集中问题单-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-当前开发进度与执行TODO-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-当前状态独立审核-防跑偏核查-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-当前调用矩阵-待核证.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-接手时已有Client改动hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-新主会话接手卡-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-旧方法与调用方合并设计底稿.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-最终通关前临时门控与忽略路径清理清单-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-本人LevelB与登录时间KV存储用户裁决-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-架构复审裁决与修复顺序-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-正式接线依赖受审基线-修订2.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-正式接线依赖独立复审-修订2.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-正式接线依赖补审提示词-修订2.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-正式接线依赖补审方案-修订2-待评审.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-等级榜接口设计受审hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-等级榜设计范围纠正-LevelB沿用原逻辑-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-等级榜设计范围纠正hash.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-等级榜读取与本人统计键接口设计-待完整审核-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-管理器同生态位替代策略-2026-09-29.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-纠偏与底稿独立审查.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-纯平移主会话裁决与C2d实施记录-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-纯平移核减基线核对-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-纯平移用户审查确认与C2d实施边界-2026-09-30.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-纯平移继续前核证记录-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/M2-纯平移范围纠偏与既有改动核减清单-2026-09-30.md create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/current-scan/calls.json create mode 100644 CodexOutput/upserver/B3BatchMigration/M2/current-scan/source-hashes.json create mode 100644 CodexOutput/upserver/KVGameLoadTests/CP2AExistingArchiveTests.cs create mode 100644 CodexOutput/upserver/KVGameLoadTests/CP2ARuntimeSelectionTests.cs create mode 100644 CodexOutput/upserver/KVGameLoadTests/GameHandoffTests.cs create mode 100644 CodexOutput/upserver/KVGameLoadTests/M2MergedContractTests.cs create mode 100644 CodexOutput/upserver/KVGameLoadTests/RegressionSupport/Dependencies.targets create mode 100644 CodexOutput/upserver/KVGameLoadTests/ServiceHost/C3IdentityCompatibilityTests.cs create mode 100644 CodexOutput/upserver/KVGameLoadTests/ServiceHost/C3ProfileCacheTests.cs create mode 100644 CodexOutput/upserver/KVGameLoadTests/ServiceHost/C3StatisticsWriteTests.cs create mode 100644 CodexOutput/upserver/KVGameLoadTests/ServiceHost/M2MergedGameplayTests.cs diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..d43435b4a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,9 @@ +# 项目通用开发规则 + +- KV模式的迁移目标是由KV管理器及其接线承接原PlayFab相关能力,不只迁个人存档;等级榜、公开资料、好友和匹配是原PlayFab调用的既有功能,不得当作新增产品需求、默认延期或直接转交服务端。先核客户端已有KV能力及等价调用映射;只有明确证实缺少必要能力时,才把具体接口证据集中写入沟通文档。不得反复要求用户确认“是否存KV”、新ID或原邮件流程。已审同合同替换连续实施,确有新合同或架构差异时一次合并评审,避免逐功能送审。 +- 整个迁移流程、所有阶段与批次均只做平移,不限于 M2。全部迁移完成前,仅修改完成迁移所必需的存储、身份和接口接线,保留原业务规则、调用顺序、同步/异步方式、返回值、异常处理和界面流程。不得夹带额外业务修正、优化或代码重构;不得以“更安全”“更合理”或“顺手修复”为由改变原逻辑。 +- 发现原有业务缺陷、代码结构问题或可优化点,统一记录到迁移完成后的待办,不在任何迁移阶段穿插处理。必须等整个迁移流程全部完成后,再由用户另行授权修正;单个阶段完成不构成提前修正的许可。此前方案或评审包含此类扩展时,以此规则及用户最新要求为准。 +- 最终闲置实现清理仅限本次迁移造成且经核实已无消费者的实现,不得借清理重构代码或删除原有有效功能。确有无法保持原流程的迁移障碍,先说明具体差异,不自行改写业务规则或冻结功能。 +- 在满足已确认的功能、正确性和必要安全边界的前提下,优先选择最简单、最直观、最容易维护的实现。抽象应服务于实际调用者;不要为假设中的扩展增加接口、适配器、管理器、状态机或重复保护层。 +- 修改代码前完成相关方案的完整评审,记录裁决和开发边界。评审新增抽象时,说明它解决的具体问题、实际调用点,以及为何复用或小幅修改现有实现不足;无法说明必要性的层次不要引入。 +- 同一事实保持单一来源,同一业务流程避免多重开关和重复状态。迁移中的临时路径须登记,最终通关前恢复或清理;最终代码删除闲置实现,但保留仍在使用的原有功能。 diff --git a/Client/Assets/Scripts/AOTScripts/Boostrap.cs b/Client/Assets/Scripts/AOTScripts/Boostrap.cs index 363fc1b79..859228009 100644 --- a/Client/Assets/Scripts/AOTScripts/Boostrap.cs +++ b/Client/Assets/Scripts/AOTScripts/Boostrap.cs @@ -503,7 +503,7 @@ public class Boostrap : MonoBehaviour private async Task AfterAssetUpdateV2() { bsLoading.SetProgress(0.15f); - await SubBoostrap.RegisterServices(ctx.gameObject); + await SubBoostrap.RegisterServices(ctx.gameObject, config); bsLoading.SetProgress(0.16f); await SubBoostrap.AfterAssetUpdate(config, bsLoading.SetProgress); bsLoading.SetProgress(0.18f); diff --git a/Client/Assets/Scripts/Activity/Data/EventDataRepository.cs b/Client/Assets/Scripts/Activity/Data/EventDataRepository.cs index f6a44fec4..8b55a0e42 100644 --- a/Client/Assets/Scripts/Activity/Data/EventDataRepository.cs +++ b/Client/Assets/Scripts/Activity/Data/EventDataRepository.cs @@ -9,6 +9,10 @@ namespace Activity.Data /// public class EventDataRepository : IEventDataRepository { + private readonly game.PlayerDataStorage.IPlayerSaveStore store; + public EventDataRepository(game.PlayerDataStorage.IPlayerSaveStore store) + { this.store = store ?? throw new ArgumentNullException(nameof(store)); } + public void Save(T data) where T : IEventData { if (data == null) @@ -23,7 +27,7 @@ namespace Activity.Data #if UNITY_EDITOR Debug.Log($"[EventDataRepository] Saving {typeof(T).Name}: {json}"); #endif - PlayFabMgr.Instance?.UpdateUserDataValue(typeof(T).Name, json); + store.Write(typeof(T).Name, json).RequireAccepted(); } catch (Exception e) { @@ -35,7 +39,7 @@ namespace Activity.Data { try { - var dataStr = PlayFabMgr.Instance?.GetLocalData(typeof(T).Name); + var dataStr = store.Read(typeof(T).Name).ValueOrThrow(); if (string.IsNullOrEmpty(dataStr)) return new T(); // #if UNITY_EDITOR // Debug.Log($"[EventDataRepository] Load {typeof(T).Name}: {dataStr}"); @@ -52,7 +56,7 @@ namespace Activity.Data public bool Exists() where T : IEventData { - var dataStr = PlayFabMgr.Instance?.GetLocalData(typeof(T).Name); + var dataStr = store.Read(typeof(T).Name).ValueOrThrow(); return !string.IsNullOrEmpty(dataStr); } } diff --git a/Client/Assets/Scripts/Activity/Services/EventTokenService.cs b/Client/Assets/Scripts/Activity/Services/EventTokenService.cs index 9f145dace..04ab69caa 100644 --- a/Client/Assets/Scripts/Activity/Services/EventTokenService.cs +++ b/Client/Assets/Scripts/Activity/Services/EventTokenService.cs @@ -28,6 +28,10 @@ namespace Activity.Services /// public class EventTokenService : IEventTokenService { + private readonly game.PlayerDataStorage.IPlayerSaveStore store; + public EventTokenService(game.PlayerDataStorage.IPlayerSaveStore store) + { this.store = store ?? throw new ArgumentNullException(nameof(store)); } + #region 常量与字段 private const string TransitionDataKey = "TransitionData"; @@ -75,7 +79,7 @@ namespace Activity.Services { try { - var dataStr = PlayFabMgr.Instance?.GetLocalData(TransitionDataKey); + var dataStr = store.Read(TransitionDataKey).ValueOrThrow(); if (!string.IsNullOrEmpty(dataStr)) { _tokenData.Clear(); @@ -106,7 +110,7 @@ namespace Activity.Services try { var json = Newtonsoft.Json.JsonConvert.SerializeObject(_tokenData); - PlayFabMgr.Instance?.UpdateUserDataValue(TransitionDataKey, json); + store.Write(TransitionDataKey, json).RequireAccepted(); #if UNITY_EDITOR Debug.Log($"[EventTokenService] Saved {_tokenData.Count} token entries to PlayFab"); #endif diff --git a/Client/Assets/Scripts/Aquarium/DataCenter/AquariumManager.cs b/Client/Assets/Scripts/Aquarium/DataCenter/AquariumManager.cs index 6397ef881..b12921a86 100644 --- a/Client/Assets/Scripts/Aquarium/DataCenter/AquariumManager.cs +++ b/Client/Assets/Scripts/Aquarium/DataCenter/AquariumManager.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using GameCore; @@ -12,6 +12,8 @@ using UnityEngine; public class AquariumManager { public const string AquariumEventDataNewKey = "AquariumEventDataNewKey"; + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore; + readonly IUserService loginUser; private cfg.Tables _tables; private ICustomServerMgr customServerMgr; public AquariumManagerData data { get; private set; } @@ -21,12 +23,15 @@ public class AquariumManager public List sellList; public AquariumManager() { + saveStore = GContext.container.Resolve(); + loginUser = GContext.container.Resolve(); _tables = GContext.container.Resolve(); customServerMgr = GContext.container.Resolve(); } - public static AquariumManagerData GetAquariumManagerData() + public static AquariumManagerData GetAquariumManagerData(game.PlayerDataStorage.IPlayerSaveStore store = null) { - string dataStr = PlayFabMgr.Instance.GetLocalData(AquariumEventDataNewKey); + var source = store ?? GContext.container.Resolve(); + string dataStr = source.Read(AquariumEventDataNewKey).ValueOrThrow(); if (!string.IsNullOrEmpty(dataStr)) { try @@ -43,7 +48,8 @@ public class AquariumManager public async Task Synchrodata() { //从服务器拿数据 - var dataSever = GetAquariumManagerData(); + if (!saveStore.IsCurrent) throw new OperationCanceledException(); + var dataSever = GetAquariumManagerData(saveStore); if (dataSever == null) { //新数据 @@ -63,8 +69,9 @@ public class AquariumManager return; } GetAquariumDataRequest request = new GetAquariumDataRequest(); - request.playFabId = GContext.container.Resolve().UserId; + request.playFabId = loginUser.UserId; string result = await customServerMgr.CustomServerPost("aquarium/GetAquariumData", Newtonsoft.Json.JsonConvert.SerializeObject(request)); + if (!saveStore.IsCurrent) throw new OperationCanceledException(); AquariumServerData serverData = null; if (result != null) { @@ -611,7 +618,7 @@ public class AquariumManager } void UpdateUserData() { - PlayFabMgr.Instance.UpdateUserDataValue(AquariumEventDataNewKey, data.Serialize()); + saveStore.Write(AquariumEventDataNewKey, data.Serialize()).RequireAccepted(); } void SaveData(bool all = false) { @@ -637,7 +644,7 @@ public class AquariumManager if (all) { UpdateAquariumAllDataRequest request = new UpdateAquariumAllDataRequest(); - request.playFabId = GContext.container.Resolve().UserId; + request.playFabId = loginUser.UserId; request.data = new AquariumServerData() { startTime = data.startTime, @@ -653,7 +660,7 @@ public class AquariumManager else { UpdateSlotDatasRequest request = new UpdateSlotDatasRequest(); - request.playFabId = GContext.container.Resolve().UserId; + request.playFabId = loginUser.UserId; request.slotDatas = data.slotDatas; request.cardLv = string.Join(',', cardLv); customServerMgr.CustomServerPost("aquarium/UpdateSlotData", Newtonsoft.Json.JsonConvert.SerializeObject(request)); diff --git a/Client/Assets/Scripts/Camp/CampDataMM.cs b/Client/Assets/Scripts/Camp/CampDataMM.cs index 72ba1be2c..6f1bc3082 100644 --- a/Client/Assets/Scripts/Camp/CampDataMM.cs +++ b/Client/Assets/Scripts/Camp/CampDataMM.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using GameCore; @@ -10,6 +10,8 @@ using UnityEngine; public class CampDataMM { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + private cfg.Tables _tables; MMTService _MMService; public CampDataMM(cfg.Tables tables, MMTService mmService) @@ -142,7 +144,7 @@ public class CampDataMM _isFix = isFix; if (isSave) { - PlayFabMgr.Instance.UpdateUserDataValue("IsFix", _isFix.ToString()); + SaveStore.Write("IsFix", _isFix.ToString()).RequireAccepted(); } } @@ -248,7 +250,7 @@ public class CampDataMM UpdateCurrentData(); } CampDataDic["CampId"] = Id; - PlayFabMgr.Instance.UpdateUserDataValue("CampDataDic", JsonMapper.ToJson(CampDataDic)); ; + SaveStore.Write("CampDataDic", JsonMapper.ToJson(CampDataDic)).RequireAccepted(); ; } else { @@ -276,7 +278,7 @@ public class CampDataMM if (NextMapID == -1 || !_tables.TbConstruction.DataMap.ContainsKey(NextMapID)) { _isOpenSkyscraper = "1"; - PlayFabMgr.Instance.UpdateUserDataValue("IsOpenSkyscraper", _isOpenSkyscraper); + SaveStore.Write("IsOpenSkyscraper", _isOpenSkyscraper).RequireAccepted(); return; } Debug.LogError( @@ -353,7 +355,7 @@ public class CampDataMM if (NextMapID == -1 || !_tables.TbConstruction.DataMap.ContainsKey(NextMapID)) { _isOpenSkyscraper = "1"; - PlayFabMgr.Instance.UpdateUserDataValue("IsOpenSkyscraper", _isOpenSkyscraper); + SaveStore.Write("IsOpenSkyscraper", _isOpenSkyscraper).RequireAccepted(); } } } diff --git a/Client/Assets/Scripts/Core/CustomServerMgr.cs b/Client/Assets/Scripts/Core/CustomServerMgr.cs index 058bf787c..1a38fbb46 100644 --- a/Client/Assets/Scripts/Core/CustomServerMgr.cs +++ b/Client/Assets/Scripts/Core/CustomServerMgr.cs @@ -4,6 +4,7 @@ using System; using System.Net; using System.Net.Http; using System.Text; +using System.Threading; using System.Threading.Tasks; using UnityEngine; using game.Account; @@ -39,23 +40,50 @@ public class CustomServerMgr : ICustomServerMgr private CookieContainer _cookie; private readonly Func handlerFactory; + private readonly SynchronizationContext ownerContext; public int SessionVersion { get; private set; } public event Action SessionChanged; PlayerKVAccountLease kvLease; bool kvOnly; + bool kvBusinessReady; + bool kvBusinessPublished; int pfRequests; internal event Action KVUnauthorized; internal bool IsFreshForKVLoad => pfRequests==0 && kvLease==null; internal void BindKVForValidation(PlayerKVAccountLease lease) { - if(lease==null || !lease.IsCurrent || lease.ApiBaseUri!=ApiBaseUri || !IsFreshForKVLoad) + if(lease==null || lease.IsFormal || !lease.IsCurrent || lease.ApiBaseUri!=ApiBaseUri || !IsFreshForKVLoad) throw new InvalidOperationException("Fresh matching KV lease required."); - kvOnly=true; SessionVersion++; kvLease=lease; _cookie=null; + kvOnly=true; kvBusinessReady=false; kvBusinessPublished=false; SessionVersion++; kvLease=lease; _cookie=null; var previous=client; client=null; previous?.Dispose(); SessionChanged?.Invoke(); } + internal void BindKVForGame(PlayerKVAccountLease lease) + { + if(lease==null || !lease.IsFormal || !lease.IsCurrent || lease.ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl || + ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl || !IsFreshForKVLoad) + throw new InvalidOperationException("Fresh formal KV lease required."); + kvOnly=true; kvBusinessReady=false; kvBusinessPublished=false; SessionVersion++; kvLease=lease; _cookie=null; + var previous=client; client=null; previous?.Dispose(); SessionChanged?.Invoke(); + } + internal void EnableKVBusiness(long epoch) + { + if(!kvOnly || kvBusinessReady || kvBusinessPublished || kvLease==null || !kvLease.IsFormal || !kvLease.IsCurrent || + kvLease.Epoch!=epoch || kvLease.ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl || + ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl) + throw new InvalidOperationException("Current formal KV lease required for business transport."); + kvBusinessPublished=true; kvBusinessReady=true; + } + internal void DisableKVBusiness() + { + if(!kvOnly || !kvBusinessReady) return; + kvBusinessReady=false; SessionVersion++; + try { SessionChanged?.Invoke(); } + catch(Exception ex) { Debug.LogError($"KV session change failed: {ex.GetType().Name}"); } + } + internal Task ClearKVForGame() => ClearKVForValidation(); internal Task ClearKVForValidation() { - SessionVersion++; var previous=kvLease; kvLease=null; + kvBusinessReady=false; SessionVersion++; var previous=kvLease; kvLease=null; _cookie=null; var closing=previous?.CloseAsync() ?? Task.CompletedTask; SessionChanged?.Invoke(); return closing; } @@ -74,13 +102,16 @@ public class CustomServerMgr : ICustomServerMgr } - public CookieContainer Cookie => _cookie ?? throw new System.NullReferenceException(); + public CookieContainer Cookie => kvOnly + ? (kvBusinessReady && kvLease?.IsFormal==true ? kvLease.FormalCookies : null) ?? throw new NullReferenceException() + : _cookie ?? throw new NullReferenceException(); public Uri ApiBaseUri { get; } public CustomServerMgr(IConfig config) : this(config, null) { } public CustomServerMgr(IConfig config, Func handlerFactory) { + ownerContext=SynchronizationContext.Current; this.handlerFactory = handlerFactory ?? (cookies => new HttpClientHandler { CookieContainer = cookies, UseCookies = true, AllowAutoRedirect = false @@ -125,7 +156,42 @@ public class CustomServerMgr : ICustomServerMgr // Unity callers use the main thread. Capture a fixed transport before the first await. private async Task SendAsync(HttpMethod method, string url, string body, string contentType) { - if(kvOnly) throw new InvalidOperationException("Only controlled validation routes are enabled."); + if(kvOnly) + { + if(ownerContext!=null && !ReferenceEquals(SynchronizationContext.Current,ownerContext)) + { + var completion=new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + ownerContext.Post(async _=> + { + try { completion.TrySetResult(await SendAsync(method,url,body,contentType)); } + catch(Exception ex) { completion.TrySetException(ex); } + },null); + return await completion.Task.ConfigureAwait(false); + } + if(!kvBusinessReady) throw new InvalidOperationException("Formal KV business transport is not ready."); + var lease=kvLease; var kvVersion=SessionVersion; + if(lease==null || !lease.IsFormal || !lease.IsCurrent) return null; + try + { + var response=await lease.SendAsync(method,url,body,contentType); + if(!kvBusinessReady || kvVersion!=SessionVersion || !ReferenceEquals(lease,kvLease) || !response.IsCurrent) + return null; + if(response.StatusCode==(int)HttpStatusCode.OK) return response.Body; + if(response.StatusCode==(int)HttpStatusCode.Unauthorized || response.StatusCode==(int)HttpStatusCode.Forbidden) + { + DisableKVBusiness(); + KVUnauthorized?.Invoke(SessionVersion); + } + else if(response.StatusCode.HasValue) + Debug.LogError($"API request failed: HTTP {response.StatusCode.Value}"); + return null; + } + catch(Exception e) + { + if(kvVersion==SessionVersion) Debug.LogError($"API request failed: {e.GetType().Name}"); + return null; + } + } pfRequests++; var transport = client; var version = SessionVersion; diff --git a/Client/Assets/Scripts/Core/KVMgr.cs b/Client/Assets/Scripts/Core/KVMgr.cs new file mode 100644 index 000000000..7dd95dfdf --- /dev/null +++ b/Client/Assets/Scripts/Core/KVMgr.cs @@ -0,0 +1,52 @@ +using System.Threading; +using System.Threading.Tasks; +using game.PlayerDataStorage; + +internal static class KVMgr +{ + internal static PlayerKVKeyReadResult ReadKV(PlayerKVGameSessionHandle handle, string key) + { + if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.ReadLocal)) + return new PlayerKVKeyReadResult(PlayerKVKeyReadError.LoadGuardActive, handle); + if (handle == null || !KVSnapshot.ValidKey(key)) + return new PlayerKVKeyReadResult(PlayerKVKeyReadError.InvalidInput, handle); + var read = handle.ReadLocalSnapshot(); + if (!read.Success) + return new PlayerKVKeyReadResult(read.Error == PlayerKVLocalReadError.StaleOrClosing + ? PlayerKVKeyReadError.StaleOrClosing : PlayerKVKeyReadError.NotReady, handle); + var found = read.Data.TryGetValue(key, out var value); + return new PlayerKVKeyReadResult(PlayerKVKeyReadError.None, handle, found, value); + } + + internal static PlayerKVEditResult WriteKV(PlayerKVGameSessionHandle handle, + string key, string value, bool remoteStore = true) + { + if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Update)) + return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Blocked)); + if (handle == null) + return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Validation)); + return handle.Update(key, value, remoteStore); + } + + internal static Task FlushKVAsync(PlayerKVGameSessionHandle handle, + CancellationToken waitToken = default) + { + if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync)) + return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Cancelled, + handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status)); + if (handle == null) + return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded)); + return handle.FlushAsync(waitToken); + } + + internal static Task WaitForKVTicketAsync(PlayerKVGameSessionHandle handle, + PlayerKVSyncTicket ticket, CancellationToken waitToken = default) + { + if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync)) + return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Cancelled, + handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status)); + if (handle == null) + return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded)); + return handle.WaitForTicketAsync(ticket, waitToken); + } +} diff --git a/Client/Assets/Scripts/Core/KVMgr.cs.meta b/Client/Assets/Scripts/Core/KVMgr.cs.meta new file mode 100644 index 000000000..4f52d1917 --- /dev/null +++ b/Client/Assets/Scripts/Core/KVMgr.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e96f727fbe08473c89bb88150927d2be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Client/Assets/Scripts/Core/PlayFabMgr.cs b/Client/Assets/Scripts/Core/PlayFabMgr.cs index 0bc421a98..faf13a402 100644 --- a/Client/Assets/Scripts/Core/PlayFabMgr.cs +++ b/Client/Assets/Scripts/Core/PlayFabMgr.cs @@ -320,6 +320,8 @@ public class PlayFabMgr : MonoBehaviour GameDebug.LogError("[PlayFabMgr]UpdateUserData Error: {0}", error.ToString()); } + internal void FlushBufferedData() => SyncData(); + public async Task SyncDataImmidiate(string key, string data) { #if UNITY_EDITOR && !SERVICE_HOST @@ -353,51 +355,4 @@ public class PlayFabMgr : MonoBehaviour return await taskSource.Task; } - // BEGIN KV explicit fixed-handle access - internal static PlayerKVKeyReadResult ReadKV(PlayerKVGameSessionHandle handle, string key) - { - if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.ReadLocal)) - return new PlayerKVKeyReadResult(PlayerKVKeyReadError.LoadGuardActive, handle); - if (handle == null || !KVSnapshot.ValidKey(key)) - return new PlayerKVKeyReadResult(PlayerKVKeyReadError.InvalidInput, handle); - var read = handle.ReadLocalSnapshot(); - if (!read.Success) - return new PlayerKVKeyReadResult(read.Error == PlayerKVLocalReadError.StaleOrClosing - ? PlayerKVKeyReadError.StaleOrClosing : PlayerKVKeyReadError.NotReady, handle); - var found = read.Data.TryGetValue(key, out var value); - return new PlayerKVKeyReadResult(PlayerKVKeyReadError.None, handle, found, value); - } - - internal static PlayerKVEditResult WriteKV(PlayerKVGameSessionHandle handle, - string key, string value, bool remoteStore = true) - { - if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Update)) - return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Blocked)); - if (handle == null) - return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Validation)); - return handle.Update(key, value, remoteStore); - } - - internal static Task FlushKVAsync(PlayerKVGameSessionHandle handle, - CancellationToken waitToken = default) - { - if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync)) - return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Cancelled, - handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status)); - if (handle == null) - return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded)); - return handle.FlushAsync(waitToken); - } - - internal static Task WaitForKVTicketAsync(PlayerKVGameSessionHandle handle, - PlayerKVSyncTicket ticket, CancellationToken waitToken = default) - { - if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync)) - return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Cancelled, - handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status)); - if (handle == null) - return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded)); - return handle.WaitForTicketAsync(ticket, waitToken); - } - // END KV explicit fixed-handle access } diff --git a/Client/Assets/Scripts/DataCenter/BargainPackData.cs b/Client/Assets/Scripts/DataCenter/BargainPackData.cs index 71e950965..8f6d049e3 100644 --- a/Client/Assets/Scripts/DataCenter/BargainPackData.cs +++ b/Client/Assets/Scripts/DataCenter/BargainPackData.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using GameCore; using UnityEngine; @@ -8,6 +8,8 @@ using System.Collections.Generic; public class BargainPackData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + private readonly Tables _tables = GContext.container.Resolve(); private readonly TbEventPackManager _epm = GContext.container.Resolve().TbEventPackManager; private readonly TbSpecialPack _spp = GContext.container.Resolve().TbSpecialPack; @@ -178,8 +180,8 @@ public class BargainPackData public void SaveData() { //Debug.LogError("Testing, data not saved for debug purpose."); - PlayFabMgr.Instance.UpdateUserDataValue("GeneralEventPackData", - Newtonsoft.Json.JsonConvert.SerializeObject(_data)); + SaveStore.Write("GeneralEventPackData", + Newtonsoft.Json.JsonConvert.SerializeObject(_data)).RequireAccepted(); } public void LoadData(GeneralEventPackData data) diff --git a/Client/Assets/Scripts/DataCenter/BattlePassData.cs b/Client/Assets/Scripts/DataCenter/BattlePassData.cs index 9122be5af..35de19450 100644 --- a/Client/Assets/Scripts/DataCenter/BattlePassData.cs +++ b/Client/Assets/Scripts/DataCenter/BattlePassData.cs @@ -33,6 +33,7 @@ public struct BpVipUnlock public class BattlePassData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } public BattlePassRecord BattlePassRecord; public BattleTask BattleTask; @@ -114,7 +115,7 @@ public class BattlePassData { string battlePassRecord = BattlePassRecord.SerializeObject(); string battleTask = BattleTask.SerializeObject(); - PlayFabMgr.Instance.UpdateUserDataValue("BattlePassRecordTask", battlePassRecord + "#" + battleTask); + playerSaveStore.Write("BattlePassRecordTask", battlePassRecord + "#" + battleTask).RequireAccepted(); } public void SaveBattlePassRecord() { diff --git a/Client/Assets/Scripts/DataCenter/BuffDataCenter.cs b/Client/Assets/Scripts/DataCenter/BuffDataCenter.cs index 5abb9b5f4..d8947dd18 100644 --- a/Client/Assets/Scripts/DataCenter/BuffDataCenter.cs +++ b/Client/Assets/Scripts/DataCenter/BuffDataCenter.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using GameCore; using System; @@ -6,6 +6,8 @@ using System.Collections.Generic; public class BuffDataCenter { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + private cfg.Tables _tables; public BuffDataCenter(cfg.Tables tables) { @@ -202,7 +204,7 @@ public class BuffDataCenter DateTime now = ZZTimeHelper.UtcNow().UtcNowOffset(); mapBuffData.buffEndTime = now.AddSeconds(buffData.CountDown); mapBuffDataList.Add(mapID, mapBuffData); - PlayFabMgr.Instance.UpdateUserDataValue("BuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(mapBuffDataList)); + SaveStore.Write("BuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(mapBuffDataList)).RequireAccepted(); return true; } } @@ -291,12 +293,12 @@ public class BuffDataCenter if (targetBuffDataList[i].buffID == fishBuffTimeData.buffID && targetBuffDataList[i].sourceID == fishBuffTimeData.sourceID) { targetBuffDataList[i] = fishBuffTimeData; - PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)); + SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted(); return; } } targetBuffDataList.Add(fishBuffTimeData); - PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)); + SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted(); } } else @@ -307,7 +309,7 @@ public class BuffDataCenter public void ClearTargetBuff() { targetBuffDataList.Clear(); - PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)); + SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted(); } /// /// CollectionTargetWeight的特殊处理 @@ -345,7 +347,7 @@ public class BuffDataCenter else if (fishItemId == eTKeepsake.FishIDList[collectionTargetWeight.TargetFishIndex - 1]) { item.isEnd = true; - PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)); + SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted(); break; } } @@ -455,7 +457,7 @@ public class BuffDataCenter fishBuffTimeData.addDown = buff.CountDown; showFishBuffIds.Add(fishBuffTimeData); } - PlayFabMgr.Instance.UpdateUserDataValue("GlobalBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(globalBuffDataList)); + SaveStore.Write("GlobalBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(globalBuffDataList)).RequireAccepted(); GContext.Publish(new AddGlobalBuffEvent(buffID)); } } @@ -559,7 +561,7 @@ public class BuffDataCenter } AddGlobalBuff(buff.BuffID); fishDailyBuff.isEnd = false; - PlayFabMgr.Instance.UpdateUserDataValue("FishDailyBuff", Newtonsoft.Json.JsonConvert.SerializeObject(fishDailyBuff)); + SaveStore.Write("FishDailyBuff", Newtonsoft.Json.JsonConvert.SerializeObject(fishDailyBuff)).RequireAccepted(); return fishDailyBuff; } } diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.FishingEventData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.FishingEventData.cs index 3ad2e11f0..68b1ddb8a 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.FishingEventData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.FishingEventData.cs @@ -1,4 +1,4 @@ -using Activity.Services; +using Activity.Services; using asap.core; using Assets.Scripts.UI.SocialRush; using cfg; @@ -56,6 +56,17 @@ namespace GameCore { public partial class FishingEventData : IDisposable { + game.PlayerDataStorage.IPlayerSaveStore boundSaveStore; + [Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore + { + get => boundSaveStore; + set + { + ThanksGivingPackData.BindSaveStore(value); + ChainPackWithProgressMigrationData.BindSaveStore(value); + boundSaveStore = value; + } + } private cfg.Tables _tables; private MMTService _mmtService; private IEventTokenService _eventTokenService; @@ -578,7 +589,7 @@ namespace GameCore id = t.ID, endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(), }; - PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeEventDic", JsonMapper.ToJson(fixedTimeEventDic)); + playerSaveStore.Write("FixedTimeEventDic", JsonMapper.ToJson(fixedTimeEventDic)).RequireAccepted(); } } switch (t.Type) @@ -846,7 +857,7 @@ namespace GameCore private bool Condition_NoRechargeSeconds(int timeSeconds) { - var lastPaymentStr = PlayFabMgr.Instance.GetLocalData("LastPaymentTime"); + var lastPaymentStr = playerSaveStore.Read("LastPaymentTime").ValueOrThrow(); DateTime curTime = ZZTimeHelper.UtcNow().UtcNowOffset(); DateTime endTime = curTime; if (string.IsNullOrEmpty(lastPaymentStr) || !lastPaymentStr.Contains("__")) @@ -866,7 +877,8 @@ namespace GameCore } public static bool Condition_NoRechargeDay(int timeDay = 7) { - var lastPaymentStr = PlayFabMgr.Instance.GetLocalData("LastPaymentTime"); + var store = GContext.container.Resolve().playerSaveStore; + var lastPaymentStr = store.Read("LastPaymentTime").ValueOrThrow(); if (!string.IsNullOrEmpty(lastPaymentStr) && lastPaymentStr.Contains("__")) return false; DateTime curTime = ZZTimeHelper.UtcNow(); @@ -1052,7 +1064,7 @@ namespace GameCore case 2: // Debug.Log($"[EventBreak] Id {e.ID} activated."); EventBreakAct.Ctx = EventBreakTableContext.ReadTables(e.ID, GContext.container.Resolve()); - var playfabData = EventBreakPfData.Deserialize(PlayFabMgr.Instance.GetLocalData(EventBreakPfData.PfKey)); + var playfabData = EventBreakPfData.Deserialize(playerSaveStore.Read(EventBreakPfData.PfKey).ValueOrThrow()); var eventBreakModel = GContext.container.Resolve(); if (eventBreakModel == null) { @@ -1074,7 +1086,7 @@ namespace GameCore break; case 4: var canModel = GContext.container.Resolve(); - var ecPlayfabString = PlayFabMgr.Instance.GetLocalData(EventCanPlayfabData.PlayFabKey); + var ecPlayfabString = playerSaveStore.Read(EventCanPlayfabData.PlayFabKey).ValueOrThrow(); var ecPpString = PlayerPrefs.GetString(EventCanPlayerPreferenceData.PlayerPrefsKey); var ecPlayfabData = EventCanPlayfabData.Deserialize(ecPlayfabString); var ecPlayerPrefsData = EventCanPlayerPreferenceData.Deserialize(ecPpString); @@ -1150,7 +1162,7 @@ namespace GameCore SetTurntable(t); break; case 3: - var pfString = PlayFabMgr.Instance.GetLocalData(EventLuckMagicPlayfabData.Key); + var pfString = playerSaveStore.Read(EventLuckMagicPlayfabData.Key).ValueOrThrow(); var pfData = EventLuckMagicPlayfabData.Deserialize(pfString); var ppString = PlayerPrefs.GetString(EventLuckMagicPlayerPreferenceData.Key); var ppData = EventLuckMagicPlayerPreferenceData.Deserialize(ppString); @@ -1339,7 +1351,7 @@ namespace GameCore SaveTransitionData(turntableEvent.ID, TurntableCoupon); } TurntableRed(); - PlayFabMgr.Instance.UpdateUserDataValue("TurntableRoll", TurntableCoupon.ToString()); + playerSaveStore.Write("TurntableRoll", TurntableCoupon.ToString()).RequireAccepted(); } public void RewardTurntableRoll(int value, bool remote = true) { @@ -1358,7 +1370,7 @@ namespace GameCore .AddContent("change_num", value); } #endif - PlayFabMgr.Instance.UpdateUserDataValue("TurntableRoll", TurntableCoupon.ToString(), remote); + playerSaveStore.Write("TurntableRoll", TurntableCoupon.ToString(), remote).RequireAccepted(); } public void TurntableRed() @@ -1443,7 +1455,7 @@ namespace GameCore void SetLimitedTimeEventDic() { - PlayFabMgr.Instance.UpdateUserDataValue("LimitedTimeEventDic", Newtonsoft.Json.JsonConvert.SerializeObject(limitedTimeEventDic)); + playerSaveStore.Write("LimitedTimeEventDic", Newtonsoft.Json.JsonConvert.SerializeObject(limitedTimeEventDic)).RequireAccepted(); } #region 目标奖励活动 @@ -1615,10 +1627,14 @@ namespace GameCore public async Task CheckResourceLoadQueue(string key, List label) { + var store = playerSaveStore; + if (!store.IsCurrent) return false; if (!collectingTargetResoure) { ILoadResourceService loadResourceService = GContext.container.Resolve(); - collectingTargetResoure = await loadResourceService.CheckResourceLoadQueue(key, label); + var loaded = await loadResourceService.CheckResourceLoadQueue(key, label); + if (!store.IsCurrent) return false; + collectingTargetResoure = loaded; } return collectingTargetResoure; } @@ -2241,8 +2257,8 @@ namespace GameCore public void UpdateTurnTableData() { - PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)); - PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelFreeCount", freecount.ToString()); + playerSaveStore.Write("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)).RequireAccepted(); + playerSaveStore.Write("WheelLevelFreeCount", freecount.ToString()).RequireAccepted(); } /// /// Add item by dropId and multiplier, or just return that item without giving to player, if doAdd is false. @@ -2263,10 +2279,10 @@ namespace GameCore { IncreaseScore(score * multiplier); WheelOperateCount++; - PlayFabMgr.Instance.UpdateUserDataValue("WheelOperateCount", WheelOperateCount.ToString()); + playerSaveStore.Write("WheelOperateCount", WheelOperateCount.ToString()).RequireAccepted(); AllWheelOperateCount += multiplier; - PlayFabMgr.Instance.UpdateUserDataValue("AllWheelOperateCount", AllWheelOperateCount.ToString()); + playerSaveStore.Write("AllWheelOperateCount", AllWheelOperateCount.ToString()).RequireAccepted(); } public void IncreaseScore(int score) { @@ -2283,7 +2299,7 @@ namespace GameCore } else { - PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)); + playerSaveStore.Write("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)).RequireAccepted(); } } @@ -2305,7 +2321,7 @@ namespace GameCore { freecount = 0; } - PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelFreeCount", freecount.ToString()); + playerSaveStore.Write("WheelLevelFreeCount", freecount.ToString()).RequireAccepted(); } //转盘等级增加函数 public void IncreaseWheelLevel() @@ -2325,7 +2341,7 @@ namespace GameCore // 更新积分进度 WheelLevelCount[wheelLevel.Level] = progress; TurntableRed(); - PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)); + playerSaveStore.Write("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)).RequireAccepted(); } } diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.GuideData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.GuideData.cs index 657b755de..5faa34d71 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.GuideData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.GuideData.cs @@ -41,6 +41,7 @@ namespace GameCore } public class GuideDataCenter : IDisposable { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } Tables _tables; PlayerData playerData; public GuideDataCenter(cfg.Tables tables, PlayerData playerData) @@ -94,7 +95,10 @@ namespace GameCore } public async void Init() { - guidanceDefineSetting = (GuidanceDefineSetting)await Addressables.LoadAssetAsync("GuidanceConfig"); + var store = playerSaveStore; + var setting = (GuidanceDefineSetting)await Addressables.LoadAssetAsync("GuidanceConfig"); + if (disposed || !store.IsCurrent) return; + guidanceDefineSetting = setting; if (guidanceDefineSetting != null) { bool isUpdate = false; @@ -495,7 +499,9 @@ namespace GameCore } async void TriggerGuide(string groupName, string curPanelName, GuidanceGroupDefine guidanceGroupDefine) { + var store = playerSaveStore; await System.Threading.Tasks.Task.Delay(200); + if (disposed || !store.IsCurrent) return; curSaveData = new GuideSaveData(); curSaveData.groupName = groupName; GuideSaveDataDic[groupName] = curSaveData; @@ -642,6 +648,7 @@ namespace GameCore } async void ShowPanel(string PanelName) { + if (disposed || !playerSaveStore.IsCurrent) return; if (curDefine.fingerType != FingerType.None) { disposable3 = GContext.OnEvent().Subscribe(GuideNextEvent); @@ -652,10 +659,13 @@ namespace GameCore public async void ShowGuidancePopupPanel(string nodeName) { + var store = playerSaveStore; + if (disposed || !store.IsCurrent) return; popupPanelNode = nodeName; if (!string.IsNullOrEmpty(popupPanelNode)) { await UIManager.Instance.ShowUI(UITypes.GuidancePopupPanel); + if (disposed || !store.IsCurrent) return; UIManager.Instance.HideUI(UITypes.GuidancePanel); } } @@ -712,11 +722,13 @@ namespace GameCore { List strings = GuideSaveDataDic.Select(kv => kv.Key + "|" + kv.Value.guideSubIndex + "|" + (kv.Value.isFinish ? "1" : "0")).ToList(); string value = string.Join(";", strings); - PlayFabMgr.Instance.UpdateUserDataValue("GuideSaveDataNew", value); + playerSaveStore.Write("GuideSaveDataNew", value).RequireAccepted(); } + bool disposed; public void Dispose() { + disposed = true; disposable?.Dispose(); disposable = null; disposable2?.Dispose(); diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.LeadboardData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.LeadboardData.cs index 0c7aaf919..e87daf30e 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.LeadboardData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.LeadboardData.cs @@ -2,9 +2,11 @@ using asap.core; using asap.playfab.async; using cfg; using game; +using game.PlayerDataStorage; using PlayFab.ClientModels; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using tysdk; @@ -162,6 +164,27 @@ namespace GameCore { Statistics.Add(new StatisticUpdate() { StatisticName = names[i], Value = value[i] }); } + if (userService is KVUserService kvUser) + { + var store = kvUser.SaveStore; + var writtenNames = new HashSet(StringComparer.Ordinal); + bool accepted = false; + foreach (var statistic in Statistics) + { + if (!writtenNames.Add(statistic.StatisticName)) continue; + var write = store.Write(statistic.StatisticName, statistic.Value.ToString(CultureInfo.InvariantCulture)); + if (write.Accepted) accepted = true; + else Debug.LogError("KV statistic write failed: " + statistic.StatisticName + ": " + write.Error); + } + if (accepted) + { + var confirmation = await store.FlushAsync(); + if (confirmation.Status != PlayerSaveStatus.Confirmed) + Debug.LogError("KV statistic save not confirmed: " + string.Join(",", writtenNames) + + ": " + confirmation.Status + ": " + confirmation.Error); + } + return; + } UpdatePlayerStatisticsRequest request = new UpdatePlayerStatisticsRequest() { Statistics = Statistics, diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerData.cs index 9ad8a803f..aa92b6e2b 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerData.cs @@ -17,6 +17,7 @@ namespace GameCore { public class PlayerData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } private cfg.Tables _tables; MMTService _MMService; public PlayerData(cfg.Tables tables, MMTService mmService) @@ -336,7 +337,7 @@ namespace GameCore if (!newRodList.Contains(id)) { newRodList.Add(id); - PlayFabMgr.Instance.UpdateUserDataValue("NewRodList", JsonMapper.ToJson(newRodList)); + playerSaveStore.Write("NewRodList", JsonMapper.ToJson(newRodList)).RequireAccepted(); if (addShowNewRod) { showNewRodList.Add(id); @@ -367,7 +368,7 @@ namespace GameCore public void RewardNewRod(int id) { newRodList.Remove(id); - PlayFabMgr.Instance.UpdateUserDataValue("NewRodList", JsonMapper.ToJson(newRodList)); + playerSaveStore.Write("NewRodList", JsonMapper.ToJson(newRodList)).RequireAccepted(); GContext.container.Resolve().SetRedPoint(); } @@ -1233,7 +1234,7 @@ namespace GameCore #if UNITY_EDITOR && !SERVICE_HOST if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled) return game.PlayerDataStorage.PlayerKVGameplayLoop.Write("NewPlayerDataDic",Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic),remote); #endif - PlayFabMgr.Instance.UpdateUserDataValue("NewPlayerDataDic", Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic), remote); + playerSaveStore.Write("NewPlayerDataDic", Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic), remote).RequireAccepted(); return null; } public void Init() @@ -1392,13 +1393,14 @@ namespace GameCore } public async void CoRecoveryEnergy(int energyRecoveryTime) { + var store = playerSaveStore; tokenSource?.Cancel(); tokenSource = new System.Threading.CancellationTokenSource(); var token = tokenSource.Token; _isRecoveryEnergy = true; int initEnergyRestorationSpeed = _tables.TbGlobalConfig.InitEnergyRestorationSpeed * 60; - while (Energy < MaxEnergy && !token.IsCancellationRequested) + while (Energy < MaxEnergy && !token.IsCancellationRequested && store.IsCurrent) { if (energyRecoveryTime >= initEnergyRestorationSpeed) { @@ -1431,7 +1433,7 @@ namespace GameCore SavePlayerData(); } await Awaiters.Seconds(1); - if (token.IsCancellationRequested) + if (token.IsCancellationRequested || !store.IsCurrent) { return; } @@ -1502,14 +1504,17 @@ namespace GameCore public async void OpenAppraisePopupPanel(int fishId) { + var store = playerSaveStore; + if (!store.IsCurrent) return; if (lastMapId != _tables.TbMapData.DataList[0].ID && !IsOpenAppraise) { var fishData = _tables.TbFishData.GetOrDefault(fishId); if (fishData != null && fishData.Quality >= 5) { await UIManager.Instance.ShowUI(UITypes.AppraisePopupPanel); + if (!store.IsCurrent) return; IsOpenAppraise = true; - PlayFabMgr.Instance.UpdateUserDataValue("IsOpenAppraise", "true"); + playerSaveStore.Write("IsOpenAppraise", "true").RequireAccepted(); } } } diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerFishData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerFishData.cs index a08c815f3..68b0c02fe 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerFishData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerFishData.cs @@ -52,6 +52,7 @@ namespace GameCore } public partial class PlayerFishData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } private cfg.Tables _tables; private ICustomServerMgr customServerMgr; public PlayerFishData(cfg.Tables tables, ICustomServerMgr customServerMgr) @@ -426,7 +427,7 @@ namespace GameCore { GContext.container.Resolve().AddNewRod(id); rodData.Add(id, 0); - PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData)); + playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted(); //鱼竿红点数据修改 RedPointManager.Instance.SetRedPointState(RedPointName.Home_Rod, true); } @@ -527,7 +528,7 @@ namespace GameCore .AddContent("rod_chips_consume", 0); } #endif - PlayFabMgr.Instance.UpdateUserDataValue("RodLevelData", JsonMapper.ToJson(rodLevelData)); + playerSaveStore.Write("RodLevelData", JsonMapper.ToJson(rodLevelData)).RequireAccepted(); GContext.container.Resolve().SetPearl(GContext.container.Resolve().pearl - count); } @@ -586,7 +587,7 @@ namespace GameCore } //鱼竿红点数据修改 CheckRodRedPointUp(); - PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData)); + playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted(); } public int GetRodPiece(int id) @@ -616,7 +617,7 @@ namespace GameCore } } - PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData)); + playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted(); } public void GMSetStarAll(int lv) @@ -642,7 +643,7 @@ namespace GameCore } } - PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData)); + playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted(); } public void GMAddAllFishMastery(bool all = false) @@ -1221,7 +1222,7 @@ namespace GameCore void MapNewUpdateUserDataValue(int mapID, Dictionary keyValuePairs) { Dictionary mapData = keyValuePairs.ToDictionary(_ => _.Key, _ => _.Value.Serialize()); - PlayFabMgr.Instance.UpdateUserDataValue($"Map_5_{mapID}", JsonMapper.ToJson(mapData)); + playerSaveStore.Write($"Map_5_{mapID}", JsonMapper.ToJson(mapData)).RequireAccepted(); } public int GetFishLevelByMap(int mapId) { @@ -1354,10 +1355,10 @@ namespace GameCore if (fishId != 0) { fishSwimToMapCount[id] = 0; - PlayFabMgr.Instance.UpdateUserDataValue("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount)); + playerSaveStore.Write("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount)).RequireAccepted(); } fishSwimToMap[id] = fishId; - PlayFabMgr.Instance.UpdateUserDataValue("FishSwimToMap", JsonMapper.ToJson(fishSwimToMap)); + playerSaveStore.Write("FishSwimToMap", JsonMapper.ToJson(fishSwimToMap)).RequireAccepted(); } public void SetFishSwimToMapCount(int id, int count) { @@ -1368,7 +1369,7 @@ namespace GameCore { SetFishSwimToMap(id, 0); } - PlayFabMgr.Instance.UpdateUserDataValue("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount)); + playerSaveStore.Write("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount)).RequireAccepted(); } } //===========================鱼图鉴=========================== @@ -1438,7 +1439,7 @@ namespace GameCore } GContext.container.Resolve().AddItemByDropList(dorpList, null); - PlayFabMgr.Instance.UpdateUserDataValue("MapProgress", Newtonsoft.Json.JsonConvert.SerializeObject(mapProgress)); + playerSaveStore.Write("MapProgress", Newtonsoft.Json.JsonConvert.SerializeObject(mapProgress)).RequireAccepted(); } public int GetAllPTSByMap(int mapID) diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerItemData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerItemData.cs index 04ebdc440..bee3bdf01 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerItemData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerItemData.cs @@ -1,4 +1,4 @@ -using cfg; +using cfg; using asap.core; using System.Collections.Generic; using System.Linq; diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerShopData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerShopData.cs index b68f7d001..70a26d979 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.PlayerShopData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.PlayerShopData.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using CodeStage.AntiCheat.ObscuredTypes; using game; @@ -73,6 +73,13 @@ namespace GameCore } public partial class PlayerShopData : IDisposable { + game.PlayerDataStorage.IPlayerSaveStore boundSaveStore; + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore + { + get => boundSaveStore; + set { CouponData.BindSaveStore(value); boundSaveStore = value; } + } + [Inject] public cfg.Tables _tables { get; set; } [Inject] @@ -250,7 +257,7 @@ namespace GameCore public void AddVoucher(int value) { Voucher = Voucher + value; - PlayFabMgr.Instance.UpdateUserDataValue("Voucher", Voucher.ToString()); + SaveStore.Write("Voucher", Voucher.ToString()).RequireAccepted(); } public void Init() { @@ -369,10 +376,10 @@ namespace GameCore if (Voucher >= iAPItemList.CostToken) { Voucher = Voucher - iAPItemList.CostToken; - PlayFabMgr.Instance.UpdateUserDataValue("Voucher", Voucher.ToString()); + SaveStore.Write("Voucher", Voucher.ToString()).RequireAccepted(); //二次弹窗 //回调 - PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{0}"); + SaveStore.Write("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{0}").RequireAccepted(); BuySuccess(buyType, iAPItemList, itemDataGift, rewardShowType, true); OrderManager.OrderManager.OnOrderSuccess(buyType, iAPItemList, itemDataGift, rewardShowType, true); if (!buyType.NoShow) @@ -429,7 +436,7 @@ namespace GameCore if (result.isSuccess) { - PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{sku.price}"); + SaveStore.Write("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{sku.price}").RequireAccepted(); BuySuccess(buyType, iAPItemList, itemDataGift, rewardShowType); OrderManager.OrderManager.OnOrderSuccess(buyType, iAPItemList, itemDataGift, rewardShowType); if (!buyType.NoShow) @@ -604,7 +611,7 @@ namespace GameCore } } } - PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{data.ProdPrice}"); + SaveStore.Write("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{data.ProdPrice}").RequireAccepted(); BuySuccess(data.BuyType, iAPItemList, itemDataGift, data.ShowType); if (data.BuyType.extraPurcheData != null) { @@ -628,7 +635,7 @@ namespace GameCore buyData[0] += iAPItemList.PaymentAmount; } buyData.Add(iAPItemList.ID); - PlayFabMgr.Instance.UpdateUserDataValue("BuyData", JsonMapper.ToJson(buyData)); + SaveStore.Write("BuyData", JsonMapper.ToJson(buyData)).RequireAccepted(); #if AGG GEvent.SetUserProp("Total_consumption", buyData[0]); #endif @@ -699,7 +706,7 @@ namespace GameCore } TurntableAdData = null; shopPackDailyBuyCount["0"] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear; - PlayFabMgr.Instance.UpdateUserDataValue("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount)); + SaveStore.Write("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount)).RequireAccepted(); } //} } @@ -729,7 +736,7 @@ namespace GameCore { shopPackDailyBuyCount["0"] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear; } - PlayFabMgr.Instance.UpdateUserDataValue("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount)); + SaveStore.Write("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount)).RequireAccepted(); } public int GetShopPackBuyCount(int id) { @@ -786,7 +793,7 @@ namespace GameCore { shopGiftBuyCount.Add(id, count); } - PlayFabMgr.Instance.UpdateUserDataValue("ShopGiftBuyCount", JsonMapper.ToJson(shopGiftBuyCount)); + SaveStore.Write("ShopGiftBuyCount", JsonMapper.ToJson(shopGiftBuyCount)).RequireAccepted(); } /// @@ -855,7 +862,7 @@ namespace GameCore index = 0, time = time.ToString() }; - PlayFabMgr.Instance.UpdateUserDataValue("ChainPackDataNew", JsonMapper.ToJson(ChainPackData)); + SaveStore.Write("ChainPackDataNew", JsonMapper.ToJson(ChainPackData)).RequireAccepted(); chainPackM = null; } if (chainPackM == null) @@ -897,7 +904,7 @@ namespace GameCore { AddAllPackCount(chainPackM.ID, 1); } - PlayFabMgr.Instance.UpdateUserDataValue("ChainPackDataNew", JsonMapper.ToJson(ChainPackData)); + SaveStore.Write("ChainPackDataNew", JsonMapper.ToJson(ChainPackData)).RequireAccepted(); //链式礼包 特殊处理 GContext.Publish(new TargetEvent(chainPackM.ID, 3, 10)); } @@ -927,7 +934,7 @@ namespace GameCore shopAllPackBuyCount.Add(id, count); } GContext.Publish(new ConditionTypeEvent(ConditionType.BuyPack, count)); - PlayFabMgr.Instance.UpdateUserDataValue("ShopAllPackBuyCount", JsonMapper.ToJson(shopAllPackBuyCount)); + SaveStore.Write("ShopAllPackBuyCount", JsonMapper.ToJson(shopAllPackBuyCount)).RequireAccepted(); } #endregion //========================================礼包======================================== @@ -965,7 +972,7 @@ namespace GameCore } } #endif - PlayFabMgr.Instance.UpdateUserDataValue("AdvertAllCount", JsonMapper.ToJson(advertCount)); + SaveStore.Write("AdvertAllCount", JsonMapper.ToJson(advertCount)).RequireAccepted(); GContext.Publish(new ResAddEvent(1006)); } public int GetAdticketCount() @@ -991,7 +998,7 @@ namespace GameCore { advertCount.Add(id, 1); } - PlayFabMgr.Instance.UpdateUserDataValue("AdvertAllCount", JsonMapper.ToJson(advertCount)); + SaveStore.Write("AdvertAllCount", JsonMapper.ToJson(advertCount)).RequireAccepted(); return advertCount[id]; } public void ClearAdvertCount() @@ -1006,7 +1013,7 @@ namespace GameCore advertCount[-1] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear; advertCount[0] = allCount; advertCount[-2] = ticket; - PlayFabMgr.Instance.UpdateUserDataValue("AdvertAllCount", JsonMapper.ToJson(advertCount)); + SaveStore.Write("AdvertAllCount", JsonMapper.ToJson(advertCount)).RequireAccepted(); } } else @@ -1050,7 +1057,7 @@ namespace GameCore AdConfig adConfig1 = adConfigs[VIPAdPackData.index - 1]; VIPAdPackData.cdTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(adConfig1.Interval).ToString(); } - PlayFabMgr.Instance.UpdateUserDataValue("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData)); + SaveStore.Write("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData)).RequireAccepted(); //GContext.Publish(new VIPAdPackDataEvent()); } public DateTime GetVIPAdPackTime() @@ -1082,7 +1089,7 @@ namespace GameCore VIPAdPackData = new AdvertData(); VIPAdPackData.day = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear; VIPAdPackData.isOpen = true; - PlayFabMgr.Instance.UpdateUserDataValue("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData)); + SaveStore.Write("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData)).RequireAccepted(); } public bool IsOpenAdPack() { @@ -1139,7 +1146,7 @@ namespace GameCore // { // isOverForToday = true; } - PlayFabMgr.Instance.UpdateUserDataValue("TurntableAdData", Newtonsoft.Json.JsonConvert.SerializeObject(TurntableAdData)); + SaveStore.Write("TurntableAdData", Newtonsoft.Json.JsonConvert.SerializeObject(TurntableAdData)).RequireAccepted(); // GContext.Publish(new VIPAdPackDataEvent()); } public bool IsTurntableAdMaxOut() @@ -1233,7 +1240,7 @@ namespace GameCore { _diamondShopItemRecords[itemShopId].hasBought = 1; SetItemShopRedPoint(); - PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords)); + SaveStore.Write("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords)).RequireAccepted(); } @@ -1248,7 +1255,7 @@ namespace GameCore { RefreshItemShop(); _diamondShopRefreshCount++; - PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString()); + SaveStore.Write("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString()).RequireAccepted(); } } @@ -1288,8 +1295,8 @@ namespace GameCore _diamondShopRefreshTime = new DateTime(now.Year, now.Month, now.Day).AddDays(1) + timeSpan; _diamondShopRefreshCount = 0; - PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString()); - PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopRefreshTime", _diamondShopRefreshTime.ToString()); + SaveStore.Write("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString()).RequireAccepted(); + SaveStore.Write("DiamondShopRefreshTime", _diamondShopRefreshTime.ToString()).RequireAccepted(); RefreshItemShop(); } private void RefreshItemShop() @@ -1364,7 +1371,7 @@ namespace GameCore } } - PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords)); + SaveStore.Write("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords)).RequireAccepted(); SetItemShopRedPoint(); } #endregion diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.SignupData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.SignupData.cs index d87e23ce1..3bd41007b 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.SignupData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.SignupData.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using LitJson; @@ -29,6 +29,8 @@ namespace GameCore } public class SigninData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + private cfg.Tables _tables; public SigninData(cfg.Tables tables) { @@ -102,7 +104,7 @@ namespace GameCore } if (isSave) { - PlayFabMgr.Instance.UpdateUserDataValue("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent)); + SaveStore.Write("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent)).RequireAccepted(); } bool isReward = CanDailySign(); if (isReward) @@ -154,7 +156,7 @@ namespace GameCore } } //GContext.Publish(new ShowData()); - PlayFabMgr.Instance.UpdateUserDataValue("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent)); + SaveStore.Write("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent)).RequireAccepted(); GContext.Publish(new OnSignEvent() { itemDataList = monthlySignReward }); } return isSign; diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.SmallGame.cs b/Client/Assets/Scripts/DataCenter/DataCenter.SmallGame.cs index 80f92d9b5..dd388e975 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.SmallGame.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.SmallGame.cs @@ -20,6 +20,7 @@ namespace GameCore } public class SmallGameData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } private cfg.Tables _tables; IUserService userService; ICustomServerMgr customServerMgr; @@ -76,7 +77,7 @@ namespace GameCore public void SaveHeistGameCount() { _heistGameCount++; - PlayFabMgr.Instance.UpdateUserDataValue("HeistGameCount", _heistGameCount.ToString()); + playerSaveStore.Write("HeistGameCount", _heistGameCount.ToString()).RequireAccepted(); } public void SetBombGameCount(int value) { @@ -85,7 +86,7 @@ namespace GameCore public void SaveBombGameCount() { _bombGameCount++; - PlayFabMgr.Instance.UpdateUserDataValue("BombGameCount", _bombGameCount.ToString()); + playerSaveStore.Write("BombGameCount", _bombGameCount.ToString()).RequireAccepted(); } public void SetFishHuntGameCount(int value) { @@ -94,7 +95,7 @@ namespace GameCore public void SaveFishHuntGameCount() { _fishHuntGameCount++; - PlayFabMgr.Instance.UpdateUserDataValue("FishHuntGameCount", _fishHuntGameCount.ToString()); + playerSaveStore.Write("FishHuntGameCount", _fishHuntGameCount.ToString()).RequireAccepted(); } #region 小游戏仇人 public List opponentItemDatas = new List(); diff --git a/Client/Assets/Scripts/DataCenter/DataCenter.TriggerPackData.cs b/Client/Assets/Scripts/DataCenter/DataCenter.TriggerPackData.cs index 36133eee0..ad7827993 100644 --- a/Client/Assets/Scripts/DataCenter/DataCenter.TriggerPackData.cs +++ b/Client/Assets/Scripts/DataCenter/DataCenter.TriggerPackData.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using LitJson; @@ -38,6 +38,8 @@ namespace GameCore } public class TriggerPackData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + Tables _tables; PlayerShopData playerShopData; public TriggerPackData(Tables tables) @@ -220,7 +222,7 @@ namespace GameCore id = t.ID, endTime = dateTime.AddSeconds(fixedTime.EndTime).ToString(), }; - PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)); + SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted(); TriggerPackBuyData _newSignEvent = null; for (int i = 0; i < triggerPackList.Count; i++) @@ -251,7 +253,7 @@ namespace GameCore _newSignEvent.vipLevel = GetVIPLevel(t.PackType); } GContext.container.Resolve().AddGiftFaceUIOnLogin(_newSignEvent.ID, UITypes.AdsPackPanel, _newSignEvent.lastID); - PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)); + SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted(); } } @@ -287,7 +289,7 @@ namespace GameCore endTime = time, }; fixedTimeShopDic[t.ID] = fixedTimeEvent; - PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)); + SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted(); } else if (t.TimeDefinition is LimitedTime) { @@ -306,7 +308,7 @@ namespace GameCore }; triggerPackList.Insert(0, _newSignEvent); playerShopData.AddShopPackDailyBuyCount(t.PackType, 1, false); - PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)); + SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted(); } } /// @@ -337,7 +339,7 @@ namespace GameCore endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(), }; - PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)); + SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted(); } if (FixedTimeEventExpired(t.ID)) { @@ -370,7 +372,7 @@ namespace GameCore endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(), }; - PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)); + SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted(); } if (FixedTimeEventExpired(t.ID)) { @@ -472,7 +474,7 @@ namespace GameCore } if (isUpdate) { - PlayFabMgr.Instance.UpdateUserDataValue("GiftVIPDData", JsonMapper.ToJson(giftVIPDData)); + SaveStore.Write("GiftVIPDData", JsonMapper.ToJson(giftVIPDData)).RequireAccepted(); } } } @@ -516,7 +518,7 @@ namespace GameCore }; } giftVIPDData[PackType] = giftVIPD; - PlayFabMgr.Instance.UpdateUserDataValue("GiftVIPDData", JsonMapper.ToJson(giftVIPDData)); + SaveStore.Write("GiftVIPDData", JsonMapper.ToJson(giftVIPDData)).RequireAccepted(); } } #region 触发礼包 @@ -573,7 +575,7 @@ namespace GameCore }; triggerPackList.Insert(0, _newSignEvent); playerShopData.AddShopPackDailyBuyCount(t.PackType, 1, false); - PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)); + SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted(); } } public void AddTriggerPackCount(int id) @@ -586,7 +588,7 @@ namespace GameCore { triggerPackList.Remove(triggerPackList[i]); } - PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)); + SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted(); break; } } @@ -641,7 +643,7 @@ namespace GameCore { triggerPackList.Remove(dailySignEvent); GContext.Publish(new TriggerPackEvent()); - PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)); + SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted(); } return endTime - curTime; } diff --git a/Client/Assets/Scripts/DataCenter/EventPackData.cs b/Client/Assets/Scripts/DataCenter/EventPackData.cs index 78fdf29e2..f146e69d7 100644 --- a/Client/Assets/Scripts/DataCenter/EventPackData.cs +++ b/Client/Assets/Scripts/DataCenter/EventPackData.cs @@ -3,6 +3,7 @@ using GameCore; using cfg; public class EventPackData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } private Tables _tables = GContext.container.Resolve(); private struct Data { @@ -100,8 +101,8 @@ public class EventPackData } public void SaveEventPackData() { - PlayFabMgr.Instance.UpdateUserDataValue("EventPackData", - Newtonsoft.Json.JsonConvert.SerializeObject(_data)); + playerSaveStore.Write("EventPackData", + Newtonsoft.Json.JsonConvert.SerializeObject(_data)).RequireAccepted(); } private void TriggerEventPack() { diff --git a/Client/Assets/Scripts/DataCenter/EventPartnerGatherManager.cs b/Client/Assets/Scripts/DataCenter/EventPartnerGatherManager.cs index 3ba5697d3..cc77fb685 100644 --- a/Client/Assets/Scripts/DataCenter/EventPartnerGatherManager.cs +++ b/Client/Assets/Scripts/DataCenter/EventPartnerGatherManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -100,6 +100,8 @@ namespace DataCenter // EventPartnerGather 管理器 public class EventPartnerGatherManager : IAutoMatchManagerContext { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + private const bool EnableTraceLogs = false; public const string SaveKey = "EventPartnerGatherData"; internal static game.PlayerDataStorage.PlayerKVPartnerState DecodeForKVLoad( @@ -864,7 +866,7 @@ namespace DataCenter Trace($"SaveData eventId={EventId}"); #endif { - PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(GatherData)); + SaveStore.Write(SaveKey, JsonConvert.SerializeObject(GatherData)).RequireAccepted(); } } public void LoadData(string dataValue) diff --git a/Client/Assets/Scripts/DataCenter/EventPinballDataManager.cs b/Client/Assets/Scripts/DataCenter/EventPinballDataManager.cs index 510ec9b71..2510230a3 100644 --- a/Client/Assets/Scripts/DataCenter/EventPinballDataManager.cs +++ b/Client/Assets/Scripts/DataCenter/EventPinballDataManager.cs @@ -11,6 +11,7 @@ namespace game { public class EventPinballDataManager { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } #if UNITY_EDITOR private bool m_IsCheckCondition = true; @@ -375,7 +376,7 @@ namespace game public void SyncData() { if (!m_IsSyncData) return; - PlayFabMgr.Instance.UpdateUserDataValue(EventPinballConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PinballData)); + playerSaveStore.Write(EventPinballConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PinballData)).RequireAccepted(); } #endregion diff --git a/Client/Assets/Scripts/DataCenter/EventPotionDataManager.cs b/Client/Assets/Scripts/DataCenter/EventPotionDataManager.cs index 21d1f61c9..d58015968 100644 --- a/Client/Assets/Scripts/DataCenter/EventPotionDataManager.cs +++ b/Client/Assets/Scripts/DataCenter/EventPotionDataManager.cs @@ -13,6 +13,7 @@ namespace game { public class EventPotionDataManager { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } #if UNITY_EDITOR private bool m_IsCheckCondition = true; private bool m_IsSyncData = true; @@ -572,7 +573,7 @@ namespace game public void SyncData() { if (!m_IsSyncData) return; - PlayFabMgr.Instance.UpdateUserDataValue(EventPotionConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PotionData)); + playerSaveStore.Write(EventPotionConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PotionData)).RequireAccepted(); } public PotionItemData GetOperationItemData() { diff --git a/Client/Assets/Scripts/DataCenter/EventScratchTicketDataManager.cs b/Client/Assets/Scripts/DataCenter/EventScratchTicketDataManager.cs index d4bd33e31..6e675e89f 100644 --- a/Client/Assets/Scripts/DataCenter/EventScratchTicketDataManager.cs +++ b/Client/Assets/Scripts/DataCenter/EventScratchTicketDataManager.cs @@ -14,6 +14,7 @@ namespace game { public class EventScratchTicketDataManager { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } #if UNITY_EDITOR private bool m_IsCheckCondition = true; private bool m_IsSyncData = true; @@ -594,7 +595,7 @@ namespace game public void SyncData() { if (!m_IsSyncData) return; - PlayFabMgr.Instance.UpdateUserDataValue(EventScratchTicketConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_ScratchTicketData)); + playerSaveStore.Write(EventScratchTicketConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_ScratchTicketData)).RequireAccepted(); } List magList = new List() { 1, 5, 10, 20 }; diff --git a/Client/Assets/Scripts/DataCenter/FishingChallengeManager.cs b/Client/Assets/Scripts/DataCenter/FishingChallengeManager.cs index cbcbb3847..63d91899a 100644 --- a/Client/Assets/Scripts/DataCenter/FishingChallengeManager.cs +++ b/Client/Assets/Scripts/DataCenter/FishingChallengeManager.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using GameCore; @@ -40,6 +40,8 @@ public class FishingChallengeData public class FishingChallengeManager { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + // private const string SaveKey = "FishingChallengeData"; @@ -69,7 +71,11 @@ public class FishingChallengeManager game.PlayerDataStorage.PlayerKVSaveSchema.DecodeChallenge(raw,snapshot,errors); internal void ResetForKVLoad() { - fishingChallengeData=null; IsInit=false; PrefabName=null; TopRankTier=Rank=FullStep=PlayerFullNumber=PreScore=_cheatingScore=0; + fishingChallengeData=null; IsInit=false; PrefabName=null; +#if UNITY_EDITOR + _cheatingScore=0; +#endif + TopRankTier=Rank=FullStep=PlayerFullNumber=PreScore=0; CurFishingEventData=null; StartTime=EndTime=default; eventChallengeMain=null; eventChallengeConfig=null; challengeMapData=null; itemDataList=null; _stageDropList.Clear(); _eliminateListScore.Clear(); _eventTrackStageList=new List(); _eventTrackNormalRewardList=new List(); InVisibleReason=string.Empty; } @@ -1081,7 +1087,7 @@ public class FishingChallengeManager private void DoSave() { - PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(fishingChallengeData)); + SaveStore.Write(SaveKey, JsonConvert.SerializeObject(fishingChallengeData)).RequireAccepted(); } public string GetOpenEventKey() diff --git a/Client/Assets/Scripts/DataCenter/FishingEventData_OneOne.cs b/Client/Assets/Scripts/DataCenter/FishingEventData_OneOne.cs index c4f67514b..9cecd6711 100644 --- a/Client/Assets/Scripts/DataCenter/FishingEventData_OneOne.cs +++ b/Client/Assets/Scripts/DataCenter/FishingEventData_OneOne.cs @@ -19,7 +19,7 @@ namespace GameCore { if (Pack1A1Data == null) { - string json_duelData = PlayFabMgr.Instance.GetLocalData(Pack1A1DataKey); + string json_duelData = playerSaveStore.Read(Pack1A1DataKey).ValueOrThrow(); if (json_duelData != null) { Pack1A1Data = Newtonsoft.Json.JsonConvert.DeserializeObject(json_duelData); @@ -42,7 +42,7 @@ namespace GameCore }; RedPointManager.Instance.SetRedPointState(HomeBtnOneOnePack.redKey, false); - PlayFabMgr.Instance.UpdateUserDataValue(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data)); + playerSaveStore.Write(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data)).RequireAccepted(); } public void SetPack1A1Index(int index) { @@ -58,7 +58,7 @@ namespace GameCore GContext.Publish(new TargetEvent(Pack1A1Data.lastID, 3, 11)); } RedPointManager.Instance.SetRedPointState(HomeBtnOneOnePack.redKey, Pack1A1Data.index == 1); - PlayFabMgr.Instance.UpdateUserDataValue(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data)); + playerSaveStore.Write(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data)).RequireAccepted(); } public int GetPack1A1Index() { diff --git a/Client/Assets/Scripts/DataCenter/FishingEventData_OneTwo.cs b/Client/Assets/Scripts/DataCenter/FishingEventData_OneTwo.cs index 220845283..bf3d09205 100644 --- a/Client/Assets/Scripts/DataCenter/FishingEventData_OneTwo.cs +++ b/Client/Assets/Scripts/DataCenter/FishingEventData_OneTwo.cs @@ -50,7 +50,7 @@ namespace GameCore { if (Pack1A2Data == null) { - string json_duelData = PlayFabMgr.Instance.GetLocalData(Pack1A2DataKey); + string json_duelData = playerSaveStore.Read(Pack1A2DataKey).ValueOrThrow(); if (json_duelData != null) { Pack1A2Data = Newtonsoft.Json.JsonConvert.DeserializeObject(json_duelData); @@ -74,7 +74,7 @@ namespace GameCore SetType(); SetRodDstId(); SetChainPackRed(); - PlayFabMgr.Instance.UpdateUserDataValue(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data)); + playerSaveStore.Write(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data)).RequireAccepted(); } void SetType() { @@ -109,7 +109,7 @@ namespace GameCore return; } Pack1A2Data.index++; - PlayFabMgr.Instance.UpdateUserDataValue(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data)); + playerSaveStore.Write(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data)).RequireAccepted(); SetChainPackRed(); } void SetChainPackRed() diff --git a/Client/Assets/Scripts/DataCenter/FishingEvent_PVPData.cs b/Client/Assets/Scripts/DataCenter/FishingEvent_PVPData.cs index 2e807e9d7..4062f816b 100644 --- a/Client/Assets/Scripts/DataCenter/FishingEvent_PVPData.cs +++ b/Client/Assets/Scripts/DataCenter/FishingEvent_PVPData.cs @@ -87,9 +87,12 @@ namespace GameCore } public async void ShowRankTierChange() { + var store = playerSaveStore; + if (!store.IsCurrent) return; if (rankTierChangeState > 0 && curSolomain != null) { GameObject go = await UIManager.Instance.ShowUI(UITypes.EventFishingDuelRankChangePopupPanel); + if (!store.IsCurrent) return; EventFishingDuelRankChangePopupPanel changePopupPanel = go.GetComponent(); changePopupPanel.SetRank(rankTierChangeState == 1, curSolomain); rankTierChangeState = 0; @@ -98,7 +101,7 @@ namespace GameCore } public void SoloCheckClaimReward() { - string json_duelData = PlayFabMgr.Instance.GetLocalData(FishingDuelManager.SoloDataKey); + string json_duelData = playerSaveStore.Read(FishingDuelManager.SoloDataKey).ValueOrThrow(); if (json_duelData != null) { duelData = Newtonsoft.Json.JsonConvert.DeserializeObject(json_duelData); @@ -120,7 +123,7 @@ namespace GameCore duelData.rewardEventID = 0; duelData.preProgress = 0; string json_duelData = Newtonsoft.Json.JsonConvert.SerializeObject(duelData); - PlayFabMgr.Instance.UpdateUserDataValue(FishingDuelManager.SoloDataKey, json_duelData); + playerSaveStore.Write(FishingDuelManager.SoloDataKey, json_duelData).RequireAccepted(); } } public void GMAddSoloProgress(int count) @@ -133,7 +136,7 @@ namespace GameCore } public void InitSoloData(FishingEvent t) { - string json_duelData = PlayFabMgr.Instance.GetLocalData(FishingDuelManager.SoloDataKey); + string json_duelData = playerSaveStore.Read(FishingDuelManager.SoloDataKey).ValueOrThrow(); if (json_duelData != null) { duelData = Newtonsoft.Json.JsonConvert.DeserializeObject(json_duelData); @@ -262,7 +265,7 @@ namespace GameCore public void AddPVPToken(int value) { PVPToken += value; - PlayFabMgr.Instance.UpdateUserDataValue("PVPToken", PVPToken.ToString()); + playerSaveStore.Write("PVPToken", PVPToken.ToString()).RequireAccepted(); if (value < 0 && duelData != null) { duelData.rePVPToken -= value; @@ -272,7 +275,7 @@ namespace GameCore public void SaveDuelData() { string json_duelData = Newtonsoft.Json.JsonConvert.SerializeObject(duelData); - PlayFabMgr.Instance.UpdateUserDataValue(FishingDuelManager.SoloDataKey, json_duelData); + playerSaveStore.Write(FishingDuelManager.SoloDataKey, json_duelData).RequireAccepted(); } #endregion SoloData } diff --git a/Client/Assets/Scripts/DataCenter/OfferChainsChestManager.cs b/Client/Assets/Scripts/DataCenter/OfferChainsChestManager.cs index f313b3ba4..e21d41220 100644 --- a/Client/Assets/Scripts/DataCenter/OfferChainsChestManager.cs +++ b/Client/Assets/Scripts/DataCenter/OfferChainsChestManager.cs @@ -41,6 +41,7 @@ namespace DataCenter public class OfferChainsChestManager { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } public const string SaveKey = "OfferChainsChestData"; [Inject] public Tables _tables { get; set; } @@ -277,7 +278,7 @@ namespace DataCenter private void SaveData() { ELog($"SaveData-> {JsonConvert.SerializeObject(OfferChainsData)}"); - PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(OfferChainsData)); + playerSaveStore.Write(SaveKey, JsonConvert.SerializeObject(OfferChainsData)).RequireAccepted(); } public void LoadData(string dataValue) @@ -289,6 +290,7 @@ namespace DataCenter // 进入游戏舞台 public async void OnEnterGameAct() { + if (!playerSaveStore.IsCurrent) return; Log("OnEnterGameAct()"); IsFirstOpen = false; await UIManager.Instance.ShowUI(new UIType(OfferChainsChestMain.UIPanel)); diff --git a/Client/Assets/Scripts/DataCenter/OfferDiscoPartyManager.cs b/Client/Assets/Scripts/DataCenter/OfferDiscoPartyManager.cs index 95470678a..595bd3e30 100644 --- a/Client/Assets/Scripts/DataCenter/OfferDiscoPartyManager.cs +++ b/Client/Assets/Scripts/DataCenter/OfferDiscoPartyManager.cs @@ -44,6 +44,7 @@ namespace DataCenter // Disco Manager public class OfferDiscoPartyManager { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } public const string SaveKey = "OfferDiscoPartyManager"; // 免费抽奖次数 @@ -291,7 +292,7 @@ namespace DataCenter private void SaveData() { - PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(OfferDiscoPartyData)); + playerSaveStore.Write(SaveKey, JsonConvert.SerializeObject(OfferDiscoPartyData)).RequireAccepted(); } public void LoadData(string dataValue) @@ -309,6 +310,7 @@ namespace DataCenter public async void OnEnterGameAct() { + if (!playerSaveStore.IsCurrent) return; ELog("OnEnterGameAct()"); IsFirstOpen = false; await UIManager.Instance.ShowUI(new UIType(OfferDiscoParty.UIPanel)); diff --git a/Client/Assets/Scripts/DataCenter/PiggyBankPackData.cs b/Client/Assets/Scripts/DataCenter/PiggyBankPackData.cs index 1e48cd6d5..b3cd6df1e 100644 --- a/Client/Assets/Scripts/DataCenter/PiggyBankPackData.cs +++ b/Client/Assets/Scripts/DataCenter/PiggyBankPackData.cs @@ -8,6 +8,7 @@ using game; using System.Linq; public class PiggyBankPackData { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; } private readonly Tables _tables = GContext.container.Resolve(); private readonly TbEventPackManager _epm = GContext.container.Resolve().TbEventPackManager; @@ -193,8 +194,8 @@ public class PiggyBankPackData } public void SaveData() { - PlayFabMgr.Instance.UpdateUserDataValue("PiggyBankPackData", - Newtonsoft.Json.JsonConvert.SerializeObject(_data)); + playerSaveStore.Write("PiggyBankPackData", + Newtonsoft.Json.JsonConvert.SerializeObject(_data)).RequireAccepted(); } public bool AddProgress(int fishTier, int magnification) { diff --git a/Client/Assets/Scripts/DataCenter/PlayerFishDataRod.cs b/Client/Assets/Scripts/DataCenter/PlayerFishDataRod.cs index 08021504b..ea6328ae1 100644 --- a/Client/Assets/Scripts/DataCenter/PlayerFishDataRod.cs +++ b/Client/Assets/Scripts/DataCenter/PlayerFishDataRod.cs @@ -74,7 +74,7 @@ namespace GameCore public void SaveInitRodAccessoriesData() { string value = Newtonsoft.Json.JsonConvert.SerializeObject(rodAccessoriesData); - PlayFabMgr.Instance.UpdateUserDataValue(InitRodAccessoriesDataKey, value); + playerSaveStore.Write(InitRodAccessoriesDataKey, value).RequireAccepted(); } /// /// 手是否解锁 @@ -272,7 +272,7 @@ namespace GameCore .AddContent("rod_chips_consume", rquiredFragments); } #endif - PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData)); + playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted(); //鱼竿红点数据修改 CheckRodRedPointUp(); //合成鱼竿 @@ -354,7 +354,7 @@ namespace GameCore public void SaveHonorLevelData() { string value = Newtonsoft.Json.JsonConvert.SerializeObject(_honorlevel); - PlayFabMgr.Instance.UpdateUserDataValue(HonorLevelDataKey, value); + playerSaveStore.Write(HonorLevelDataKey, value).RequireAccepted(); } #endregion 荣耀等级 diff --git a/Client/Assets/Scripts/DataCenter/PlayerItemData_Inflation.cs b/Client/Assets/Scripts/DataCenter/PlayerItemData_Inflation.cs index 19edb2f9b..1fbeb1600 100644 --- a/Client/Assets/Scripts/DataCenter/PlayerItemData_Inflation.cs +++ b/Client/Assets/Scripts/DataCenter/PlayerItemData_Inflation.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using System; diff --git a/Client/Assets/Scripts/DataCenter/TotalRechargeManager.cs b/Client/Assets/Scripts/DataCenter/TotalRechargeManager.cs index f297ea362..a4a34b505 100644 --- a/Client/Assets/Scripts/DataCenter/TotalRechargeManager.cs +++ b/Client/Assets/Scripts/DataCenter/TotalRechargeManager.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using LitJson; @@ -17,12 +17,14 @@ namespace GameCore } public class TotalRechargeManager { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public const string TotalRechargeDataKey = "EventTotalRecharge"; public TotalRechargeData GetEventData() { var totalRechargeData = new TotalRechargeData(); - string data = PlayFabMgr.Instance.GetLocalData(TotalRechargeDataKey); + string data = saveStore.Read(TotalRechargeDataKey).ValueOrThrow(); if (!string.IsNullOrEmpty(data)) { try @@ -175,7 +177,7 @@ namespace GameCore void SaveTotalRechargeData(TotalRechargeData totalRechargeData) { - PlayFabMgr.Instance.UpdateUserDataValue(TotalRechargeDataKey, JsonMapper.ToJson(totalRechargeData)); + saveStore.Write(TotalRechargeDataKey, JsonMapper.ToJson(totalRechargeData)).RequireAccepted(); } } } diff --git a/Client/Assets/Scripts/DebugFunc.cs b/Client/Assets/Scripts/DebugFunc.cs index 0504c85bf..8ba5db7bf 100644 --- a/Client/Assets/Scripts/DebugFunc.cs +++ b/Client/Assets/Scripts/DebugFunc.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using game; using GameCore; using IngameDebugConsole; @@ -720,7 +720,7 @@ public class DebugFunc } static void ClearLastPaymentTime() { - PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", ""); + GContext.container.Resolve().Write("LastPaymentTime", "").RequireAccepted(); } static void HookWheelForecActive() { diff --git a/Client/Assets/Scripts/Duel/UI/EventFishingDuelPanel.cs b/Client/Assets/Scripts/Duel/UI/EventFishingDuelPanel.cs index 4c11f6373..a05cc5382 100644 --- a/Client/Assets/Scripts/Duel/UI/EventFishingDuelPanel.cs +++ b/Client/Assets/Scripts/Duel/UI/EventFishingDuelPanel.cs @@ -607,6 +607,12 @@ public class EventFishingDuelPanel : BasePanel } void CreateMatchmakingTicket() { + if (GContext.container.Resolve() is not PlayFabUserService) + { + Debug.LogWarning("KV matchmaking service is not connected."); + FDM.MachingEnd(null); + return; + } int MaxMatchTime = FDM.eventSoloConfig.MaxMatchTime; //可匹配段位列表,杯数,选择倍率,地图列表,随机种子seed,鱼卡等级 List matchTierList = FDM.eventSolomain.MatchTierList; @@ -631,8 +637,8 @@ public class EventFishingDuelPanel : BasePanel { Entity = new EntityKey { - Id = userService.entityKey.Id, - Type = userService.entityKey.Type + Id = ((PlayFabUserService)userService).entityKey.Id, + Type = ((PlayFabUserService)userService).entityKey.Type }, Attributes = new MatchmakingPlayerAttributes { @@ -717,6 +723,12 @@ public class EventFishingDuelPanel : BasePanel } void GetMatchDetails(string matchId) { + if (GContext.container.Resolve() is not PlayFabUserService) + { + Debug.LogWarning("KV matchmaking service is not connected."); + FDM.MachingEnd(null); + return; + } var request = new PlayFab.MultiplayerModels.GetMatchRequest { MatchId = matchId, @@ -745,7 +757,7 @@ public class EventFishingDuelPanel : BasePanel for (int i = 0; i < result.Members.Count; i++) { MatchmakingPlayerWithTeamAssignment member = result.Members[i]; - if (member.Entity.Id != userService.entityKey.Id) + if (member.Entity.Id != ((PlayFabUserService)userService).entityKey.Id) { JObject dataObject = JObject.FromObject(result.Members[i].Attributes.DataObject); string[] tierArray = dataObject["Tier"].ToObject(); diff --git a/Client/Assets/Scripts/Event/AEventDataManager.cs b/Client/Assets/Scripts/Event/AEventDataManager.cs index f01b48dc7..cb97c78a9 100644 --- a/Client/Assets/Scripts/Event/AEventDataManager.cs +++ b/Client/Assets/Scripts/Event/AEventDataManager.cs @@ -16,6 +16,8 @@ namespace game GContext.OnEvent().Subscribe(OnEvent_TargetEvent).AddTo(Disposables); } private Tables _tables; + [Inject] public PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + bool disposed; [Inject] public Tables Tables @@ -28,6 +30,7 @@ namespace game public virtual void Dispose() { + disposed = true; Disposables?.Dispose(); } @@ -38,6 +41,7 @@ namespace game protected virtual void OnEvent_TargetEvent(TargetEvent targetEvent) { + if (disposed || SaveStore == null || !SaveStore.IsCurrent) return; if (targetEvent.type == EventType && targetEvent.subType == EventSubType) RefreshData(targetEvent.id); } @@ -54,7 +58,8 @@ namespace game #if UNITY_EDITOR Debug.Log($"jsd {typeof(T).Name} SaveData {JsonConvert.SerializeObject(Data)}"); #endif - PlayFabMgr.Instance.UpdateUserDataValue(typeof(T).Name, JsonConvert.SerializeObject(Data)); + if (disposed) throw new ObjectDisposedException(GetType().Name); + SaveStore.Write(typeof(T).Name, JsonConvert.SerializeObject(Data)).RequireAccepted(); } protected virtual void SaveData(T data) @@ -62,7 +67,8 @@ namespace game #if UNITY_EDITOR Debug.Log($"jsd {typeof(T).Name} SaveData {JsonConvert.SerializeObject(data)}"); #endif - PlayFabMgr.Instance.UpdateUserDataValue(typeof(T).Name, JsonConvert.SerializeObject(data)); + if (disposed) throw new ObjectDisposedException(GetType().Name); + SaveStore.Write(typeof(T).Name, JsonConvert.SerializeObject(data)).RequireAccepted(); } protected virtual void RefreshData(int eventId) @@ -82,7 +88,8 @@ namespace game protected T GetCacheData() { - var dataStr = PlayFabMgr.Instance.GetLocalData(typeof(T).Name); + if (disposed) throw new ObjectDisposedException(GetType().Name); + var dataStr = SaveStore.Read(typeof(T).Name).ValueOrThrow(); #if UNITY_EDITOR Debug.Log($"jsd {typeof(T).Name} LoadData sData {dataStr}"); #endif @@ -133,4 +140,4 @@ namespace game } #endregion } -} \ No newline at end of file +} diff --git a/Client/Assets/Scripts/EventBingo/EventBingoData.cs b/Client/Assets/Scripts/EventBingo/EventBingoData.cs index b44f03509..0e82ae5a2 100644 --- a/Client/Assets/Scripts/EventBingo/EventBingoData.cs +++ b/Client/Assets/Scripts/EventBingo/EventBingoData.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using GameCore; using System; @@ -410,6 +410,8 @@ public class EventBingoStepState public class EventBingoPlayfabData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public int EventId, TicketCount, RoundCount, StepInRound, Seed, ChainProgress, ChainTaskTokenProgress; public float InflationRate; private const int TokenCount = 8; @@ -473,12 +475,12 @@ public class EventBingoPlayfabData public void Save() { - PlayFabMgr.Instance.UpdateUserDataValue(Key, Serialize()); + saveStore.Write(Key, Serialize()).RequireAccepted(); } public static EventBingoPlayfabData Load() { - var s = PlayFabMgr.Instance.GetLocalData(Key); + var s = GContext.container.Resolve().Read(Key).ValueOrThrow(); return Deserialize(s); } } diff --git a/Client/Assets/Scripts/EventBreak/EventBreakData.cs b/Client/Assets/Scripts/EventBreak/EventBreakData.cs index a8d3932f7..98e777ccb 100644 --- a/Client/Assets/Scripts/EventBreak/EventBreakData.cs +++ b/Client/Assets/Scripts/EventBreak/EventBreakData.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using UnityEngine; using SystemRandom = System.Random; using System.Text; @@ -152,6 +152,8 @@ public class DrillModel : IHasChainPack public class EventBreakPfData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public int EventId { get; set; } public int TicketCount { get; set; } public int ChainPackProgress { get; set; } @@ -238,7 +240,7 @@ public class EventBreakPfData public void Save() { var s = Serialize(); - PlayFabMgr.Instance.UpdateUserDataValue(PfKey, s); + saveStore.Write(PfKey, s).RequireAccepted(); } } diff --git a/Client/Assets/Scripts/EventCan/EventCanData.cs b/Client/Assets/Scripts/EventCan/EventCanData.cs index 345e74e5b..57a2e46c8 100644 --- a/Client/Assets/Scripts/EventCan/EventCanData.cs +++ b/Client/Assets/Scripts/EventCan/EventCanData.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using GameCore; using UnityEngine; using System.Collections.Generic; @@ -350,6 +350,8 @@ public class EventCanProgressTaskInfo public class EventCanPlayfabData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public const string PlayFabKey = "EventCan"; private const char Splitter = '|', Comma = ','; private const int SerializedTokenCount = 11; @@ -433,7 +435,7 @@ public class EventCanPlayfabData public void Save() { var s = Serialize(); - PlayFabMgr.Instance.UpdateUserDataValue(PlayFabKey, s); + saveStore.Write(PlayFabKey, s).RequireAccepted(); } public void Log() diff --git a/Client/Assets/Scripts/EventCubeMelt/Data/EventCubeMeltManager.cs b/Client/Assets/Scripts/EventCubeMelt/Data/EventCubeMeltManager.cs index bd192258e..2a4993774 100644 --- a/Client/Assets/Scripts/EventCubeMelt/Data/EventCubeMeltManager.cs +++ b/Client/Assets/Scripts/EventCubeMelt/Data/EventCubeMeltManager.cs @@ -1,4 +1,4 @@ -// EventCubeMeltManager.cs +// EventCubeMeltManager.cs // 锻刀大赛 using System; @@ -22,6 +22,8 @@ using Random = UnityEngine.Random; public class EventCubeMeltManager { + [asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; } + // public const string SaveKey = "EventCubeMeltData"; @@ -137,7 +139,7 @@ public class EventCubeMeltManager { ELog($"SaveData()-> {eventDataJson}"); } - PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, eventDataJson); + SaveStore.Write(SaveKey, eventDataJson).RequireAccepted(); } public void AddTicket(int costValue) diff --git a/Client/Assets/Scripts/EventGatherCore/EventGatherCoreData.cs b/Client/Assets/Scripts/EventGatherCore/EventGatherCoreData.cs index 2fa4eae70..ed98bb1f1 100644 --- a/Client/Assets/Scripts/EventGatherCore/EventGatherCoreData.cs +++ b/Client/Assets/Scripts/EventGatherCore/EventGatherCoreData.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using UnityEngine; using GameCore; using asap.core; @@ -265,6 +265,8 @@ public class EventGatherCoreRewardInfo public class EventGatherCorePlayfabData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public int EventId { get; set; } public int TicketCount { get; set; } public int ChainPackID { get; set; } @@ -312,12 +314,12 @@ public class EventGatherCorePlayfabData public void Save() { - PlayFabMgr.Instance.UpdateUserDataValue(Key, Serialize()); + saveStore.Write(Key, Serialize()).RequireAccepted(); } public static EventGatherCorePlayfabData Load() { - var s = PlayFabMgr.Instance.GetLocalData(Key); + var s = GContext.container.Resolve().Read(Key).ValueOrThrow(); var res = new EventGatherCorePlayfabData(); try { diff --git a/Client/Assets/Scripts/EventLuckGame/EventLuckyGameModel.cs b/Client/Assets/Scripts/EventLuckGame/EventLuckyGameModel.cs index 6b7d301d6..fcd45b28f 100644 --- a/Client/Assets/Scripts/EventLuckGame/EventLuckyGameModel.cs +++ b/Client/Assets/Scripts/EventLuckGame/EventLuckyGameModel.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using GameCore; using System; @@ -11,6 +11,8 @@ using UnityEngine; /// public class EventLuckyGameModel : ILuckyTaskGetData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public static EventLuckyGameModel Get() { var model = GContext.container.Resolve(); @@ -57,7 +59,7 @@ public class EventLuckyGameModel : ILuckyTaskGetData string s = Newtonsoft.Json.JsonConvert.SerializeObject(eventLuckGameRecord); //Debug.Log($"[EventLuckGameModel] Save EventLuckGameRecord: {s}"); - PlayFabMgr.Instance.UpdateUserDataValue(Key, s); + saveStore.Write(Key, s).RequireAccepted(); } //=========================以下是活动数据========================= @@ -163,7 +165,7 @@ public class EventLuckyGameModel : ILuckyTaskGetData { return; } - string s = PlayFabMgr.Instance.GetLocalData(Key); + string s = saveStore.Read(Key).ValueOrThrow(); if (string.IsNullOrEmpty(s)) { eventLuckGameRecord = new EventLuckGameRecord(); diff --git a/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyData.cs b/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyData.cs index 28d1e8936..21c073ff3 100644 --- a/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyData.cs +++ b/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyData.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using asap.core; using GameCore; using UnityEngine; @@ -261,6 +261,8 @@ public class EventOfferJourneyBlockData public class EventOfferJourneyPlayfabData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public int EventId, Progress, TicketCount, VipLvlOnTrigger, RoundCount; public float InflationRate; private const string Key = "EventOfferJourneyData"; @@ -319,14 +321,14 @@ public class EventOfferJourneyPlayfabData public static EventOfferJourneyPlayfabData Load() { - var s = PlayFabMgr.Instance.GetLocalData(Key); + var s = GContext.container.Resolve().Read(Key).ValueOrThrow(); return Deserialize(s); } public void Save() { var s = Serialize(); - PlayFabMgr.Instance.UpdateUserDataValue(Key, s); + saveStore.Write(Key, s).RequireAccepted(); } } diff --git a/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyLvlTriggerData.cs b/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyLvlTriggerData.cs index 6c4ec268b..9bff8fc4f 100644 --- a/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyLvlTriggerData.cs +++ b/Client/Assets/Scripts/EventOfferJourney/EventOfferJourneyLvlTriggerData.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Text; using GameCore; using UnityEngine; @@ -156,6 +156,8 @@ public class EventOfferJourneyLvlTriggerData : AEventOfferJourneyData public class EventOfferJourneyLvlTriggerPlayfabData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public int Progress, TicketCount, RoundCount; private const string Key = "EventOfferJourneyLvlTriggerData"; private const int TokenCount = 3; @@ -195,13 +197,13 @@ public class EventOfferJourneyLvlTriggerPlayfabData public static EventOfferJourneyLvlTriggerPlayfabData Load() { - var s = PlayFabMgr.Instance.GetLocalData(Key); + var s = GContext.container.Resolve().Read(Key).ValueOrThrow(); return Deserialize(s); } public void Save() { var s = Serialize(); - PlayFabMgr.Instance.UpdateUserDataValue(Key, s); + saveStore.Write(Key, s).RequireAccepted(); } } \ No newline at end of file diff --git a/Client/Assets/Scripts/EventStrikeLucky/EventLuckMagicData.cs b/Client/Assets/Scripts/EventStrikeLucky/EventLuckMagicData.cs index 645344edc..3b67e08a2 100644 --- a/Client/Assets/Scripts/EventStrikeLucky/EventLuckMagicData.cs +++ b/Client/Assets/Scripts/EventStrikeLucky/EventLuckMagicData.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using GameCore; @@ -564,6 +564,8 @@ public class RewardItemNewFlyToStashRequest public class EventLuckMagicPlayfabData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public int EventId; public int TicketCount; public int ChainProgress; @@ -668,7 +670,7 @@ public class EventLuckMagicPlayfabData { var s = Serialize(); // Debug.Log($"[EventLuckMagic] Save playfab data : \n" + s); - PlayFabMgr.Instance.UpdateUserDataValue(Key, s); + saveStore.Write(Key, s).RequireAccepted(); } } diff --git a/Client/Assets/Scripts/EventWelcomeBack/EventWelcomeBackManager.cs b/Client/Assets/Scripts/EventWelcomeBack/EventWelcomeBackManager.cs index 986123101..f7395e9be 100644 --- a/Client/Assets/Scripts/EventWelcomeBack/EventWelcomeBackManager.cs +++ b/Client/Assets/Scripts/EventWelcomeBack/EventWelcomeBackManager.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using GameCore; using System; @@ -15,6 +15,8 @@ public class WelcomeBackData } public class EventWelcomeBackManager { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + string DataKey_WelcomeBack = "WelcomeBack"; Tables tables; public TbEventWelcomeBackConfig eventWelcomeBackConfig; @@ -28,7 +30,7 @@ public class EventWelcomeBackManager { try { - string data = PlayFabMgr.Instance.GetLocalData(DataKey_WelcomeBack); + string data = saveStore.Read(DataKey_WelcomeBack).ValueOrThrow(); if (!string.IsNullOrEmpty(data)) { welcomeBackData = Newtonsoft.Json.JsonConvert.DeserializeObject(data) ?? new WelcomeBackData(); @@ -228,7 +230,7 @@ public class EventWelcomeBackManager void SaveData() { - PlayFabMgr.Instance.UpdateUserDataValue(DataKey_WelcomeBack, Newtonsoft.Json.JsonConvert.SerializeObject(welcomeBackData)); + saveStore.Write(DataKey_WelcomeBack, Newtonsoft.Json.JsonConvert.SerializeObject(welcomeBackData)).RequireAccepted(); } } public struct ClaimComeBack diff --git a/Client/Assets/Scripts/GampPlay/FishingB/FishingBehaviorB.cs b/Client/Assets/Scripts/GampPlay/FishingB/FishingBehaviorB.cs index 8e4a66bcc..d698a05ad 100644 --- a/Client/Assets/Scripts/GampPlay/FishingB/FishingBehaviorB.cs +++ b/Client/Assets/Scripts/GampPlay/FishingB/FishingBehaviorB.cs @@ -1,3 +1,4 @@ +using game.PlayerDataStorage; using asap.core; using cfg; using DG.Tweening; @@ -70,6 +71,7 @@ public partial class FishingBehaviorB : MonoBehaviour catch(Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); } } #endif + IPlayerSaveStore saveStore; Tables _tables; [Header("RELATED OBJECT SETTINGS")] [SerializeField] @@ -213,6 +215,7 @@ public partial class FishingBehaviorB : MonoBehaviour } public void Init() { + saveStore = GContext.container.Resolve(); fishingData = GContext.container.Resolve(); fishingBehaviorConf = fishingData.fishingBehaviorConf; collectingData = GContext.container.Resolve(); @@ -852,8 +855,8 @@ public partial class FishingBehaviorB : MonoBehaviour { GContext.Publish(new ConditionTypeEvent(ConditionType.ConsumeEnergy, energy)); } - var success = await PlayFabMgr.Instance.SyncDataImmidiate("NewPlayerDataDic", - Newtonsoft.Json.JsonConvert.SerializeObject(commonDatas)); + var success = (await saveStore.WriteAndConfirmAsync("NewPlayerDataDic", + Newtonsoft.Json.JsonConvert.SerializeObject(commonDatas))).Confirmed; Debug.Log($"[FishBehaviourB::ConsumeBaitOnPlayfab] {success}"); } diff --git a/Client/Assets/Scripts/InfiniteBuilding/InfiniteBuildingData.cs b/Client/Assets/Scripts/InfiniteBuilding/InfiniteBuildingData.cs index 651f1874a..1f0bad926 100644 --- a/Client/Assets/Scripts/InfiniteBuilding/InfiniteBuildingData.cs +++ b/Client/Assets/Scripts/InfiniteBuilding/InfiniteBuildingData.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using GameCore; using System.Collections.Generic; @@ -6,6 +6,8 @@ using UnityEngine; public class InfiniteBuildingData { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public int Lvl, Step, StepLvl = 1, LastHangingBlock = -1; public List Record = new List(); // private readonly TbConstructionUnits BlocksTable = GContext.container.Resolve().TbConstructionUnits; @@ -64,7 +66,7 @@ public class InfiniteBuildingData //Debug.Log("Upload!!!!!!!!!!!!!!"); //Debug.Log(s); GContext.container.Resolve().InfiniteBuildingData = s; - PlayFabMgr.Instance.UpdateUserDataValue("InfiniteBuildingData", s); + saveStore.Write("InfiniteBuildingData", s).RequireAccepted(); } public void DownloadData(string s) diff --git a/Client/Assets/Scripts/LuckyTask/UI/LuckyADTaskPopupPanel.cs b/Client/Assets/Scripts/LuckyTask/UI/LuckyADTaskPopupPanel.cs index 5056be914..6ed73801c 100644 --- a/Client/Assets/Scripts/LuckyTask/UI/LuckyADTaskPopupPanel.cs +++ b/Client/Assets/Scripts/LuckyTask/UI/LuckyADTaskPopupPanel.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using game; using GameCore; @@ -9,6 +9,8 @@ using UnityEngine; public class LuckyADTaskPopupPanel : LuckyTaskPanelBase { + game.PlayerDataStorage.IPlayerSaveStore saveStore; + List taskList; List taskItems = new List(); List taskADList = new List(); @@ -18,6 +20,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase System.DateTime refreshTime; protected override void Awake() { + saveStore = GContext.container.Resolve(); base.Awake(); luckyTaskItem = transform.Find("root/hook_missions_object").GetComponent(); text_time = transform.Find("root/text_time").GetComponent(); @@ -120,7 +123,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase int round = taskData.GetValueOrDefault(-1, 0); float inflationRate = taskData.GetValueOrDefault(-3, 0) / 100f; int group = taskData.GetValueOrDefault(-4, 0); - string adData = PlayFabMgr.Instance.GetLocalData(LuckyTaskData.ADTaskADKey); + string adData = saveStore.Read(LuckyTaskData.ADTaskADKey).ValueOrThrow(); int index = 0; int curDay = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear; if (!string.IsNullOrEmpty(adData)) @@ -134,13 +137,13 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase else { adData = $"{index}|{curDay}"; - PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData); + saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted(); } } else { adData = $"{index}|{curDay}"; - PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData); + saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted(); } List taskADList = new List(); TbEventLuckyTask eventLuckyTask = LuckyTaskData.GetTbEventLuckyTask(luckyModel.EventId, round, group); @@ -180,7 +183,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase luckyADTaskItem.Play(); - string adData = PlayFabMgr.Instance.GetLocalData(LuckyTaskData.ADTaskADKey); + string adData = saveStore.Read(LuckyTaskData.ADTaskADKey).ValueOrThrow(); int index = 0; int day = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear; if (!string.IsNullOrEmpty(adData)) @@ -195,7 +198,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase //保存进度 index++; adData = $"{index}|{day}"; - PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData); + saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted(); RefreshADItemState(index); canvasGroup.blocksRaycasts = true; GContext.Publish(new ShowData()); diff --git a/Client/Assets/Scripts/LuckyTask/UI/LuckyTaskBtn.cs b/Client/Assets/Scripts/LuckyTask/UI/LuckyTaskBtn.cs index 01a6ddaa7..d341e8cde 100644 --- a/Client/Assets/Scripts/LuckyTask/UI/LuckyTaskBtn.cs +++ b/Client/Assets/Scripts/LuckyTask/UI/LuckyTaskBtn.cs @@ -1,3 +1,4 @@ +using asap.core; using cfg; using GameCore; using TMPro; @@ -6,6 +7,8 @@ using UnityEngine.UI; public class LuckyTaskBtn : MonoBehaviour, IUIRedPoint { + game.PlayerDataStorage.IPlayerSaveStore saveStore; + Button btn; ILuckyTaskGetData model; @@ -15,6 +18,7 @@ public class LuckyTaskBtn : MonoBehaviour, IUIRedPoint public TMP_Text text_redpoint_big; void Awake() { + saveStore = GContext.container.Resolve(); btn = GetComponent public DateTime? GetLastLoginTime() { - return _userService?.LastLoginTime; + var value = _userService?.LastLoginTime; + return value == DateTime.MinValue ? null : value; } /// @@ -121,16 +123,18 @@ namespace TimeManager /// /// 跨天刷新逻辑 /// - private void OnCrossDayRefresh() + private bool OnCrossDayRefresh() { try { // 1. 发送活动跨天刷新事件 GContext.Publish(new ActivityCrossDayRefreshEvent()); + return true; } catch (Exception e) { Debug.LogError($"[TimeRefreshManager] Error during cross day refresh: {e.Message}\n{e.StackTrace}"); + return false; } } diff --git a/Client/Assets/Scripts/UI/AdWheel/AdWheelManager.cs b/Client/Assets/Scripts/UI/AdWheel/AdWheelManager.cs index e1f5e6717..b785be734 100644 --- a/Client/Assets/Scripts/UI/AdWheel/AdWheelManager.cs +++ b/Client/Assets/Scripts/UI/AdWheel/AdWheelManager.cs @@ -1,4 +1,4 @@ -using asap.core; +using asap.core; using cfg; using GameCore; using Newtonsoft.Json; @@ -14,6 +14,8 @@ namespace Assets.Scripts.UI.AdWheel { public class AdWheelManager:IDisposable { + readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve(); + public AdWheelManager() { @@ -97,7 +99,7 @@ namespace Assets.Scripts.UI.AdWheel private AdWheelData GetCachedData() { - var dataStr = PlayFabMgr.Instance.GetLocalData(nameof(AdWheelData)); + var dataStr = saveStore.Read(nameof(AdWheelData)).ValueOrThrow(); #if UNITY_EDITOR Debug.Log($"jsd AdWheelData LoadData sData {dataStr}"); #endif @@ -117,7 +119,7 @@ namespace Assets.Scripts.UI.AdWheel #if UNITY_EDITOR Debug.Log($"jsd AdWheelData SaveData {JsonConvert.SerializeObject(Data)}"); #endif - PlayFabMgr.Instance.UpdateUserDataValue(nameof(AdWheelData), JsonConvert.SerializeObject(Data)); + saveStore.Write(nameof(AdWheelData), JsonConvert.SerializeObject(Data)).RequireAccepted(); } private List _rewards = new List(); diff --git a/Client/Assets/Scripts/UI/Advert/AdvertPanel.cs b/Client/Assets/Scripts/UI/Advert/AdvertPanel.cs index 382b43681..e656abe41 100644 --- a/Client/Assets/Scripts/UI/Advert/AdvertPanel.cs +++ b/Client/Assets/Scripts/UI/Advert/AdvertPanel.cs @@ -1,4 +1,4 @@ -using System; +using System; using asap.core; using Assets.Scripts.UI.AdWheel; using cfg; @@ -19,6 +19,8 @@ public class AdvertData } public class AdvertPanel : MonoBehaviour { + game.PlayerDataStorage.IPlayerSaveStore saveStore; + Button btn_close; TMP_Text txt_energy, txt_money, txt_ticket; ulong _curGold; @@ -35,6 +37,7 @@ public class AdvertPanel : MonoBehaviour private void Awake() { + saveStore = GContext.container.Resolve(); txt_ticket = transform.Find("top_area/resource/icon_ticket/text_num").GetComponent(); txt_energy = transform.Find("top_area/resource/icon_energy/text_num").GetComponent(); txt_money = transform.Find("top_area/resource/icon_money/text_num").GetComponent(); @@ -94,7 +97,7 @@ public class AdvertPanel : MonoBehaviour // 判断是否满足{seconds}没有充值了 private bool Condition_NoRechargeSeconds(int timeSeconds) { - var lastPaymentStr = PlayFabMgr.Instance.GetLocalData("LastPaymentTime"); + var lastPaymentStr = saveStore.Read("LastPaymentTime").ValueOrThrow(); DateTime curTime = ZZTimeHelper.UtcNow().UtcNowOffset(); DateTime endTime = curTime; if (string.IsNullOrEmpty(lastPaymentStr) || !lastPaymentStr.Contains("__")) diff --git a/Client/Assets/Scripts/UI/DeBugPanel.cs b/Client/Assets/Scripts/UI/DeBugPanel.cs index 625b8b65c..39e2c2fc0 100644 --- a/Client/Assets/Scripts/UI/DeBugPanel.cs +++ b/Client/Assets/Scripts/UI/DeBugPanel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using GameCore; using asap.core; @@ -14,6 +14,8 @@ using Activity.Event; public class DeBugPanel : MonoBehaviour { + game.PlayerDataStorage.IPlayerSaveStore saveStore; + static public bool isShow = true; private CanvasGroup _canvasGroup; private Button btn_close; @@ -111,6 +113,7 @@ public class DeBugPanel : MonoBehaviour // Start is called before the first frame update void Awake() { + saveStore = GContext.container.Resolve(); inputField_itemId = transform.Find("root/InputField_icon").GetComponent(); inputField_itemCount = transform.Find("root/InputField_icon_num").GetComponent(); btn_addItem = transform.Find("root/btn_sure2/btn_green").GetComponent