Files
zeling_v2/Docs/Review/DeepDive_2026.md
2026-05-12 15:34:08 +08:00

26 KiB
Raw Blame History

zeling_v2 深度代码评审 2026

评审日期2026-01
评审范围Assets/Scripts/ 全部 ~415 个 .cs 文件
评审标准:以同等体量商业 2D 动作游戏Hollow Knight / Celeste / Hades代码质量为基准
代码终态:本轮评审基于所有 P1-P3 修复全部落地后的最终版本


评分总览

维度 得分(/10 说明
架构设计 8.2 程序集隔离 + ServiceLocator + SO Event Channel 构成优秀骨架,少量单例混用
性能 8.0 热路径零分配设计扎实BatchLOS 时间切片;小处存在可优化空间
可扩展性 8.3 数据驱动策略模式普遍应用,工厂字典 + 版本迁移链完备
编辑器友好 8.2 工具链完整(监控/验证/可视化Post-fix 后类型化,个别窗口健壮性待补
使用便利性DX 8.2 API 命名清晰,订阅生命周期管理完善,混用模式尚存,部分接口语义有歧义
综合 8.2 同等体量独立游戏上游水准,离头部商业游戏代码约 0.51.0 分距离

一、架构设计

1.1 程序集隔离Assembly Definitions

25 个 .asmdef 文件将模块划分为独立编译单元,强制单向依赖:

Core → Input → Player → Combat → Enemies → World → ...
  • 无循环依赖BaseGames.Parry 不引用 BaseGames.CombatConsumeParry() 签名无 DamageInfo 参数——这种取舍有意为之,体现了架构约束的一致贯彻。
  • 接口切面ILOSRequesterIDamageableIPoiseSourceIStatusEffectableIObjectPoolServiceIPlatformService 等接口均定义在依赖链上游,让下游实现以干净方式向上暴露能力。
  • 条件编译护栏#if GRAPH_DESIGNER#if STEAMWORKS_NET#if UNITY_EDITOR 三类编译守卫严格隔离平台/工具代码,防止运行时包体污染。

评价:程序集设计达到商业中等水准。大型工作室(如 Team Cherry同样采用类似分层策略。


1.2 服务定位器ServiceLocator

// 静态字典Unity 主线程单线程访问,无锁竞争
private static readonly Dictionary<Type, object> _services = new();

public static T Get<T>()         // 缺失时抛出异常,快速失败
public static T GetOrDefault<T>() // 缺失时返回 null防御性访问
public static void RegisterIfAbsent<T>(...) // 幂等注册

#if UNITY_EDITOR
public static void OverrideForTest<T>(...) // 测试注入点
#endif
  • 设计优点:单责任(查找/注册),Get<T>() 快速失败语义明确,GetOrDefault<T>() 防御性访问分开Editor 测试注入不污染运行时。
  • 局限:静态状态在 Domain Reload 后需要手动清理Unity 在 [InitializeOnLoad] 中已有对应处理);构造图对新人不可见。

对比Hades 的引擎使用类似的 Service Locator而非 DI 容器),同规模项目此方案已足够。


1.3 SO Event Channel 系统

// BaseEventChannelSO<T>
private event Action<T> _action;  // 私有 backing field防止外部 = 覆盖
public event Action<T> Action { add => _action += value; remove => _action -= value; }

// 订阅返回 IDisposable支持 CompositeDisposable.AddTo() 生命周期绑定
public EventSubscription Subscribe(Action<T> handler) { ... }
特性 评估
私有 backing field 防外部 = 覆盖,只能 +=/-=
EventSubscriptionreadonly struct 零分配IDisposable 自动反订阅
CompositeDisposable.AddTo() 生命周期与 MonoBehaviour 绑定,无泄漏
EventBusMonitor 256 条环形记录 运行时事件流可观测
Editor 订阅者计数 0 订阅者时红色高亮警告

最强设计点EventSubscription 作为 readonly struct 实现 IDisposable,避免了大量项目中常见的"忘记取消订阅"内存泄漏问题,与 UniRx/R3 的 Disposable 模式对齐。


1.4 状态机体系

玩家状态机PlayerStateBase + PlayerController

  • 纯 C# 状态对象(无 MonoBehaviour 开销),构造器注入依赖,ValidTransitions 白名单 #if UNITY_EDITOR 校验。
  • Dictionary<Type, PlayerStateBase> _states O(1) 查找,无反射。

游戏状态机GameStateMachine

  • 纯 C# 类(不挂 MonoBehaviourDictionary<GameStateId, IGameState> + ValidNextStates 白名单,TransitionTo() 失败返回 error 字符串而非抛异常。

敌人状态机EnemyBase._stateObjs

  • Dictionary<EnemyStateType, IEnemyState> POCO 实现,状态由子类在 Awake 填充,基类不假定具体状态集。

弹反状态机ParrySystem

  • 枚举 ParryPhase { Inactive, Startup, Active, EndLag, CounterWindow } 清晰定义相变,Update 驱动计时,IsParrying/IsInCounterWindow 布尔属性暴露只读状态。

潜在问题

  • GameStateMachine.TransitionTo_current.ValidNextStates.Contains()ValidNextStatesIEnumerable(线性查找),在频繁转换时存在微小 O(n) 开销。建议内部改用 HashSet<GameStateId>

1.5 存档系统

SaveManagerSemaphoreSlim 并发锁)
  ├── ISaveable注册接口
  ├── ISaveStorageLocalFileStorage 实现)
  ├── SaveMigratorgoto 版本链 1.0→1.1→2.0→2.1
  └── SaveDataNewtonsoft.Json 序列化)
  • SemaphoreSlim(1,1) 防止并发写入损坏文件。
  • Checksum 两步计算(先 null→序列化→计算→填入→再序列化正确且清晰注释。
  • SaveMigratorgoto case 是 C# 语言规范中唯一正确的 switch-fallthrough 写法,并非 bad practice。

混用模式问题(-0.2 分)SaveManager.InstanceVFXPool.InstanceGlobalObjectPool.Instance 为传统单例,而其他服务均通过 ServiceLocator 访问。其中 GlobalObjectPool 在 Awake 同时注册 ServiceLocator.Register<IObjectPoolService>(this),形成双重访问路径,容易造成混淆。


1.6 架构设计待改进项

问题 影响 建议
SaveManager.Instance 未接入 ServiceLocator 模式不一致,测试困难 ISaveManager 接口 + ServiceLocator 注册
AnalyticsManager 无 namespace 声明 全局命名空间污染 添加 namespace BaseGames.Support.Analytics
PlayerController.GetCurrentPoiseLevel() 硬返回 PoiseLevel.None 误导性 API调用者以为玩家有霸体 注释说明或移除方法,改为常量字段
IGameState.ValidNextStatesIEnumerable 状态转换 O(n) 改为 IReadOnlySet<GameStateId> 实现

二、性能

2.1 热路径零分配设计

类型 技术 效果
DamageInfo struct + From() 工厂 无堆分配
EventSubscription readonly struct IDisposable 无堆分配
HurtBox 8 步管线 纯 struct/值类型操作 每帧命中无 GC 压力
HitBox 命中去重 HashSet<Collider2D> O(1) per check
MaterialPropertyBlock StatusEffectManager 渲染 不产生材质实例
Newtonsoft.Json Formatting.None SaveManager 减小序列化字符串体积
ValidTransitions 白名单 #if UNITY_EDITOR 只在 Editor 执行 运行时无额外开销

2.2 BatchLOSSystem 时间切片

[DefaultExecutionOrder(-200)]  // 保证在 EnemyBase.FixedUpdate 之前执行
private const int _maxRequestersPerFrame = 8;

// 均匀旋转偏移,避免每帧处理同一批请求
private int _offset;
for (int i = 0; i < _maxRequestersPerFrame; i++)
{
    int idx = (_offset + i) % _requesters.Count;
    // ... raycast + callback
}
_offset = (_offset + _maxRequestersPerFrame) % _requesters.Count;

设计优点:无论敌人数量多少,每帧固定 8 次 Raycast时间复杂度 O(1) per frame。通过轮转偏移保证每个请求者以均匀频率得到更新。

待优化(-0.15 分)

  • _requesters 使用 List<ILOSRequester>Register 时内部 Contains() 为 O(n)。当场景内存在 >30 个敌人时,批量注册阶段(关卡加载)会产生 O(n²) 开销。建议改用 HashSet<ILOSRequester>(List + HashSet) 双结构。

2.3 VFXPoolP3-10 修复后)

Play(vfxRef, position, ...)
  ├── TryDequeue() 命中 → PlayImmediate同帧播放无 Addressables 等待)
  └── 未命中           → PlayLoadAsync异步加载 + 实例化)

修复前每次 Play() 即使池中已有实例也要经过一帧协程等待。修复后池命中路径 0 帧延迟,与 Celeste 的预热粒子池策略一致。


2.4 GlobalObjectPool

  • WarmupAsync() 预热,避免运行时 Addressables.InstantiateAsync 延迟。
  • Dictionary<string, Queue<PooledObject>> 池 + Dictionary<string, LinkedList<PooledObject>> 活跃链表O(1) 入队/出队 + O(1) 强制回收LinkedList.Remove 为 O(1) 已知节点)。
  • MaxCount > 0 限制池 + 活跃对象总量,防止无限扩张。

2.5 性能待改进项

问题 位置 严重度 建议
BatchLOSSystem._requesters.Contains() O(n) Register() 改用 HashSet<ILOSRequester>
EquipmentManager.UsedNotches 每次调用 LINQ Sum() 属性 getter 维护 _usedNotches 缓存字段,装备/卸下时增减
AnalyticsManager.Track() 创建 new Dictionary<string,object> 每次调用 低(非热路径) 在 Gameplay 密集调用点使用静态预分配
DamageInforeadonly struct DamageInfo.cs 标记为 readonly structBuilder 内部操作局部变量
EventBusMonitor.Queue<EventRecord> struct 装箱 Editor only 极低 EventRecord[] 环形数组 + int head/tail
ClashResolver XOR key 碰撞 ResolveClash() 极低 (int, int) 对元组替代 XOR

三、可扩展性

3.1 数据驱动架构ScriptableObject

以下系统全面采用 SO 数据驱动:

系统 SO 类型 可配置项
护符 CharmSO + ICharmEffect[] 策略模式,效果任意组合
技能 FormSkillSO + SkillSlotOverride 护符可覆盖技能槽
Boss 技能 BossSkillSO + SkillSequenceSO Windup/Active/Recovery 三段配置
伤害源 DamageSourceSO 直接 DamageInfo.From(so) 零分配构建
弹反配置 ParryConfigSO 前摇/后摇/反击窗口毫秒级可调
装备 EquipmentConfigSO 初始 Notch 数
世界状态 WorldStateRegistry (SO) OnEnable 自动清理Editor 安全

ICharmEffect 策略模式是可扩展性最强的设计:新护符效果只需实现接口,无需修改任何管理器代码,完全符合开闭原则。


3.2 StatusEffect 工厂字典P2-5 修复后)

// 修复前:静态 switch新效果必须修改 StatusEffectManager 源码
// 修复后:
private readonly Dictionary<DamageType, Func<StatusEffect>> _effectFactories = new();

public void RegisterEffectFactory(DamageType type, Func<StatusEffect> factory)
    => _effectFactories[type] = factory;

// Boss 模块可在运行时注册自定义效果
StatusEffectManager.RegisterEffectFactory(DamageType.Dark, () => new DarkCurseEffect());

对外扩展点与运行时动态注册并存,是 Hades 中 Boon 效果系统类似的做法。


3.3 SaveMigrator 版本迁移链

switch (data.Meta.Version)
{
    case "1.0": data = MigrateFrom1_0(data); goto case "1.1";
    case "1.1": data = MigrateFrom1_1(data); goto case "2.0";
    case "2.0": data = MigrateFrom2_0(data); goto case "2.1";
    case "2.1": break;
}
  • 新版本只需添加一个新的 case + goto,旧版本代码不变。
  • 每个迁移函数独立,测试友好(传入 SaveData 验证输出)。
  • null 合并运算符 ??= 处理旧版本缺失字段,不影响新版本正常路径。

局限:版本字符串 "1.0" 为 magic string若版本标识改为 int/enum 可减少拼写错误风险。


3.4 平台抽象层

// IPlatformService 接口
// SteamPlatformService#if UNITY_STANDALONE && STEAMWORKS_NET
// ConsolePlatformService预留
// MockPlatformService测试用

多平台切换不需要修改任何业务代码。与 Hades / Cuphead 多平台发布策略一致。


3.5 WorldStateRegistry 泛化 API

// 泛化版本(直接使用)
public bool IsMarked(WorldObjectCategory category, string id)
public void Mark(WorldObjectCategory category, string id)

// 具名别名(向后兼容)
public bool IsCollected(string id) => IsMarked(WorldObjectCategory.Collectible, id);
public void MarkDestroyed(string id) => Mark(WorldObjectCategory.Destroyed, id);

新类别只需在枚举添加值,无需修改逻辑层,同时保留具名 API 的可读性。OnStateChanged 事件允许 UI/测试代码响应式订阅,不耦合到具体业务逻辑。


3.6 可扩展性待改进项

问题 影响 建议
SkillManager 技能槽硬编码为字符串 "SoulSkill"/"SpiritSkill1"/"SpiritSkill2" 新形态需修改多处字符串 抽象为 SkillSlotId enumconst string 集中管理
EquipmentManager._collected.Contains() 为 O(n) 100+ 护符时 改用 HashSet<CharmSO> _collectedSet
SaveMigrator 版本为 magic string 拼写错误难察觉 改为 Version 类或 int 常量
PlayerController.GetCurrentPoiseLevel() 始终返回 None 玩家霸体无法实现 实现基于护符/状态的动态计算

四、编辑器友好性

4.1 工具链全景

BaseGames/Tools/
  ├── Event Bus Monitor    Ctrl+Shift+E   — 运行时事件流监控
  ├── Boss Skill Sequence Viewer          — 甘特图可视化 Boss 技能时序
  ├── Validate Address Keys               — Addressables key 一致性检查
  └── SOValidationRunner   (Build Hook)   — ScriptableObject 完整性验证

这四个工具覆盖了运行时调试设计验证构建前检查三个阶段,形成完整的质量保障链。


4.2 EventBusMonitorWindow

[Time]  [Frame]  [Channel]              [Payload]       [Subs]
0.234   143      OnPlayerTakeDamage     {amount:12.0}   3
0.251   144      OnEnemyDied            {id:"Slug_01"}  2
0.267   145      OnHealPickup           ← 0 subs        0     ← 红色警告行
  • Filter:实时文本过滤,IndexOf 大小写不敏感。
  • Pause Capture:保留历史快照不被新事件覆盖。
  • Auto Scroll_scroll.y = float.MaxValue 强制滚底。
  • 0 订阅者红色高亮:立即暴露频道配错或漏连的问题。

唯一缺陷EventBusMonitor 后端使用 Queue<EventRecord> 而非固定大小数组,每次超出 256 条时 Dequeue() 有轻微 GCEditor only可接受


4.3 BossSkillSequenceWindow

甘特图实时渲染 Boss 技能相位:

相位 颜色 含义
Windup 黄色 前摇
Active 红色 伤害判定窗口
Recovery 灰色 后摇
VulnerabilityWindow 绿色覆盖 被弹反可反击窗口
DurationNormalized < 0.1 警告红 阶段过短,设计器警告

拖放 BossSkillSO / SkillSequenceSO 即可加载,EditorGUIUtility.PingObject 点击高亮资产——这是 Unity 原生编辑器工具的最佳实践写法。


4.4 AddressKeyValidator

public class AddressKeyValidatorBuildHook : IPreprocessBuildWithReport
{
    public int callbackOrder => 0;  // 在 SOValidationRunner(1) 之前执行

    public void OnPreprocessBuild(BuildReport report)
    {
        // 反射枚举 AddressKeys 所有 const string 字段
        // 与 Addressable 分组实际地址集合做差集
        // 有孤儿 key → throw BuildFailedException → 构建中止
    }
}

强制构建门槛:孤儿 AddressKey 会导致运行时 Addressables.LoadAssetAsync 失败,这类错误在发布版本中极难排查。IPreprocessBuildWithReport 在构建流水线最早阶段拦截,与 CI/CD 自动化完全兼容。


4.5 SOValidationRunner + IValidatableP3-9 修复后)

// 修复前:字符串启发式判断严重性
bool isError = msg.Contains("必须") || msg.StartsWith("❌");

// 修复后:类型化严重性
foreach (var result in validatable.Validate())
{
    if (result.Severity == ValidationSeverity.Error)
        errors.Add($"❌ {result.Message}  ({path})");
    else
        warnings.Add($"⚠️ {result.Message}  ({path})");
}

严重性分级Error/WarningValidationResult 结构体持有,消除了脆弱的字符串模式匹配。


4.6 HurtBoxEditorP3-8 修复后)

// 修复前:反射读取 private 字段(字符串 fieldName脆弱
// 修复后typed lambda getter
(System.Func<HurtBox, object> getter, string label, string absentNote)[] _fields = {
    (hb => hb.EditorOwner,           "Owner (IDamageable)", "— 注入失败"),
    (hb => hb.EditorShieldable,      "Shieldable",         "— 无护盾"),
    (hb => hb.EditorParrySystem,     "ParrySystem",        "— 无弹反"),
    (hb => hb.EditorPoiseSource,     "PoiseSource",        "— 无霸体"),
    (hb => hb.EditorStatusEffectable,"StatusEffectable",   "— 无状态效果"),
};

字段重命名后编译器立即报错,而非运行时 null 静默失败。


4.7 编辑器友好性待改进项

问题 建议
BossSkillSequenceWindow_loadedSkill 字段未作空字段检查 在 DrawSkillTimeline 入口添加 HelpBox 提示
EventBusMonitor 使用 Queue 而非固定 EventRecord[] 换循环缓冲区,彻底消除 Editor GC
SOValidationRunner 未提供 "一键修复" 按钮 对 Warning 级别问题提供可选自动修复
无场景引用可视化工具 仿 Odin Inspector [SceneObjectsOnly] 属性或自定义 PropertyDrawer

五、使用便利性Developer Experience

5.1 命名一致性

全项目命名规范高度一致:

约定 示例
EventChannel SO_on 前缀 _onPlayerDied, _onSaveIndicatorVisible
SO 类型后缀 InputReaderSO, ParryConfigSO, CharmEventChannelSO
接口前缀 I IDamageable, ILOSRequester, ISaveable, IPlatformService
管理器后缀 Manager EquipmentManager, SaveManager, StatusEffectManager
枚举 Type/Phase/Id ParryPhase, GameStateId, StatusEffectType
私有字段 _camelCase _currentSlot, _saveLock, _effectFactories

商业项目级别的命名一致性,新团队成员阅读代码时认知成本极低。


5.2 API 契约清晰度

优秀范例:

// TryEquipCharmnull = 成功string = 错误原因(优于 bool + out string
public string TryEquipCharm(CharmSO charm) { ... }

// ConsumeJump/ConsumeAttack/ConsumeDash读取即消耗避免调用者手动清零
public bool ConsumeJump() { ... }

// GetOrDefault明确声明可能返回 null不同于 Get 的快速失败语义
public static T GetOrDefault<T>() { ... }

// ValidationResult.Error / ValidationResult.Warning工厂方法减少直接 new
public static ValidationResult Error(string msg) => new(ValidationSeverity.Error, msg);

需改进的 API

// HitBox.OnHitConfirmed 是 public field非 event keyword
// 外部可以用 = 覆盖所有订阅者
public Action<DamageInfo> OnHitConfirmed;  // ❌

// 应改为:
public event Action<DamageInfo> OnHitConfirmed;  // ✅

// PlayerController.GetCurrentPoiseLevel() 始终返回 PoiseLevel.None
// 调用者无法区分"玩家本身无霸体设计"和"功能未实现"
public PoiseLevel GetCurrentPoiseLevel() => PoiseLevel.None;  // ❌ 误导性

5.3 订阅生命周期管理

// 推荐写法CompositeDisposable 与 MonoBehaviour 生命周期绑定)
private CompositeDisposable _subs = new();

private void OnEnable()
{
    _onPlayerDied.Subscribe(OnPlayerDied).AddTo(_subs);
    _onRoomEntered.Subscribe(OnRoomEntered).AddTo(_subs);
}

private void OnDisable() => _subs.Dispose();

全项目统一了此模式,彻底解决了传统 OnEnable += / OnDisable -= 遗忘匹配的问题。这是区别于大多数中小型 Unity 项目的最大质量优势之一。


5.4 InputBuffer 设计

// 3 个独立帧缓冲,每帧递减,消耗即清零
// 尺寸全部可在 Inspector 调节(不需要修改代码)
[SerializeField] private float _jumpBufferDuration   = 0.15f;
[SerializeField] private float _attackBufferDuration = 0.12f;
[SerializeField] private float _dashBufferDuration   = 0.10f;

ConsumeJump() / ConsumeAttack() / ConsumeDash() 的调用者不需要知道缓冲窗口时长,只需询问"现在能不能执行"。Celeste 的 Coyote Time 实现与此完全同构。


5.5 混用模式(-0.2 分)

访问路径矛盾:
  ServiceLocator.Get<IObjectPoolService>()   // GlobalObjectPool ✓
  GlobalObjectPool.Instance                  // GlobalObjectPool ✓(同一对象,两条路)
  SaveManager.Instance                       // SaveManager不通过 ServiceLocator
  VFXPool.Instance                           // VFXPool不通过 ServiceLocator
  ClashResolver → ServiceLocator.GetOrDefault<ClashResolver>()  // ✓
  AudioManager → ???(已移除旧 .Instance但新路径需确认

团队成员面对混用时难以判断"我该用哪个",也会使单元测试的 Mock 替换复杂化。


5.6 使用便利性待改进项

问题 建议
HitBox.OnHitConfirmed 为 public field 改为 public event Action<DamageInfo>
混用 .Instance 单例 + ServiceLocator 统一为 ServiceLocator.Instance 标记 [Obsolete]
DamageInforeadonly struct 标记 readonly,修改操作改为 With...() 方法
SkillSlot 字符串魔法值 提取为 static class SkillSlotNames 常量
AnalyticsManager 无 namespace 添加 namespace BaseGames.Support.Analytics

六、商业基准对标

维度 zeling_v2 Hollow Knight估算 Celeste开源代码 HadesGDC 演讲)
程序集隔离 25 asmdef 多 asmdef 单项目 分层
事件系统 SO Channel + IDisposable 自定义事件总线 Celeste 事件系统 消息总线
零分配热路径 struct DamageInfo struct 伤害值 简单值类型 严格零分配
时间切片 AI BatchLOSSystem 视野感知分帧 N/A 模式分帧
数据驱动护符 CharmSO + ICharmEffect Charm 系统 N/A Boon SO
存档版本迁移 goto 链 版本号检查
编辑器工具链 4 专用工具 未知 Lönn 编辑器 内部工具
弹反系统完备性 5 相位状态机 经典弹反 N/A 多弹反类型
模式一致性 ⚠️ 混用单例 统一单例 统一单例 统一 SL

七、综合建议

高优先级(影响可维护性)

  1. 统一服务访问模式SaveManagerVFXPool 注册到 ServiceLocator.Instance 添加 [Obsolete]
  2. HitBox.OnHitConfirmed 改为 event:消除外部覆盖风险,影响范围小。
  3. AnalyticsManager 添加 namespaceBaseGames.Support.Analytics5 分钟可完成。
  4. BatchLOSSystem._requesters 改 HashSet:场景大规模加载时性能优化。

中优先级(影响代码质量)

  1. PlayerController.GetCurrentPoiseLevel() 实现或标记未完成
  2. DamageInfo 标记为 readonly structBuilder 内使用局部变量。
  3. IGameState.ValidNextStates 改为 IReadOnlySet<GameStateId>
  4. EquipmentManager.UsedNotches 缓存计算结果,避免每次调用 LINQ Sum()

低优先级(技术债偿还)

  1. SaveMigrator 版本字符串改为常量 const string V1_0 = "1.0",消除 magic string。
  2. SkillSlot 字符串统一到 SkillSlotNames 常量类
  3. EventBusMonitor 改用固定 EventRecord[] 环形缓冲区(消除 Editor GC

附录:文件覆盖说明

本次评审直接阅读的源文件(按模块):

模块 已审文件
Core/Events BaseEventChannelSO.cs, EventSubscription.cs, EventBusMonitor.cs
Core/Save SaveManager.cs, SaveMigrator.cs, ISaveable.cs, WorldStateRegistry.cs
Core/Pool GlobalObjectPool.cs, PooledObject.cs
Core/Assets AssetLoader.cs, AssetReleaseTracker.cs
Core ServiceLocator.cs, GameStateMachine.cs
Input InputReaderSO.cs, InputBuffer.cs
Player PlayerController.cs, PlayerStateBase.cs, PlayerMovement.cs
Combat HurtBox.cs, HitBox.cs, DamageInfo.cs, ClashResolver.cs
Combat/StatusEffects StatusEffectManager.cs
Enemies EnemyBase.cs, BossBase.cs, BatchLOSSystem.cs
Equipment EquipmentManager.cs
Skills SkillModifierRegistry.cs
Parry ParrySystem.cs
VFX VFXPool.cs
Support AnalyticsManager.cs, SteamPlatformService.cs
Editor EventBusMonitorWindow.cs, BossSkillSequenceWindow.cs, AddressKeyValidator.cs, HurtBoxEditor.cs, SOValidationRunner.cs

受覆盖范围限制,DialogueQuestCutsceneTutorialLocalization 等子系统未纳入本次深度审查。


生成于 2026-01 | 评审人GitHub Copilot (Claude Sonnet 4.6)