161 lines
8.9 KiB
Markdown
161 lines
8.9 KiB
Markdown
# 代码深度评审 DeepDive 2026 Q2
|
||
|
||
> 评审范围:`Assets/Scripts/` 416 个 .cs 文件(DeepDive_2026.md 修复完成后的新一轮评审)
|
||
> 重点模块:Audio、Camera、Dialogue、Quest、Progression、EventChain、UI、Tutorial、World(全子系统)、Support
|
||
> 评审标准:以商业级成熟作品(Hollow Knight、Celeste、Hades)为参照基线
|
||
|
||
---
|
||
|
||
## 一、评审维度与总分
|
||
|
||
| 维度 | 满分 | 得分 | 说明 |
|
||
|------|------|------|------|
|
||
| 架构设计 (Architecture) | 25 | 21 | SO 事件总线 + ServiceLocator 整体优秀,但仍有混用 Instance/ServiceLocator |
|
||
| 性能 (Performance) | 25 | 20 | 批处理 / 对象池 / 环形缓冲区均到位;3 处反射调用是负担 |
|
||
| 可扩展性 (Extensibility) | 20 | 17 | 谜题接口、EventChain、WorldStateRegistry 设计良好;对话变体未实装 |
|
||
| 编辑器友好 (Editor UX) | 15 | 13 | HurtBoxEditor / EventBusMonitorWindow 完善;极少数字段缺少 Tooltip |
|
||
| 使用便利性 (DX / API) | 15 | 12 | 核心 API 简洁;namespace 缺失与 SaveManager.Instance 残留拉低得分 |
|
||
| **合计** | **100** | **83** | |
|
||
|
||
---
|
||
|
||
## 二、各维度详细评分与问题清单
|
||
|
||
### 2.1 架构设计 (21/25)
|
||
|
||
#### 优点
|
||
- **SO 事件频道体系**成熟,`BaseEventChannelSO<T>` + `EventSubscription(IDisposable)` + `CompositeDisposable.AddTo()` 完整闭环,各系统无直接依赖。
|
||
- **ServiceLocator** 统一服务注册,`GetOrDefault<T>` 优雅处理可选服务。
|
||
- **GameStateMachine** 显式白名单状态机,避免非法转换,DeepDive_2026 已完善。
|
||
- **25 个 asmdef** 严格单向依赖链(Core → Player → Combat → … → World),编译隔离优秀。
|
||
- **WorldStateRegistry** 作为 ScriptableObject,SO 注入代替全局单例,设计一流。
|
||
- **EventChainManager** 中继 C# 事件架构清晰,Editor 专用静态事件零运行时开销。
|
||
|
||
#### 问题
|
||
| ID | 文件 | 描述 | 严重性 |
|
||
|----|------|------|--------|
|
||
| A-1 | `QuestManager.cs` | `OnEnable/OnDisable` 使用已废弃的 `SaveManager.Instance?.Register/Unregister` | 中 |
|
||
| A-2 | `ShopController.cs` | 同 A-1,`SaveManager.Instance?.Register/Unregister` | 中 |
|
||
| A-3 | `EventChainManager.cs` | `Awake` 中使用 `SaveManager.Instance?.GetCompletedChains()` | 中 |
|
||
| A-4 | `TutorialManager.cs` | 使用原始 Singleton 模式(`public static Instance`),未注册 ServiceLocator | 低 |
|
||
| A-5 | `DialogueManager.cs` | `ResolveVariant()` 为存根,变体条件从未与 `WorldStateRegistry` 实际对接 | 低 |
|
||
|
||
---
|
||
|
||
### 2.2 性能 (20/25)
|
||
|
||
#### 优点
|
||
- `EventBusMonitor`:固定 256 条 `EventRecord[]` 环形缓冲区,Editor 零 GC。
|
||
- `GlobalObjectPool`:`WarmupAsync` 预热,`IObjectPoolService` 接口注册,`ServiceLocator` 解耦。
|
||
- `BatchLOSSystem`:`HashSet + List` 双结构,O(1) 查重 + 分帧限制 8 个请求。
|
||
- `EquipmentManager.UsedNotches`:缓存字段,完全消除 LINQ Sum。
|
||
- `AudioManager`:6 路 SFX 轮转池,避免高密度战斗音效互戳;BGM 双 Source 交叉淡入淡出。
|
||
- `HomingProjectile`:方向向量用 `sqrMagnitude` 比较速度上限,无开方开销。
|
||
|
||
#### 问题
|
||
| ID | 文件 | 描述 | 严重性 |
|
||
|----|------|------|--------|
|
||
| P-1 | `LiquidZone.cs` | `PlayFeedback()` 通过 `GetMethod("PlayFeedbacks")` 反射调用,每次玩家进出液体区都触发 | 高 |
|
||
| P-2 | `PuzzleSwitch.cs` | 同 P-1,同一反射模式 | 高 |
|
||
| P-3 | `PuzzleReceiver.cs` | 同 P-1,同一反射模式 | 高 |
|
||
| P-4 | `Projectile.cs` | `ReturnToPool()` 使用 `GlobalObjectPool.Instance`(已标废弃),应走 ServiceLocator | 低 |
|
||
|
||
---
|
||
|
||
### 2.3 可扩展性 (17/20)
|
||
|
||
#### 优点
|
||
- `PuzzleInterfaces.cs`:`ISwitchable / IMovable / IActivatable` 三接口,谜题元素完全可替换实现。
|
||
- `AchievementCondition` + 11 个具体实现:抽象基类 + 工厂,新增成就类型零侵入现有代码。
|
||
- `EventChainSO` + `ChainCondition`:ScriptableObject 配置驱动,策划可在 Inspector 搭建复杂叙事链。
|
||
- `WorldStateRegistry.WorldObjectCategory`:枚举泛化 API,一个 registry 统一 Collectible/Door/Flag 等全部世界状态。
|
||
- `ToolSlotManager`:工具栏插槽与 SO 解耦,扩展新工具只需新建 ToolSO。
|
||
|
||
#### 问题
|
||
| ID | 文件 | 描述 | 严重性 |
|
||
|----|------|------|--------|
|
||
| E-1 | `DialogueManager.cs` | `ResolveVariant` 永远返回原始序列;条件分支对话完全无效 | 中 |
|
||
| E-2 | `AchievementManager.cs` | 注册为具体类型 `Register<AchievementManager>`,无法在测试中 mock | 低 |
|
||
|
||
---
|
||
|
||
### 2.4 编辑器友好 (13/15)
|
||
|
||
#### 优点
|
||
- `HurtBoxEditor`:运行时实时展示注入对象,调试受击逻辑极为便利。
|
||
- `EventBusMonitorWindow`:环形缓冲区在 Editor 窗口可视,零 GC。
|
||
- `BossSkillSequenceWindow`:Boss 技能序列可视化 Inspector。
|
||
- `AddressKeyValidator`:构建时自动校验 Addressable Key 拼写,防止发布错误。
|
||
- `WorldStateRegistry.OnEnable() => _states.Clear()`:每次进入 Play Mode 自动重置 SO 状态,无脏数据问题。
|
||
- `EventChainManager`:`OnChainExecutedInEditor` 静态事件仅在编辑器存在,零运行时影响。
|
||
|
||
#### 问题
|
||
| ID | 文件 | 描述 | 严重性 |
|
||
|----|------|------|--------|
|
||
| UX-1 | 全局 | `SpeedrunTimer`、`AccessibilityManager` 缺少 namespace,IDE 浏览/搜索时易混淆 | 低 |
|
||
| UX-2 | `AntiSoftlockSystem.cs` | 类体未在 namespace 内缩进,与项目其他文件风格不一致 | 低 |
|
||
|
||
---
|
||
|
||
### 2.5 使用便利性(API/DX)(12/15)
|
||
|
||
#### 优点
|
||
- `ServiceLocator.GetOrDefault<T>(fallback)` 安全查询,代码调用方无需 null 判断。
|
||
- `DamageInfo.From(so, knockDir, sourcePos, layer)` 工厂方法 + `Builder`:两种构造路径清晰。
|
||
- `CompositeDisposable.AddTo()`:Rx 风格订阅管理,防止事件泄漏。
|
||
- `QuestManager`:`IQuestManager` 接口 + `ServiceLocator.Register<IQuestManager>(this)`,调用方面向接口编程。
|
||
- `SkillSlotNames`:常量类消除 `"SoulSkill"` 等魔法字符串。
|
||
|
||
#### 问题
|
||
| ID | 文件 | 描述 | 严重性 |
|
||
|----|------|------|--------|
|
||
| D-1 | `SpeedrunTimer.cs` | 缺少 namespace,与全局命名空间污染冲突 | 低 |
|
||
| D-2 | `AccessibilityManager.cs` | 缺少 namespace | 低 |
|
||
| D-3 | `UIManager.cs` | `TogglePause()` 只开不合,按两次暂停后第二次无效 | 中 |
|
||
| D-4 | `AchievementManager.cs` | `_saveRef` 字段在 `OnLoad` 赋值后从未读取(死代码) | 低 |
|
||
|
||
---
|
||
|
||
## 三、与商业标准的横向对比
|
||
|
||
| 对比项 | Hollow Knight 参照模式 | 本项目现状 |
|
||
|--------|------------------------|-----------|
|
||
| 事件解耦 | 自定义 C# 事件 + delegate | SO 频道体系,更 Inspector 友好 ✓ |
|
||
| 状态机 | 纯 C# 非 MonoBehaviour 状态 | 同,PlayerStateBase 模式一致 ✓ |
|
||
| 对象池 | 静态池,键值 string | GlobalObjectPool + IObjectPoolService + ServiceLocator ✓✓ |
|
||
| 存档系统 | PlayerPrefs + 二进制 | Newtonsoft.Json + MD5 校验 + SemaphoreSlim 防并发 ✓✓ |
|
||
| 依赖注入 | 无(大量 singleton) | ServiceLocator(部分残留 singleton 待清理) ≈ |
|
||
| Addressables | Unity 自有 AssetBundle | Addressables + AddressKeyValidator 构建校验 ✓✓ |
|
||
| 谜题系统 | 基于碰撞的单一谜题 | ISwitchable/IActivatable 接口体系 ✓✓ |
|
||
| 对话变体 | 全局标记条件分支 | 框架存在但未接入 WorldStateRegistry(TODO) △ |
|
||
| 速通支持 | 无内置计时器 | SpeedrunTimer + ISaveable 持久化 ✓ |
|
||
| 无障碍 | 无内置色盲/震屏控制 | AccessibilityManager + ColorblindFilter ✓ |
|
||
|
||
---
|
||
|
||
## 四、修复项汇总(按优先级)
|
||
|
||
| 优先级 | ID | 文件 | 修复内容 |
|
||
|--------|----|------|----------|
|
||
| 高 | P-1,P-2,P-3 | `LiquidZone.cs`, `PuzzleSwitch.cs`, `PuzzleReceiver.cs` | 反射 → `MoreMountains.Feedbacks.MMFeedbacks` 直接转型 |
|
||
| 中 | A-1 | `QuestManager.cs` | `SaveManager.Instance` → `ServiceLocator.GetOrDefault<SaveManager>()` |
|
||
| 中 | A-2 | `ShopController.cs` | 同上 |
|
||
| 中 | A-3 | `EventChainManager.cs` | 同上 |
|
||
| 中 | D-3 | `UIManager.cs` | `TogglePause()` 改为真实 toggle |
|
||
| 低 | P-4 | `Projectile.cs` | `GlobalObjectPool.Instance` → `ServiceLocator.GetOrDefault<IObjectPoolService>()` |
|
||
| 低 | D-1 | `SpeedrunTimer.cs` | 补齐 namespace |
|
||
| 低 | D-2 | `AccessibilityManager.cs` | 补齐 namespace |
|
||
| 低 | D-4 | `AchievementManager.cs` | 删除 `_saveRef` 死代码字段 |
|
||
| 低 | UX-2 | `AntiSoftlockSystem.cs` | 类体补全缩进 |
|
||
|
||
---
|
||
|
||
## 五、不在本次修复范围内的已知问题(技术债)
|
||
|
||
| 问题 | 原因/说明 |
|
||
|------|----------|
|
||
| `DialogueManager.ResolveVariant()` 存根 | 需 Phase 4 完整接入 `WorldStateRegistry` 条件标记,属功能开发范畴,非代码质量问题 |
|
||
| `TutorialManager` raw singleton | 功能正确,仅可测试性不足;整改需新增接口,成本大于收益 |
|
||
| `AchievementManager` 注册具体类型 | 暂无 mock 需求,改为接口注册需新建 interface,暂缓 |
|
||
| `AudioManager.PlayBGM/PlaySFX(key)` 存根 | 等待 Phase 2 AudioEventSO 模块,属功能开发范畴 |
|