Add independent review reports for Minimap system (Rounds 8, 9, and 26)

- Round 8 report highlights improvements in architecture, editor usability, and data robustness, with a total score of 80/100.
- Round 9 report focuses on editor extension capabilities, identifying issues with room data indexing and layout editing, resulting in a score of 76/100.
- Round 26 report evaluates the system against commercial standards, noting new issues and confirming previous fixes, with a score of 95.8/100.
This commit is contained in:
2026-05-25 23:15:12 +08:00
parent e2bc324905
commit f74d7f1877
53 changed files with 6825 additions and 270 deletions

View File

@@ -0,0 +1,188 @@
# 小地图系统 R26 独立评审报告
**评审轮次**Round 26R25 修复后全面重审)
**评审基准**:成熟 2D Metroidvania 游戏商业级标准 + 专业编辑器扩展
---
## 一、各维度评分
| 维度 | 满分 | 得分 | vs R25修复后 |
|------|------|------|----------------|
| 架构设计 & 解耦合 | 25 | 24.0 | -0.5 |
| 性能 & 运行时效率 | 20 | 19.5 | ±0 |
| 编辑器工具质量 | 15 | 14.5 | ±0 |
| 代码质量 & 可维护性 | 15 | 13.8 | -0.2 |
| 存档 & 持久化 | 10 | 9.5 | ±0 |
| 可扩展性 | 10 | 9.5 | ±0 |
| 功能完整性 | 5 | 5.0 | ±0 |
| **综合** | **100** | **95.8** | **-1.7** |
> R25修复后基准97.5 → R2695.8(发现 2 项新问题)
---
## 二、R25 修复全部落地确认
| 修复项 | 状态 |
|--------|------|
| C1TeleportService.CanTeleportTo `_mapSvc == null \|\| ...``_mapSvc != null && ...` | ✅ |
| N1MapPanel._subs 死代码字段及 Clear() 调用全部移除 | ✅ |
| N2MapInputHandler.Awake 展开 + `#if UNITY_EDITOR \|\| DEVELOPMENT_BUILD` 校验警告 | ✅ |
---
## 三、持续表现优秀的设计
| 维度 | 设计亮点 |
|------|---------|
| **接口解耦** | IMapService / IPlayerPositionProvider / IPinService / ITeleportService 全通过 ServiceLocatorUI 层无任何具体类引用 |
| **执行顺序链** | MapManager(-700)→MapPlayerTracker(-600)→MapPinManager(-500)→TeleportService(-400)→UI(0);服务注册先于所有消费方 |
| **空间索引共享** | MapDatabaseSO 统一维护 `_cellToRoom` 字典MinimapHUD 的 O(viewRadius²) 剔除与 MapPlayerTracker 的 O(1) 房间判定共享同一索引,无重复构建 |
| **五类对象池** | MapPanelCell/Exit/Pin+ MinimapHUDCell/Pin全量 Disable 入池、Enable 出池OnDestroy 销毁剩余发现动画协程自清理R20-N1|
| **ISaveable 防御性拷贝** | MapManager / MapPinManager / TeleportService 三处对称OnSave new HashSet/ListOnLoad Clear+foreach Add |
| **_servicesReady 短路** | MapPanel + MinimapHUD 均在三服务就绪后置 true消除每帧 ServiceLocator 查询 |
| **LateUpdate 脏检查** | MapPanel 玩家图标RoomId + NormPos 双字段MinimapHUD 玩家圆点Pin 版本号脏检查——全部避免无效 RectTransform 读写 |
| **DRY** | ChooseDisplayIcon 集中在 MapRoomDataSOBuildRegionDict / ResolveRegionDisplayName 集中在 MapServiceExtensionsMapPanel + MinimapHUD 均通过委托调用 |
| **编辑器工具** | 拖拽/缩放/验证4类错误/搜索RoomId/RegionId/RoomType三维/图例/Play Mode 玩家叠加GUIStyle 缓存MatchesRoomType 不区分大小写 |
| **存档健壮性** | OnLoad 空集合防御、空 id 过滤OnValidate 自动 Trim RoomId、迁移旧 bool 字段;`delayCall -=;+=` 防止 Inspector 快速操作重复触发 |
| **UnsubscribeServices 有意不对称** | MapPanelOnDestroy 末尾不清空引用vs MinimapHUD置 null + 重置标志,支持跨场景重连)——均有注释说明 |
---
## 四、新发现问题
### N1 — NormalITeleportService 接口不完整(`UnlockTeleportStation` / `NotifyTeleportCompleted` 缺失)
**文件**`ITeleportService.cs`(接口缺失),`TeleportService.cs`L103115 公开方法)
**问题**
```csharp
// ITeleportService 接口中存在的方法:
bool CanTeleportTo(string roomId);
void RequestTeleport(string targetRoomId);
event Action<string, string> OnTeleportRequested;
event Action<string> OnTeleportCompleted;
// ─── 缺失的两个写操作方法 ───
// TeleportService 上有 public 定义,但不在接口中:
public void NotifyTeleportCompleted(string arrivedRoomId); // 场景加载系统须调用
public void UnlockTeleportStation(string roomId); // 游戏触发器须调用
```
**影响**
- **场景加载系统**完成传送后需调用 `NotifyTeleportCompleted`,但通过 `ServiceLocator.GetOrDefault<ITeleportService>()` 只能拿到接口,无法访问该方法;调用方被迫使用具体类型(`TeleportService`)或反射,**破坏接口解耦原则**。
- **传送站触发器**`OnTriggerEnter` 等)需要调用 `UnlockTeleportStation`,同样面临相同问题。
- 接口 + ServiceLocator 模式在整个系统中一致使用,此处缺口会让后续维护者混淆。
**修复**:在 `ITeleportService` 中补全两个方法:
```csharp
/// <summary>解锁指定房间的传送点(游戏触发器调用)。</summary>
void UnlockTeleportStation(string roomId);
/// <summary>场景加载系统传送完成后调用,触发 OnTeleportCompleted 事件。</summary>
void NotifyTeleportCompleted(string arrivedRoomId);
```
---
### N2 — NormalMapPinManager 缺少 `_isDuplicate` 单例保护(与 MapManager / MapPlayerTracker 不一致)
**文件**`MapPin.cs`MapPinManager 类L3237
**问题**
```csharp
// MapManager正确
private void Awake()
{
if (ServiceLocator.GetOrDefault<IMapService>() != null) { _isDuplicate = true; Destroy(gameObject); return; }
ServiceLocator.Register<IMapService>(this);
}
// MapPlayerTracker正确
private void Awake()
{
if (ServiceLocator.GetOrDefault<IPlayerPositionProvider>() != null) { _isDuplicate = true; ... }
...
}
// MapPinManager缺少保护
private void Awake()
{
// ← 无重复实例检测
ServiceLocator.Register<IPinService>(this); // 若已有注册,直接覆盖
}
```
**影响**
- 若场景中意外存在两个 MapPinManagerPersistent 场景加载两次、DontDestroyOnLoad 重复等),第二个实例会覆盖 ServiceLocator 注册,但第一个实例的 `ISaveable` 仍保持注册状态(`OnEnable` 中加入 SaveableRegistry导致存档时 `OnSave` 被调用两次、集合竞争写入 `SaveData.Map.Pins`
- 系统其他三处服务均有 `_isDuplicate` 守卫,此处缺失属于架构一致性漏洞。
**修复**
```csharp
private void Awake()
{
if (ServiceLocator.GetOrDefault<IPinService>() != null)
{
_isDuplicate = true;
Destroy(gameObject);
return;
}
ServiceLocator.Register<IPinService>(this);
}
// OnEnable / OnDisable / OnDestroy 首行加 if (_isDuplicate) return;
```
---
## 五、各文件评分摘要
| 文件 | 状态 | 备注 |
|------|------|------|
| MapManager.cs | ✅ 完整 | 执行顺序/ISaveable/IMapService/缓存/LINQ 仅在非热路径 |
| MapPlayerTracker.cs | ✅ 完整 | O(1) 空间索引/平滑归一化/单例保护 |
| **MapPinManagerMapPin.cs** | ⚠️ N2 | 缺少 _isDuplicate 保护 |
| **TeleportService.cs** | ⚠️ N1 | 接口缺口UnlockTeleportStation/NotifyTeleportCompleted |
| MapPanel.cs | ✅ 完整 | R25-N1 _subs 死代码已移除;五层解耦;三对象池 |
| MinimapHUD.cs | ✅ 完整 | O(viewRadius²) 剔除跨场景重连GC 友好缓冲区 |
| MapInputHandler.cs | ✅ 完整 | R24-N2 单一 scale 状态R25-N2 配置警告 |
| MinimapInputHandler.cs | ✅ 完整 | 干净委托,单职责 |
| MapRoomCellUI.cs | ✅ 完整 | 双场景复用PlayRevealAnim 颜色恢复 |
| MapRoomDataSO.cs / MapDatabaseSO | ✅ 完整 | ChooseDisplayIcon 集中空间索引共享OnValidate 含延迟通知防抖 |
| MapServiceExtensions.cs | ✅ 完整 | 纯静态无状态DRY 中心 |
| RegionNameDisplay.cs | ✅ 完整 | CompositeDisposable 正确使用;协程 OnDisable 终止安全 |
| **ITeleportService.cs** | ⚠️ N1 | 缺少两个写操作方法声明 |
| MapLayoutEditorWindow.cs编辑器 | ✅ 完整 | 搜索+图例+拖拽+验证+GUIStyle 缓存+✕按钮 |
---
## 六、修复优先级
| 编号 | 严重度 | 文件 | 影响 | 建议 |
|------|--------|------|------|------|
| N1 | 🟡 Normal | ITeleportService.cs + TeleportService.cs | 接口不完整导致调用方被迫使用具体类型 | 立即修复 |
| N2 | 🟡 Normal | MapPin.csMapPinManager | 多实例场景存档竞争写入 | 立即修复 |
---
## 七、评分历史
| 轮次 | 综合评分 | 主要变化 |
|------|---------|---------|
| R17 | 93.0 | 初轮重构后 |
| R18R19 | 93.8 | 平移/缩放/协程修复 |
| R20 | 94.2 | DRY + 协程自清理 |
| R21 | 95.0 | ServicesReady 对称 |
| R22 | 96.5 | BuildRegionDict 集中 |
| R23 | 97.5 | MatchesRoomType + 执行顺序 |
| R24 | 97.5 | TeleportService 重建(遗留 C1 |
| R25修复前 | 95.5 | 发现 C1 逻辑反转 + N1 死代码 + N2 无警告 |
| R25修复后基准 | 97.5 | 三项全修复 |
| **R26** | **95.8** | 发现 N1接口不完整-1.2+ N2单例缺失-0.5|
---
*R26 评审完成时间2026-05-25*