using UnityEngine;
using BaseGames.Core.Events;
namespace BaseGames.AI
{
///
/// AI 配方资产基类。子类以序列化字段描述一张图,Build 里组装。
/// 一个资产 = 一种敌人 AI;所有引用该资产的实例共享同一张 AiGraph(flyweight)。
///
public abstract class AiRecipeSO : ScriptableObject, IAiDefinition
{
AiGraph _cached;
///
/// 子类若要自己的 OnEnable,必须 override 本方法并调 base.OnEnable()——
/// 声明成 protected virtual 正是为此:若留作 private,子类另写一个 OnEnable 会
/// 静默遮蔽它(Unity 只调最派生的那个),缓存清理从此不再注册且无任何报错。
///
protected virtual void OnEnable()
{
// 项目已关闭 Domain Reload:SO 的运行时态在多次 Play 会话间会残留,
// 改了配方再进 Play 仍用旧图。登记到统一的"进入 Play 前重置"通道。
PlayModeResetHook.Register(ClearCache);
}
void ClearCache() => _cached = null;
/// 装配 / 修改模块后调用,丢弃已缓存的图。
/// 不调的话,改动要等到下次进入 Play 才生效——静默的陈旧图。
protected void InvalidateGraph() => _cached = null;
/// 校验专用:用一次性 BrainBuilder 试建,只为暴露建图期异常。
/// 刻意不碰 _cached——走 GetOrBuildGraph 会在缓存已热时跳过 Build(等于没探测),
/// 且事后置空缓存会破坏"一个配方共享一张图"的 flyweight 不变量。
protected void ProbeBuild()
{
var b = new BrainBuilder();
Build(b);
b.Build();
}
public AiGraph GetOrBuildGraph()
{
if (_cached == null)
{
var b = new BrainBuilder();
Build(b);
_cached = b.Build();
}
return _cached;
}
protected abstract void Build(BrainBuilder b);
}
}