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
@@ -94,5 +94,58 @@ namespace BaseGames.Tests.EditMode.AI
Assert.AreEqual(SinglePost.Post, second.EntryState); // 新模块生效
Object.DestroyImmediate(so);
}
static System.Collections.Generic.List<BaseGames.Core.ValidationResult> Validate(PerceptionRecipeSO so)
=> new System.Collections.Generic.List<BaseGames.Core.ValidationResult>(so.Validate());
[Test]
public void Validate_Clean_WhenFullyConfigured()
{
var so = MakeE001Recipe();
CollectionAssert.IsEmpty(Validate(so));
Object.DestroyImmediate(so);
}
[Test]
public void Validate_ReportsError_WhenAbilityMissing()
{
// 默认配方:RushEngagement 未配能力
var so = ScriptableObject.CreateInstance<PerceptionRecipeSO>();
var results = Validate(so);
Assert.IsTrue(results.Exists(r => r.Severity == BaseGames.Core.ValidationSeverity.Error));
Object.DestroyImmediate(so);
}
[Test]
public void Validate_DoesNotLeaveCachedGraph()
{
// 校验期试建的图不能留给运行时——否则改了模块后拿到的是校验时的旧图。
var so = MakeE001Recipe();
Validate(so);
so.AssignModules(new SinglePost(LocomotionMode.Idle),
new RushEngagement("other", RushExit.OnLostTarget));
Assert.AreEqual(SinglePost.Post, so.GetOrBuildGraph().EntryState);
Object.DestroyImmediate(so);
}
[Test]
public void Validate_ReportsError_WhenCommittedRushHasZeroCooldown()
{
// Committed 的防抖动保证依赖能力自身有冷却;cooldown<=0 时冲锋态↔未发现态
// 每帧抖动,这是配置期就能发现的错误,必须在校验里显式报出。
var ability = ScriptableObject.CreateInstance<BaseGames.Enemies.Abilities.EnemyAbilitySO>();
ability.abilityId = "e001_chase";
ability.cooldown = 0f;
var so = ScriptableObject.CreateInstance<PerceptionRecipeSO>();
so.AssignModules(new DisguiseThenPatrol(), new RushEngagement(ability, RushExit.Committed));
var results = Validate(so);
Assert.IsTrue(results.Exists(r =>
r.Severity == BaseGames.Core.ValidationSeverity.Error && r.Message.Contains("cooldown")));
Object.DestroyImmediate(so);
Object.DestroyImmediate(ability);
}
}
}