多轮审查和修复

This commit is contained in:
2026-05-12 15:34:08 +08:00
parent f55d2a57c3
commit ebbbb7332e
805 changed files with 838724 additions and 1905 deletions

View File

@@ -0,0 +1,174 @@
# Framework Review — v32026 年 5 月)
> **基准**:本文档在 v19 项)和 v27 项)全部修复完毕的基础上,对 `Assets/Scripts` 进行第三轮深度扫描。
> **验证**:修复完成后 `get_errors()` → No errors零编译错误
---
## 一、总体架构健康评估
### ✅ 已通过验证的核心设计
| 检查项 | 结论 |
|--------|------|
| ServiceLocator 注册模式 | 所有注册均使用接口类型(含本轮新增)|
| RAII 事件订阅模式 | `Subscribe().AddTo(_subs)` + `_subs.Clear()` 全覆盖 |
| 无 FindObjectOfType | 全代码库零调用 |
| 无 Singleton 滥用 | NullFeedbackPlayer.Instance 为合法 Null Object Pattern |
| 事件频道 DDOL 隔离 | EventChannelRegistry 已修复v1-M3|
| 存档完整性 | HMAC-SHA256 + 原子写入 |
| 程序集依赖单向性 | Core → Core.Save 方向保持不变 |
---
## 二、本轮v3发现的问题
### B-1`SaveManager` 大量具体类型直接查询8 个文件)
**问题**`ISaveService` 接口仅覆盖了 I/O 操作Save/Load/QuickSave`SaveManager` 的业务
查询 API`GetFlag``IsBossDefeated``LastCheckpointScene` 等)被 8 个文件通过
`ServiceLocator.GetOrDefault<SaveManager>()` 直接访问,绕过接口层。
**根因**`BaseGames.Core.Save``BaseGames.Core` 存在单向依赖约束Save 不引用 Core
导致 `SaveManager` 无法直接实现 `ISaveService`;历史上 `SaveServiceAdapter` 仅转发了最小集合。
**受影响文件**
- `Quest/ChallengeRoomManager.cs`QuickSave、IsFirstClear、QuickLoad
- `Quest/ChallengeRoomTrigger.cs`IsBossDefeated
- `EventChain/EventChainSO.cs`GetFlag、SetFlag
- `EventChain/EventChainManager.cs`GetCompletedChains、SetChainCompleted
- `Progression/HPContainerPickup.cs`IsWorldCollected、GetPlayerMaxHP
- `Progression/ProgressLock.cs`IsBossDefeated、IsDoorOpened
- `Core/DeathRespawnService.cs`LastCheckpointScene/SpawnId、DeleteSlotAsync、ActiveSlot
- `Support/AntiSoftlock/AntiSoftlockSystem.cs`LastCheckpointScene/SpawnId
**修复方案**:扩展 `ISaveService` 接口覆盖所有业务查询方法;扩展 `SaveServiceAdapter`
完整转发;所有 8 个文件改用 `GetOrDefault<ISaveService>()`
**状态**:✅ 已修复
---
### B-2`SaveManager` / `GameManager` 以具体类型自注册到 ServiceLocator
**问题**
- `SaveManager.Awake()``ServiceLocator.Register<SaveManager>(this)` 仅用于自身重复防护
- `GameManager.Awake()``ServiceLocator.Register<GameManager>(this)` 仅用于自身重复防护
两者均无外部调用方通过接口以外的方式依赖该注册;具体类型暴露在 ServiceLocator 中违反
"通过接口而非实现依赖" 框架原则。
**修复方案**
- 两个类均改用 `private static T _instance;` 实例字段做重复防护
- `SaveManager.OnDestroy` 中清除实例字段、只 Unregister `ISaveableRegistry`
- `GameManager` 新增 `OnDestroy` 清除实例字段
**状态**:✅ 已修复
---
## 三、修复后的 ServiceLocator 全景v3 快照)
### 注册表Register
| 文件 | 接口键 | 说明 |
|------|--------|------|
| `GameServiceRegistrar.cs` | `IAudioService`NullAudioService 兜底) | 框架启动兜底 |
| `GameServiceRegistrar.cs` | `IDeathRespawnService` | Persistent 服务 |
| `GameServiceRegistrar.cs` | `ISceneService` | Persistent 服务 |
| `GameServiceRegistrar.cs` | `IEventChannelRegistry` | Persistent 服务 |
| `GameServiceRegistrar.cs` | `ISaveService`via SaveServiceAdapter | Persistent 服务 |
| `AudioManager.cs` | `IAudioService` | 覆盖兜底 |
| `CameraStateController.cs` | `ICameraService` | |
| `ClashResolver.cs` | `IClashService` | |
| `DifficultyManager.cs` | `IDifficultyService` | |
| `EventChannelRegistry.cs` | `IEventChannelRegistry` | |
| `GlobalObjectPool.cs` | `IObjectPoolService` | |
| `HitStopManager.cs` | `IHitStopService` | |
| `LocalizationManager.cs` | `ILocalizationService` | |
| `MapManager.cs` | `IMapService` | |
| `ProjectileManager.cs` | `IProjectileService` | |
| `QuestManager.cs` | `IQuestManager` | |
| `SaveManager.cs` | `ISaveableRegistry` | |
| `SettingsManager.cs` | `ISettingsService` | |
| `TutorialManager.cs` | `ITutorialService` | |
| `VFXPool.cs` | `IVFXPoolService` | |
| `AchievementManager.cs` | `IAchievementService` | |
| `AnalyticsManager.cs` | `IAnalyticsService` | |
| `DialogueManager.cs` | `IDialogueService` | |
| `PlatformBootstrap.cs` | `IPlatformService` | |
> **全部使用接口类型键,无任何具体类型键残留。**
---
## 四、ISaveService 扩展内容v3 新增)
本轮将 `ISaveService` 从 6 个成员扩展至 19 个成员,覆盖存档系统全部公开 API
```csharp
// 新增v3
void QuickLoad(); // 同步 fire-and-forget 版
Task DeleteSlotAsync(int slot);
string LastCheckpointScene { get; }
string LastCheckpointSpawnId { get; }
bool IsWorldCollected(string id);
bool IsDoorOpened(string id);
bool IsBossDefeated(string bossId);
int GetPlayerMaxHP();
bool IsFirstClear(string challengeId);
bool GetFlag(string flagId);
void SetFlag(string flagId, bool value);
IEnumerable<string> GetCompletedChains();
void SetChainCompleted(string chainId);
```
`SaveServiceAdapter` 内部完整转发上述全部方法。
---
## 五、三轮修复汇总
| 版本 | 问题数 | 类别 | 全部修复 |
|------|--------|------|----------|
| v1 | 9 | H×2, M×3, L×4 | ✅ |
| v2 | 7 | A架构×7 | ✅ |
| v3 | 2 | B接口完整性×2 | ✅ |
| **总计** | **18** | | ✅ 零编译错误 |
---
## 六、已知可接受的模式(非问题)
| 文件 | 模式 | 说明 |
|------|------|------|
| `FalseWall.cs:51` | 注释中的 `GetOrDefault<SaveManager>()` | 仅为开发示例注释,不影响运行 |
| `SaveManager.cs` 内部 `_instance` 字段 | `static SaveManager _instance` | 仅用于重复防护,无外部暴露 |
| `GameManager.cs` 内部 `_instance` 字段 | `static GameManager _instance` | 同上 |
---
## 七、当前代码库整体评估
### 架构设计 ⭐⭐⭐⭐⭐
- ServiceLocator 接口-实现分离完整
- 程序集依赖方向清晰Core.Events ← Core.Save ← Core ← 业务模块)
- SaveServiceAdapter 桥接模式正确解决跨程序集约束
### 可维护性 ⭐⭐⭐⭐⭐
- 所有服务可独立 mock/替换
- 事件频道完全解耦
- 无 FindObjectOfType / Singleton 滥用
### 扩展性 ⭐⭐⭐⭐
- 新服务只需:定义接口 → 实现类 → Awake 注册
- ISaveService 已覆盖全部存档操作,后续扩展追加方法即可
### 性能 ⭐⭐⭐⭐
- ObjectPool 覆盖 Projectile/VFX/Minion
- Update 热路径已缓存组件引用v1/v2 已修复)
- 存档 SemaphoreSlim 保证异步安全
### 编辑器友好 ⭐⭐⭐⭐
- 全部服务引用通过 `[SerializeField]` 在 Inspector 绑定
- 无 FindObjectOfType 拖慢场景打开