Files
ft/CodexOutput/upserver/B3DesignAudit/render_inventory.py

90 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Render design facts only; does not modify or execute game code."""
import json
from pathlib import Path
base = Path(__file__).resolve().parent
calls = json.loads((base / 'calls.json').read_text(encoding='utf-8-sig'))
def assign(c):
n = int(c['Id'].split('C')[-1])
if c['Path'].endswith('/Core/PlayFabMgr.cs'):
return 'A保留旧区;C另审生命周期', 'PF原流程;本次不改'
if c['Method'] == 'SyncDataImmidiate' or n == 38:
return '4C消费合同;B先审归属', '消费/等待;不得KV启用'
if n == 190:
return '身份/外围专项保留PF', '读取他人Lv;不转本人KV'
if n in (168, 183, 184, 185, 186, 187, 188, 189):
return 'B归属+C初始化发布', '登录/渠道/GM;不复用PF初始化'
if n in (126, 194):
return 'B调试入口边界', '默认禁止KV调试写;不默授权限'
if n in (1, 2, 3, 127, 128, 129):
return 'B仓库与事件上游详审', '泛型/继承;捕获异常默认值须拆开'
if n in (213, 214):
return 'B渠道回调+身份专项', 'await后UI/奖励也须旧epoch拒绝'
if n in (63,64,65,66,67,151,152,171,176,182):
return 'B归属;奖励/支付结果另裁决', '先变内存/奖励风险;禁自动重试'
return 'B逐业务完整详审', '同步末端不等于上游无延后回调'
header = '''# 阶段4B3调用事实与分期附件
日期:2026-09-24。配套[分期与4B3A方案](阶段4B3分期与4B3A固定存档入口方案-待评审-2026-09-24.md)。
**本附件是语法调用事实和阶段归属,不是4B3B完成的回调隔离合同。** 所有B/C行当前均禁止凭此编码;它们既不进入A白名单,也不获得KV运行资格。A只新增四个尚无业务调用者的静态入口。
## 1. 可复现盘点和限制
使用本地.NET 9.0.310自带Roslyn,读取Client/Assets/Scripts全部2101个.cs文件,仅解析语法,不编译或执行游戏。五种条件符号合并去重:Editor Standalone、Editor Android+AGG、Player Android+AGG、Player iOS+AGG、Player Standalone。223个位置/81文件:外部facade 212、facade内部8、SDK3。原文本234行/84文件还包含注释、声明及B2配置引用,统计口径不同。
`B3DesignAudit/calls.json`逐项含源行、所在类型/方法/属性、完整参数、方法体、局部await行、编译条件、按方法名匹配的上游位置。`source-hashes.json`封存2101个源文件hash。工具源码也纳入受审基线,运行仅产生设计分析数据。
**重要限制**:CallerNameCandidates是名称候选,可能把不同类型的Save/Load混在一起;数量0也不能证明无UnityEvent/方法组/反射调用。AwaitLines只观察包含本调用的方法;空列表不是整条链同步的证据。未枚举的自定义编译符号和包内/持久化UnityEvent另需B审查。此处不输出未经语义验证的“全部上游已覆盖”结论。
可复现命令(项目内NuGet配置,无新包):`dotnet run --project CodexOutput/upserver/B3DesignAudit/B3DesignAudit.csproj -- C:/projects/ft C:/projects/ft/CodexOutput/upserver/B3DesignAudit`。送审后复跑需另给输出目录,不覆盖受审快照。
## 2. 已人工核对的调用链与设计约束
| 位置 | 已确认链/副作用 | 捕获和取消的待审合同 |
|---|---|---|
| C050 SavePlayerData | 17个按名候选,方法自身先Publish(this),再改NewPlayerDataDic并从Fish/Achievement/Box/Event读取;remote参数可传递 | 必须从最早内存变更者起捕获,不能到此方法末端才验epoch;需要保护整个跨模块序列化对象集合 |
| C038/C223 RewardTurntableRoll→ConsumeOnPlayfab | Panel:530传false;方法先Publish、扣券、更新过渡数据与红点,后localOnly保存;随后立即远端bool | B只隔离归属;4C设计未知结果与防重入;不能把两次保存当事务 |
| C051 OpenAppraisePopupPanel | FishingRewardPanel:963调用,await ShowUI后改IsOpenAppraise并存档 | 从打开UI前捕获,await后先检查;关闭旧面板和取消等待仍不能替代epoch检查 |
| C063~067 OnBuy/Replenishment→BuySuccess | OnBuy含SDK/支付await;Replenishment亦进入BuySuccess及奖励/事件 | 支付开始时绑定账号及业务单据,不能补单回调取当前账号;B处理归属,支付恢复语义另审 |
| C151/152 OnBuySuccess | LuckyADTaskPopupPanel:87将方法组交给Item.Init;即使方法内无await也有延后来源 | 在Item回调注册处捕获;面板退出退订/失效;进入回调即检查,早于领奖/计数 |
| C171 ClubSingin | 自身已有API身份/版本捕获与await后检查,随后signTime、保存、聊天及奖励 | 复用现有API防护并证明与KV Owner/epoch绑定;避免削弱既有ClubService边界 |
| C176 OnReceiveLinkAward;C182 GetSurveyCheckAnswer | 先AddItem/Publish后标记领取并保存;Survey catch会吞掉异常继续由调用者操作 | 防止“只看保存结果”方案;失败恢复/奖励契约单独裁决,不能写失败后重发奖励 |
| C001~003 EventDataRepository | ActivityManager:34注册单例;Activity.Data/AEventDataManager有Repository.Load??new T、Save后Publish、RefreshData中AutoSaveOnCreate | 仓库与上游默认值链一起改才有效;账号关闭必须使旧事件与实例归属失效 |
| C127~129 game.AEventDataManager | 构造时Subscribe(TargetEvent),Dispose释放;GetCacheData从全局facade读、缺档new T | 注册订阅时绑定账号归属,旧事件入队仍应拒绝;继承类和公开Data可变引用须另外追踪 |
| C213 OnLinkSns | 四个按钮方法await OnLinkSns后仍改按钮/发奖;OnLinkSns内部还有账号切换UI await | 外层及内层同一操作归属;不能仅在UpdateUserDataValue前检查;finally关闭等待UI也须限制原面板实例 |
| C190 GetPlayLv | 请求PlayFabId=参数playFabId,Keys=[Lv],写PlayLvs[playFabId]缓存 | 属他人PF资料;不接本人KV。个人身份切换及缓存清理另审 |
| C177/178 ShowNotice | 属性get惰性读缓存,setter会写存档 | 账号换代必须清旧缓存或绑定新实例;无await也不能默认为账号无关设置 |
## 3. 逐调用位置与拟归属
以下“局部await”列只描述所在方法语法。每行的上下文原文与上游候选保存在同ID JSON。key为源码表达式,不把泛型名/变量/插值key误记为一个固定键。
| ID | 源文件:行(相对Client/Assets/Scripts) | 所在方法/属性 | 调用 / key表达式 | 局部await | 拟归属 | 处理约束 |
|---|---|---|---|---|---|---|
'''
def cell(x):
return str(x).replace('|', '|').replace('\r', '').replace('\n', ' ')
rows=[]
classified=[]
for c in calls:
phase,note=assign(c)
args=c['Arguments']
key=args[0] if args else '—'
# Full SDK request remains in JSON; keep the table readable.
if c['Kind']=='sdk': key='见JSON完整请求'
rows.append('| '+' | '.join(map(cell,[c['Id'],c['Path'].replace('Client/Assets/Scripts/','')+':'+str(c['Line']),c['Member'],c['Method']+' / '+key,','.join(map(str,c['AwaitLines'])) or '无(仅局部)',phase,note]))+' |')
classified.append(dict(id=c['Id'],path=c['Path'],line=c['Line'],phaseProposal=phase,implementationApproved=False,upstreamIsolationComplete=False))
tail='''
## 4. B3B完整合同的进入条件
本轮不把B3B未知项隐藏到实施阶段。B方案送审前,每个拟启用的业务入口必须给出已验证的上游调用/事件注册位置、身份捕获点、首个字段/集合修改点、取消/退订点、共享对象生命周期、localOnly/奖励副作用、错误处置以及对应验收用例。整个B单元的启用白名单必须闭合;任何新增文件先入方案,不能从本81文件统计推导允许批量改动。
在此之前,旧业务路径维持原PF;公共kv登录仍BackendNotEnabled。主方案A验收不以该待完成工作为已解决。外部应对“可先实施A”单独裁决,若不同意则退回分期。
'''
(base.parent/'阶段4B3调用事实与分期附件-2026-09-24.md').write_text(header+'\n'.join(rows)+tail,encoding='utf-8')
(base/'classification.json').write_text(json.dumps(classified,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
print(json.dumps({'renderedCalls':len(calls),'allImplementationApproved':False}))