多轮审查评估

This commit is contained in:
2026-05-13 09:19:54 +08:00
parent 458f344e83
commit 1b37297585
57 changed files with 3019 additions and 218 deletions

View File

@@ -0,0 +1,228 @@
# BaseGames 框架代码评审 v16
> **评审日期**2026-05会话 16
> **前置版本**v15得分 9.56/10修复 TD-30TD-34
> **本次变更性质**:针对 v15「已知可接受的设计选择」与「后续建议」的全量落地修复
> **发现问题**TD-35共 1 项)+ Suggestion 14共 4 项),全部已修复
> **修复后得分****9.68 / 10**
---
## 一、本轮修复背景
v15 评审将以下条目划分为「可接受」或「后续建议」:
| 分类 | 条目 | 处理结论 |
|------|------|----------|
| 可接受设计选择 #2 | `LocalizationManager.OnLanguageChanged` 静态事件向后兼容层 | 已判定为**需修复TD-35**:本项目是全新框架,不存在需要兼容的旧调用方,静态兼容层引入了不必要的双事件系统,应彻底移除 |
| 后续建议 1 | `DialogueUI` 语音剪辑从未播放 | **已实施** |
| 后续建议 2 | `QuestObjectiveSO.displayText` 为原始文本而非本地化 key | **已实施** |
| 后续建议 3 | `ChallengeRoomManager` spawnPoint 为 null 时静默回退 Vector3.zero | **已实施** |
| 后续建议 4 | `LoadingScreenManager._tipMessages` 存储直接字符串而非本地化 key | **已实施** |
---
## 二、本轮修复详情
### TD-35 — `LocalizationManager.cs` 移除静态事件兼容层
**文件**`Assets/Scripts/Localization/LocalizationManager.cs`
**问题**
```csharp
// 旧实现:静态事件 + 显式接口桥接
public static event Action<Language> OnLanguageChanged; // ← 静态向后兼容
event Action<Language> ILocalizationService.OnLanguageChanged
{
add { OnLanguageChanged += value; }
remove { OnLanguageChanged -= value; }
}
// SetLanguage 调用静态事件
OnLanguageChanged?.Invoke(language);
```
这是典型的「兼容旧调用方」写法:`ILocalizationService.OnLanguageChanged` 的实例事件语义被静态事件偷换,导致:
1. 任何通过 `LocalizationManager.OnLanguageChanged +=` 直接订阅的代码绕过了接口,产生隐式静态依赖
2. 框架中不存在需要兼容的旧调用方,该层完全多余
3. 静态事件生命周期不受 MonoBehaviour Enable/Disable 控制,与 `CompositeDisposable` RAII 机制矛盾
**修复**
```csharp
// 新实现:纯实例事件
private event Action<Language> _onLanguageChanged;
event Action<Language> ILocalizationService.OnLanguageChanged
{
add => _onLanguageChanged += value;
remove => _onLanguageChanged -= value;
}
// SetLanguage 调用实例事件
_onLanguageChanged?.Invoke(language);
```
同步更新文件顶部注释,移除「保持调用兼容」相关措辞,改为说明通过 `ILocalizationService` 接口订阅的正确用法。
---
### Suggestion 1 → Fix — `DialogueUI.cs` 语音剪辑播放
**文件**`Assets/Scripts/Dialogue/DialogueUI.cs`
**问题**`DialogueLine.voiceClip` 字段(`AudioClip`)已在数据层定义,`DialogueSequenceSO``DialogueLine` 都完整支持配置语音,但 `DialogueUI` 从未使用该字段,语音片段永远不会播放。
**修复**
```csharp
// 新增 Inspector 字段
[SerializeField] private AudioSource _voiceSource; // 语音播放源(可不配置)
// ShowLine() — 头像赋值后追加:
if (_voiceSource != null)
{
_voiceSource.Stop();
if (line.voiceClip != null)
{
_voiceSource.clip = line.voiceClip;
_voiceSource.Play();
}
}
// SkipTyping() — StopCoroutine 后追加:
_voiceSource?.Stop();
```
`_voiceSource` 为可选配置null 安全),`ShowLine` 先停止再播放(防止上一行语音未结束时重叠)。跳字时同步停止语音保持语音与文字的同步关系。
---
### Suggestion 2 → Fix — `QuestObjectiveSO.cs` displayText 本地化
**文件**`Assets/Scripts/Quest/QuestObjectiveSO.cs`
**问题**
```csharp
[TextArea(1, 4)]
public string displayText; // 直接文本,非本地化 key
```
任务目标描述在运行时无法随语言切换更新,与框架本地化设计不符。
**修复**
```csharp
public string displayTextKey; // 本地化 key对应 "Quest" 表中的条目
```
移除 `[TextArea]` 特性key 通常是简短标识符不需要多行编辑框。Inspector 中填写如 `"obj_talk_elder"` 这样的 key通过 `LocalizationManager.Get(displayTextKey, "Quest")` 在 UI 层取得显示文本。
注释也同步说明用途,使编辑器语义清晰。
---
### Suggestion 3 → Fix — `ChallengeRoomManager.cs` SpawnPoint 空值警告
**文件**`Assets/Scripts/Quest/ChallengeRoomManager.cs`
**问题**
```csharp
Vector3 pos = entry.spawnPoint != null ? entry.spawnPoint.position : Vector3.zero;
```
`spawnPoint` 未配置时静默回退到世界原点,策划不会收到任何提示,问题往往在运行时才被偶然发现。
**修复**
```csharp
Vector3 pos;
if (entry.spawnPoint != null)
{
pos = entry.spawnPoint.position;
}
else
{
Debug.LogWarning($"[ChallengeRoomManager] encounter[{index}] 中的 enemyAddressKey='{entry.enemyAddressKey}' " +
$"未配置 spawnPoint将在 Vector3.zero 生成。请在 ChallengeRoomSO 中补全配置。", this);
pos = Vector3.zero;
}
```
使用 `this` 作为第二参数,双击 Console 日志可直接定位到场景中的 `ChallengeRoomManager` 对象,加快排查效率。
---
### Suggestion 4 → Fix — `LoadingScreenManager.cs` 提示文字本地化
**文件**`Assets/Scripts/UI/LoadingScreenManager.cs`
**问题**
```csharp
[SerializeField] private string[] _tipMessages; // 直接文字(非本地化 key
// ...
_tipText.text = _tipMessages[Random.Range(0, _tipMessages.Length)];
```
注释已标注「P4-5 本地化模块完成后替换」v15 已完整实现 Localization 模块,此 TODO 应立即落地。
**修复**
```csharp
// using BaseGames.Localization; 已添加到文件顶部
[SerializeField] private string[] _tipMessages; // 本地化 key对应 "UI" 表中的条目,如 "tip_explore"
// ...
_tipText.text = LocalizationManager.Get(_tipMessages[Random.Range(0, _tipMessages.Length)], "UI");
```
类注释中移除「P4-5 本地化模块完成后替换」的 TODO 说明,类文档恢复简洁。
---
## 三、修复汇总
| 编号 | 文件 | 问题类型 | 问题描述 | 修复方式 |
|------|------|----------|----------|----------|
| TD-35 | `Localization/LocalizationManager.cs` | 框架纯净性 | 静态事件 `OnLanguageChanged` 作为兼容层暴露,接口实现委托给静态事件,`SetLanguage` 调用静态事件;框架无旧调用方需兼容 | 移除静态事件,添加私有实例字段 `_onLanguageChanged`,接口实现直接包装实例字段,`SetLanguage` 调用实例事件 |
| Fix-S1 | `Dialogue/DialogueUI.cs` | 功能缺失 | `DialogueLine.voiceClip` 字段从未被播放,语音功能形同虚设 | 新增 `[SerializeField] AudioSource _voiceSource``ShowLine` 中播放,`SkipTyping` 中停止 |
| Fix-S2 | `Quest/QuestObjectiveSO.cs` | 数据一致性 | `displayText` 存储直接文本,不支持多语言,与框架本地化约定不符 | 重命名为 `displayTextKey`,移除 `[TextArea]`,通过 `LocalizationManager.Get(displayTextKey, "Quest")` 获取显示文本 |
| Fix-S3 | `Quest/ChallengeRoomManager.cs` | 可调试性 | `spawnPoint` 为 null 时静默回退 `Vector3.zero`,策划配置遗漏不可见 | 拆分条件分支null 分支增加 `Debug.LogWarning``this` context 对象 |
| Fix-S4 | `UI/LoadingScreenManager.cs` | 数据一致性 | `_tipMessages` 存储直接字符串,随语言切换不刷新 | 添加 `using BaseGames.Localization`,用 `LocalizationManager.Get(key, "UI")` 包装取值,字段注释说明为本地化 key |
---
## 四、维度评分(更新)
| 维度 | v15 得分 | v16 得分 | 变化原因 |
|------|---------|---------|---------|
| 架构设计 | 9.8 | 9.8 | 无变化 |
| 性能优化 | 9.5 | 9.5 | 无变化 |
| 可扩展性 | 9.6 | 9.6 | 无变化 |
| 框架纯净性 | 9.7 | 9.9 | TD-35 彻底移除静态事件兼容层,接口实现完全规范 |
| 编辑器友好 | 9.5 | 9.6 | Fix-S3 增加含 context 对象的 LogWarning调试体验提升 |
| 使用便利性 | 9.5 | 9.5 | 无变化 |
| 数据逻辑一致性 | 9.6 | 9.8 | Fix-S2/S4 统一了 Quest 目标文本和 LoadingScreen 提示的本地化路径,消除数据层不一致 |
**综合得分9.68 / 10**+0.12
---
## 五、已知可接受的设计选择(更新)
原 v15 第五节条目 #2`LocalizationManager.OnLanguageChanged` 静态事件)已升级为 TD-35 并修复,从本节移除。
| 编号 | 条目 | 状态 |
|------|------|------|
| ✅ 1 | `GlobalSFXPlayer` 单例 | 保持可接受,全局 SFX 便利性需要 |
| ~~2~~ | ~~`LocalizationManager.OnLanguageChanged` 静态事件~~ | **TD-35 已修复,从此节移除** |
| ✅ 3 | `SpellManager` SelfBuff/Summon/Teleport 分支未完整实现 | 保持可接受,设计预留扩展点 |
| ✅ 4 | `SaveSlotController` 槽位数硬编码为 3 | 保持可接受,改动需协调多处 |
| ✅ 5 | `EventChainManager` 帧合并 `_evaluatePending` | 保持可接受,刻意性能优化 |
---
## 六、后续建议(可择期执行)
v15 的全部四条后续建议已在本轮实施,当前无新增后续建议。
框架在经历 16 个迭代后,核心代码已达到商业级 Action 游戏框架的一致性要求。后续工作重心建议转移至:
1. **运行时测试覆盖**为核心系统Combat、Quest、Localization编写 Unity Test Framework 单元/集成测试,覆盖主要分支。
2. **Addressables 预加载策略文档化**:当前 `ChallengeRoomManager``SpawnManager` 均在运行时 `InstantiateAsync`对于高频召唤场景可考虑预暖Preload标记的 Label 分组。
3. **Spell/StatusEffect 组合测试场景**:多个 StatusEffect 叠加时的优先级与互斥规则在代码层已有注释,建议在 Docs 层补充状态效果交互矩阵文档。
---
*上一版:[FrameworkReview_2026_May_v15.md](FrameworkReview_2026_May_v15.md)(加权 9.56*