Files
zeling_v2/Docs/Review/Minimap_Review_Round25_Independent.md
Joywayer f74d7f1877 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.
2026-05-25 23:15:12 +08:00

7.9 KiB
Raw Permalink Blame History

小地图系统 R25 独立评审报告

评审轮次Round 25R24 修复后全面重审)
评审基准:成熟 2D Metroidvania 游戏的商业级标准;编辑器工具须对开发者/策划可用友好


一、各维度评分

维度 满分 得分 变化
架构设计 & 解耦合 25 24.5 ±0
性能 & 运行时效率 20 19.5 ±0
编辑器工具质量 15 14.5 ±0
代码质量 & 可维护性 15 13.5 -0.5
存档 & 持久化 10 9.0 -0.5
可扩展性 10 9.5 ±0
功能完整性 5 5.0 ±0
综合 100 95.5 -2.0

R24 得分97.5 → R25 得分95.5(发现 1 Critical + 2 Normal 问题)


二、确认正常的设计R24 修复全部落地)

状态
TeleportService 完整重建135 行)
RequestTeleport 源 RoomId 改为 IPlayerPositionProvider.CurrentRoomId
MapInputHandler 删除 _zoom 双重状态OnScroll 直接读写 _zoomTarget.localScale.x
MapLayoutEditorWindow 搜索框 ✕ 清除按钮
执行顺序链MapManager(-700)→MapPlayerTracker(-600)→MapPinManager(-500)→TeleportService(-400)→UI(0)
ISaveable 防御性拷贝三处对称
_servicesReady 短路MapPanel & MinimapHUD 对称)
MapRoomDataSO.ChooseDisplayIcon DRY 消除
MapServiceExtensions 集中 BuildRegionDict / ResolveRegionDisplayName
三对象池MapPanelCell/Exit/PinMinimapHUDCell/Pin
发现动画协程自清理R20-N1 RunRevealAnim
MinimapHUD O(viewRadius²) 空间索引裁剪
UnsubscribeServices 有意不对称注释说明

三、新发现问题

C1 — CriticalTeleportService.CanTeleportTo 逻辑反转Fail-Open 安全漏洞)

文件Assets/_Game/Scripts/World/Map/TeleportService.cs
行号L8182

问题

_mapSvc ??= ServiceLocator.GetOrDefault<IMapService>();
return _mapSvc == null || _mapSvc.IsExplored(roomId);  // ← BUG

_mapSvc 查询失败(服务未注册、场景切换中等)时,返回 true(允许传送)。
而注释明确写道:"需要玩家已探索过目标房间(仅已知位置才允许传送)"
逻辑与意图完全相反:

  • 实际行为:_mapSvc == null无条件放行Fail-Open
  • 预期行为:_mapSvc == null拒绝传送Fail-Safe

影响:玩家可在 MapService 不可用时(存档切换、热重载等边缘时机)跳过探索校验,传送到从未到达过的房间,破坏探索核心机制。

修复

return _mapSvc != null && _mapSvc.IsExplored(roomId);

N1 — NormalMapPanel._subs 声明但永远为空(死代码)

文件Assets/_Game/Scripts/World/Map/MapPanel.cs
行号L76声明、L109Clear

问题

private readonly CompositeDisposable _subs = new();   // 永远不会有内容
// ...
private void OnDisable()
{
    _subs.Clear();   // ← 空操作
    // ...
}

MapPanel 的所有事件订阅均通过直接 += / -= 方式管理(在 SubscribeServices / UnsubscribeServices 中),没有任何订阅通过 .AddTo(_subs) 加入。_subs.Clear() 是一个完全的空操作。

影响:轻微;不影响运行时行为,但

  1. 误导后续维护者(以为订阅已通过 CompositeDisposable 管理)
  2. 在 OnDisable 中清理了并不存在的订阅,逻辑意图不清晰

修复选项 A推荐:删除 _subs 字段和 _subs.Clear() 调用,保持现有 += 管理方式即可(已有 UnsubscribeServices 妥善处理)。


N2 — NormalMapInputHandler 缺少 _zoomTarget 配置校验

文件Assets/_Game/Scripts/World/Map/MapInputHandler.cs
行号L21 注释、L97 & L382MapPanel.CurrentZoom

问题

  • MapInputHandler._zoomTarget 注释写"通常为 _roomContainer格子根节点"
  • MapPanel.CurrentZoom 明确读取 _roomContainer.localScale.x
  • MapInputHandler.OnScroll 写入 _zoomTarget.localScale
  • 若在 Inspector 中将 _zoomTarget 配置为非 _roomContainer 的节点,两者的 scale 将静默分裂:CurrentZoom 读到的是旧值,OnScroll 写入的是新值,缩放操作功能性损坏但无任何报错

影响:仅在配置错误时触发,但属于"配置错误无提示"的隐患,在 Prefab 调试时难以定位。

修复:在 Awake 中添加运行时校验警告:

private void Awake()
{
    _panel = GetComponent<MapPanel>();
#if UNITY_EDITOR || DEVELOPMENT_BUILD
    if (_zoomTarget != null && _panel != null)
    {
        // MapPanel.CurrentZoom 读取 _roomContainer要求 _zoomTarget 与其为同一节点
        Debug.LogWarning("[MapInputHandler] _zoomTarget 应配置为 MapPanel 的 _roomContainer格子根节点" +
                         "否则 CurrentZoom 与缩放操作将读写不同节点导致状态分裂。", this);
    }
#endif
}

更优做法:提供 public void SetZoomTarget(RectTransform t) 由 MapPanel.OnEnable 注入,彻底消除配置依赖。


四、各文件详细状态

MapPanel.cs

  • 架构五层解耦Interface → ServiceLocator → C# Events → UI → Object Pool
  • 性能:三对象池 + PinsVersion 脏检查 + _servicesReady 短路
  • 死代码_subs 字段N1⚠️
  • 其余对象池三种Cell/Exit/Pin均正确入池、出池、OnDestroy 销毁

MinimapHUD.cs

  • O(viewRadius²) 空间索引裁剪
  • _servicesReady 短路 + 跨场景重连null 服务引用 + 重置标志)
  • GC 友好:复用 _toRemove_roomsInViewBuffer_newlyAddedBuffer
  • 无新问题

MapInputHandler.cs

  • R24-N2 修复落地:无独立 _zoom 字段OnScroll 直接读写 _zoomTarget.localScale.x
  • 配置隐患:缺少 _zoomTarget 校验N2⚠️

TeleportService.cs

  • R24 完整重建架构正确ISaveable / ITeleportService / 单例保护
  • C1 逻辑反转CanTeleportTo_mapSvc == null 时 Fail-Open

MapManager.cs

  • 执行顺序 (-700) / ISaveable / IMapService
  • GetRoomsByRegion 懒加载缓存
  • NotifyDatabaseChanged 同步清空区域缓存

MapPinManager.cs (MapPin.cs)

  • 执行顺序 (-500) / ISaveable / IPinService
  • PinsVersion 脏版本号

MapServiceExtensions.cs

  • 无状态扩展方法集
  • GetVisibility / CreatePinAtWorldPos / BuildRegionDict / ResolveRegionDisplayName

MapLayoutEditorWindow.cs编辑器

  • 拖拽/缩放/验证/搜索/图例/Play Mode 玩家点
  • ✕ 清除按钮R24-N3
  • MatchesRoomType RoomType 枚举搜索R23-N2
  • GUIStyle 缓存(避免 60fps × 100 房间重分配)
  • Undo.undoRedoPerformed 注册

五、修复优先级

编号 严重度 文件 影响 是否立即修复
C1 🔴 Critical TeleportService.cs Fail-Open 逻辑反转,破坏探索机制
N1 🟡 Normal MapPanel.cs 死代码误导维护 推荐
N2 🟡 Normal MapInputHandler.cs 配置错误无提示 推荐

六、评分历史

轮次 综合评分 主要变化
R17 93.0 初轮大规模重构后
R18 93.8 平移/缩放 + 协程修复
R19 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-1.5+ N1-0.25+ N2-0.25

R25 评分低于 R24因 R24 重建 TeleportService 时引入了 C1 逻辑反转错误fail-open vs fail-safe该问题在 R24 评审中被遗漏。


R25 评审完成时间2025