feat(enemy): AI 配方接入 SO 校验——漏配/歧义/零冷却 Committed 在编辑期与构建期报错

This commit is contained in:
2026-07-29 17:20:12 +08:00
parent 6df4a259b7
commit da217af113
6 changed files with 124 additions and 1 deletions
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using UnityEngine;
using BaseGames.AI;
using BaseGames.Core;
namespace BaseGames.Enemies
{
@@ -8,7 +10,7 @@ namespace BaseGames.Enemies
/// 两个下拉各选一个模块即可,无需写代码。有独门机制的敌人改写 AiScript 子类。
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/AI/感知型 AI 配方", fileName = "ENM_")]
public sealed class PerceptionRecipeSO : AiRecipeSO
public sealed class PerceptionRecipeSO : AiRecipeSO, IValidatable
{
[Tooltip("未发现层:玩家尚未被发现时的行为形状")]
[SerializeReference, SubclassSelector] IUnawareModule _unaware = new SinglePost();
@@ -30,5 +32,35 @@ namespace BaseGames.Enemies
_unaware = unaware; _engagement = engagement;
InvalidateGraph();
}
/// <summary>SOValidationRunner 自动扫描调用。结构性校验(模块是否选、建图是否成功)
/// 由配方负责;模块自身的配置(能力引用、冷却语义等)委托给模块的 Validate()——
/// 新增一种打法不需要回来改这里。</summary>
public IEnumerable<ValidationResult> Validate()
{
string who = name;
if (_unaware == null)
yield return ValidationResult.Error($"{who}:未选择未发现层模块。");
if (_engagement == null)
yield return ValidationResult.Error($"{who}:未选择交战层模块。");
if (_unaware == null || _engagement == null) yield break;
foreach (var r in _engagement.Validate())
yield return new ValidationResult(r.Severity, $"{who}{r.Message}");
// 结构性校验:直接试建一次图,模块与骨架的建图期守卫会把问题抛出来
// (能力漏配、Rest 不在 States、态未声明、跨模块状态名冲突等)。
// 这是最彻底的检查——凡是运行时会炸的,这里就会炸。
ValidationResult? buildFailure = null;
try { GetOrBuildGraph(); }
catch (System.Exception e)
{
buildFailure = ValidationResult.Error($"{who}:建图失败 —— {e.Message}");
}
finally { InvalidateGraph(); } // 校验期建的图不留给运行时
if (buildFailure.HasValue) yield return buildFailure.Value;
}
}
}