Code Review · develop-fullview

develop 昨日审查
2026-06-10

22 个 commit (1 个 [skip ci] 不计, 余 21 个; 其中 art/lang/工具/bot 9 个不进代码维度), 6 位提交人, 5 个问题 P0×1 P1×2 P2×2

Commits21
Authors6
Issues5
CriticalP0×1

审查概览

1P0 阻断级问题
2P1 高优问题
2P2 质量问题
主要风险:shawna 271b5afbc63 在搜打撤局内 BattleData 的 initFromProto$$dispose$$ 里同时删除了 _resourcePointTriggerIndexMap$$.clear() / _mechanismTriggerIndexMap$$.clear() 两次清理, 同日晚些时候 c5f62219a31 又在 DeltaDungeonModule$$ 改成 "二次进副本只 dispose 不 new BattleData", 两笔变更叠加后 TODAY_TIP 实际行为是: 第二次进搜打撤副本时, 上一局留下来的资源点 / 机关触发计数原地继续累加, 而服务端会按 Index 做幂等去重, 结果第二局所有资源点 / 机关请求会被服务端整段视作重复包丢弃 (P0-1)。

跨 commit 关联

shawna · 271b5afbc63 联动 c5f62219a31

shawna 271b5afbc63 (17:51) 在 BattleData 内删除两处 trigger Index Map 的 clear, commit message 只说 "相关 bug 修复" 未披露; 同日 c5f62219a31 (20:18) 由同人在 DeltaDungeonModule$$.startDungeon$$ 把 "每次 new DeltaDungeonBattleData$$" 改成 "存在则 dispose$$ 复用", 并在 initFromProto$$ 末尾补回 _pidsInPickupRange$$.clear(), 顺手修了昨天 1f920bc 留下的 ?? 0 + 1 优先级 bug。两笔单独看都 ok, 合在一起后 TODAY_TIP 副本实例第二次进入时, 玩家自动拾取范围 PID 集合被清, 但 _resourcePointTriggerIndexMap$$ / _mechanismTriggerIndexMap$$ 两张幂等去重计数表完全保留上一局状态 (见 P0-1)。

jinko · 0aeb87ccb4d 联动 07e8972bce7

jinko 0aeb87ccb4d (18:52 [mod]loading 卡住修复) 在 NetworkStream$$.setAutoTryReconnect$$ 内为华为 / oppo 平台插了 early return, 同日 19:06 jinko 07e8972bce7 [mod]卡 loading 又把这段 early return 拿掉, 中间 14 分钟自构建窗口未触达; 落锤校验后 TODAY_TIP 状态与昨日一致, 不上报。但同 commit 链改了 GameNetService$$.OnConnectSuccess$$ / 断开回调强制 _onCloseLoadingView$$(), 紧接着 c4ac6fc37e0 在 FunctionChestPreviewView$$ 整段注释 show/hide loading, 07e8972bce7 在 AdInstance$$ 注释 showLoading$$(15)onClosehideLoading$$() 但漏注释 onErrorhideLoading$$() —— 全局 loading 互斥层这天被 jinko 三 commit 反复调, 最终态留了一个错误路径上的孤儿 hideLoading 与一处可能误关其他模块 loading 的连接事件 (见 P1-2 / P2-1)。

shawna · 271b5afbc63

shawna 271b5afbc63 还把 _tryTriggerItemHunter$$ 入参从 propID 改成整个 propItem, 在 DeltaDungeonResourceEffectComponent$$DeltaDungeonMechanismEffectComponent$$_onTriggerComplete$$ / _getCanTrigger$$ 加了 _isBattleSettledOrSettling$$() 守卫, MechanismController$$_processImg$$ tween 前补了 Tween.stopAllByTarget, 这条修复链与 P0-1 同 commit 但语义独立, 单独看是合理收紧, 落锤校验通过, 不上报。

优先处理清单

  • shawna - P0-1 DeltaDungeonBattleData$$.ts initFromProto$$ / dispose$$ 触发 Index Map 漏 clear (271b5afbc63 联动 c5f62219a31)
  • luffy - P1-1 BaseSyncBattleData$$.ts ei 与 info 语义错位 (47be5e47202)
  • jinko - P1-2 AdInstance$$.ts onError 孤儿 hideLoading$$ + showLoading$$ 已被注释 (07e8972bce7) - P2-1 AdInstance$$.ts / FunctionChestPreviewView$$.ts loading 调用整段注释而非删除 (07e8972bce7, c4ac6fc37e0)
  • tangzhipeng - P2-2 DeltaDungeonBagView$$.ts 直接用 console.log 而非项目 Logger (dcabefe0468)
当前提交人没有上报问题。
P0-1

DeltaDungeonBattleData$$.ts:101 (initFromProto$$) / :166 (dispose$$)

👤 shawna · 271b5afbc63 联动 c5f62219a31
现象
玩家在同一会话内连续进两次搜打撤副本, 第二次副本开局时 _resourcePointTriggerIndexMap$$_mechanismTriggerIndexMap$$ 仍带着第一局结束时的累加值。客户端往 DeltaDungeonResourcePointTriggerReq$$.Index$$ / DeltaDungeonMechanismTriggerReq$$.Index$$ 上回填的就是旧值, 服务端按 Index 做幂等去重时把新一局所有资源点 / 机关首次触发请求识别为 "已收过的旧 Index", 整段静默丢弃。表现: 第二次进搜打撤后, 资源点 / 机关点了没掉落、机关动画卡住、背包不刷新。
根因
271b5afbc63 在 initFromProto$$dispose$$ 两处都删掉了 _resourcePointTriggerIndexMap$$.clear() / _mechanismTriggerIndexMap$$.clear(), 加上 c5f62219a31 把 DeltaDungeonModule$$.startDungeon$$ 由 "每次 new BattleData" 改成 "复用 + dispose$$", 副本实例从此跨 raid 复用。c5f62219a31 在 initFromProto$$ 末尾只补回 _pidsInPickupRange$$.clear() 一条, 漏补两张 trigger Index Map; dispose$$ 也只清了 pidsInPickupRange。两次清理的删除动作在落锤校验时 (TODAY_TIP DeltaDungeonBattleData$$.ts L101–L113 与 L166–L186) 仍完全保留 —— Map 实例是 L95、L97 字段初始化器创建, 整个对象生命周期内 only-once。
修复建议
dispose$$ 末尾补 this._resourcePointTriggerIndexMap$$.clear(); this._mechanismTriggerIndexMap$$.clear();, initFromProto$$ 也同步补一次双保险 (即使 dispose 漏调也能兜住)。如果服务端期望 Index 是从 1 重新计起 (与 1f920bc proto 字段语义一致), 两处都需要 reset; 如果服务端预期的是单调递增的全局 Index (跨 raid 不重置), 则需要在 startDungeon$$ 下发的 ChallengeLevelInfo 里同时下发当前 Index 基线由客户端继承, 而不是默默清零。
// DeltaDungeonBattleData$$.ts:166 (dispose$$)
public dispose$$(): void {
    this._roomDataMap$$.clear();
    this._posToRoomIDMap$$.clear();
    this._areaDataMap$$.clear();
    this._selfBuffDataMap$$.clear();
    this._pidsInPickupRange$$.clear();
    this._resourcePointTriggerIndexMap$$.clear();
    this._mechanismTriggerIndexMap$$.clear();
}
P1-1

BaseSyncBattleData$$.ts:130 (伤害上报分支)

👤 luffy · 47be5e47202
现象
47be5e47202 把伤害上报阈值从固定 100 改成按 sourceUnit 分档 (普通 100x, 元素使者 1000x, 神农 5000x), 但 event Index ei 仍写死 keyValue >= 500 ? 6 : 17, info 字段写成 keyValue >= 500 ? max(500, reportRate) : reportRate。结果元素使者一次 1500x 触发上报时, ei=6 (按 PBC 约定 ei=6 这条流是 "≥500x 倍率档"), info="1000"; 神农一次 6000x 上报时 ei=6, info="5000"。同一个 ei=6 流里混入了 500/1000/5000 三种 info 取值, 下游分析任何按 ei 维度做的 cohort / 阈值看板都会把 1000、5000 当 500 计入。
根因
reportRate 这条新维度只用来做 emit gate 判定 (keyValue >= reportRate), 没把 ei 跟着 reportRate 一起切到独立流; info 用 Math.max(500, reportRate) 拼凑后随便放进 ei=6 这条历史流里。"500" 既是 ei=6 的语义档名又是 info 的字面值, 混了一脚。元素使者 / 神农两段 reportRate 提升的逻辑是后加的, 与 ei/info 的旧语义没对齐。
修复建议
要么给 1000x / 5000x 档分配独立的 ei (例如 ei=18 表示元素使者档, ei=19 表示神农档), info 直接传 keyValue 倍率; 要么干脆把 reportRate 作为 ei 的派生维度 (ei = reportRate >= 5000 ? 19 : reportRate >= 1000 ? 18 : reportRate >= 500 ? 6 : 17), info 传 reportRate.toString()。需要先和 PBC 数据侧对齐 ei 表的占用情况再落地。
// BaseSyncBattleData$$.ts:130 (建议修法)
let reportRate = 100;
if (sourceUnit.isElementalEnvoy$$()) reportRate = 1000;
if (sourceUnit.UnitID$$ == 86004) reportRate = 5000;
if (keyValue < reportRate) return;
const ei = reportRate >= 5000 ? 19 : reportRate >= 1000 ? 18 : reportRate >= 500 ? 6 : 17;
const info = reportRate.toString();
EventManager$$.Instance$$.emit$$(EventEnum$$.C_C$$, ei, sourceUnit.UnitID$$+"|"+result.Damage$$+"|"+atk+"|"+info, keyValue);
P1-2

AdInstance$$.ts:196 (onError hideLoading$$ 孤儿)

👤 jinko · 07e8972bce7
现象
07e8972bce7 把 GameViewCtrl$$.Instance$$.showLoading$$(15)onClose 路径里的 hideLoading$$() 都注释掉, 唯独漏了 onError 路径里的 hideLoading$$()。激励视频走错误回调时, 会去关掉一个本 commit 已经不再开的 loading 实例 —— GameViewCtrl 全局 loading 互斥栈被这次错误回调下拉一层, 实际关闭的是栈里另一个模块 (网络重连 / 资源加载 / 章节切换) 的 loading。同 commit 还在 GameNetService$$.OnConnectSuccess$$ / 断开回调里加了 this._onCloseLoadingView$$(), 与 AdInstance 这条孤儿 hideLoading 叠加, 广告失败 + 同时段网络抖动会两次跨模块关 loading。
根因
本次需求 "卡 loading" 是为了禁掉 ad 自带的 loading, 但 onError 这条路径漏改; 全局 loading 是基于显示栈的, 没有 owner key 隔离, 任意一处 hide 就会拉一层 —— 注释式改动让漏网的 hideLoading 在静态读时显得"对称", 实际成了无源 hide。
修复建议
删掉 onError 里的 hideLoading$$() (与 onClose / showLoading 注释保持配对), 或同时取消 onClose 的注释让 show/hide 重新成对; 长期建议给 showLoading$$ / hideLoading$$ 加 ownerKey 参数 (例如 showLoading$$("ad")), 关 loading 时按 key 关, 跨模块互踩从此消失。GameNetService$$.OnConnectSuccess$$_onCloseLoadingView$$() 同样需要按"自家 key" 关, 否则只是把问题推到下一个 commit。
// AdInstance$$.ts:188 (onError 路径)
let adCallback = {
    onClose(isReward, rewardAmount) {
        resolve(isReward);
        AudioManager$$.Instance$$.tryPauseThenPlayMusic$$();
    },
    onError(code, msg) {
        resolve(false);
        AudioManager$$.Instance$$.tryPauseThenPlayMusic$$();
    }
}
P2-1

AdInstance$$.ts:183 / FunctionChestPreviewView$$.ts (loading 整段注释)

👤 jinko · 07e8972bce7, c4ac6fc37e0
现象
07e8972bce7 在 AdInstance$$// GameViewCtrl$$.Instance$$.showLoading$$(15); 整行注释保留代码; c4ac6fc37e0 在 FunctionChestPreviewView$$showLoading$$() / hideLoading$$() 两整行注释保留。注释式删除 (commented-out code) 命中 [[code-quality-baseline]] 反模式: 让后续 reader 不知道是 "临时关掉过两天还要打开" 还是 "确定不要了"; 也阻止 IDE 的 unused 检查发挥作用。同一 commit 链已经反复在跨平台 loading 上来回切, 注释残留会让下一次回滚 / 复用判断进一步发散。
根因
commit message "卡 loading" / "华为, oppo 看广告卡 loading" 只描述结果, 不说是临时关闭还是永久删除。注释残留是 cheap rollback 留口, 但缺乏 commit message 标注就退化成噪音。
修复建议
明确删除 (推荐, 代码已进 git history, 真要回滚是 git revert), 或保留时在注释行前加 // TODO(jinko, YYYY-MM-DD): xxx 平台 SDK 修好后再开, 让删除时机有明确触发条件。
// AdInstance$$.ts:183 (建议改写)
// 直接删除该行; 后续如需恢复, 走 git history 或加 ownerKey 后启用
console.log("play_ad_time$$:", Date.now());
P2-2

DeltaDungeonBagView$$.ts (_logPlacedItemDetails$$)

👤 tangzhipeng · dcabefe0468
现象
dcabefe0468 在 DeltaDungeonBagView$$ 加了两个调试方法 _logPlacedItemDetails$$ / _getPlacedItemLogText$$, 内部直接调 console.log。项目内统一日志是 Logger$$ 系统 (有等级 / tag / 上线 strip 能力), console.log 在 release 包里不会被剥, 上生产后这条搜打撤背包刷新日志会持续打到玩家的运行时 console, 影响小程序 / 端游 console 性能, 也容易把内部字段名 (PID / 道具数量 / 槽位 index) 带到玩家可观测面。commit message 写的是 "搜打撤 1.增加背包 log", 用意是临时排查。
根因
临时排查日志直写 console.log, 没走项目 Logger$$ 通道; 也没有 if (isDevBuild$$) 这类编译态守卫。
修复建议
替换成 Logger$$.Instance$$.info$$(\"DeltaDungeonBag\", text) (或同等 tagged 接口); 排查目的达到后随 c5f62219a31 / 后续修复一并删除调用点; 短期保留也要包一层 __DEV__ / IS_DEBUG_BUILD$$ 守卫。
// DeltaDungeonBagView$$.ts (_logPlacedItemDetails$$)
private _logPlacedItemDetails$$(): void {
    if (!IS_DEBUG_BUILD$$) return;
    const text = this._getPlacedItemLogText$$();
    Logger$$.Instance$$.info$$("DeltaDungeonBag", text);
}