remove fsm

This commit is contained in:
陈思海 2025-12-26 17:46:46 +08:00
parent 0d80bcfa5b
commit 152faa5991
10 changed files with 0 additions and 672 deletions

View File

@ -1,119 +0,0 @@
using AlicizaX;
using UnityEditor;
using UnityEngine;
internal class FsmDebuggerWindow : EditorWindow
{
[MenuItem("Window/HighPerfFSM Debugger")]
public static void ShowWindow()
{
var win = GetWindow<FsmDebuggerWindow>("FSM Debugger");
win.Show();
}
private Vector2 _scroll;
private bool _autoRefresh = true;
private void OnEnable()
{
FSMDebugger.SetEnabled(true);
EditorApplication.update += RepaintIfNeeded;
}
private void OnDisable()
{
EditorApplication.update -= RepaintIfNeeded;
}
private void RepaintIfNeeded()
{
if (_autoRefresh) Repaint();
}
private void OnGUI()
{
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
{
GUILayout.Label("HighPerfFSM Debugger", EditorStyles.boldLabel);
GUILayout.FlexibleSpace();
_autoRefresh = GUILayout.Toggle(_autoRefresh, "Auto Refresh", EditorStyles.toolbarButton);
}
_scroll = EditorGUILayout.BeginScrollView(_scroll);
foreach (var kv in FSMDebugger.Entries)
{
var entry = kv.Value;
EditorGUILayout.BeginVertical("box");
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Label($"ID: {entry.Id}", GUILayout.Width(90));
GUILayout.Label(entry.Name, EditorStyles.boldLabel);
GUILayout.FlexibleSpace();
}
var stateName = (entry.StateNameGetter != null)
? entry.StateNameGetter(entry.StateIndex) ?? entry.StateIndex.ToString()
: entry.StateIndex.ToString();
EditorGUILayout.LabelField("State", stateName);
EditorGUILayout.LabelField("TimeInState", entry.TimeInState.ToString("F3"));
if (entry.BlackboardGetter != null && entry.Fields != null)
{
object bbObj = null;
try
{
bbObj = entry.BlackboardGetter();
}
catch
{
}
if (bbObj != null)
{
EditorGUILayout.LabelField("Blackboard");
EditorGUI.indentLevel++;
for (int i = 0; i < entry.Fields.Length; i++)
{
var f = entry.Fields[i];
object val = null;
try
{
val = f.GetValue(bbObj);
}
catch
{
}
EditorGUILayout.LabelField(f.Name, val != null ? val.ToString() : "null");
}
EditorGUI.indentLevel--;
}
else
{
EditorGUILayout.HelpBox("Blackboard getter returned null.", MessageType.Info);
}
}
if (entry.Owner != null && entry.Owner.TryGetTarget(out var owner) && owner != null)
{
EditorGUILayout.ObjectField("Owner", owner, typeof(UnityEngine.Object), true);
}
EditorGUILayout.EndVertical();
GUILayout.Space(4);
}
EditorGUILayout.EndScrollView();
if (GUILayout.Button("Clear All (Unregister)"))
{
var ids = new System.Collections.Generic.List<int>();
foreach (var kv in FSMDebugger.Entries) ids.Add(kv.Key);
foreach (var id in ids) FSMDebugger.Unregister(id);
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: b7e760f8a07d441dba01f9a5bf8fff62
timeCreated: 1745562869

View File

@ -1,28 +0,0 @@
using AlicizaX;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace AlicizaX
{
/// <summary>
/// 有限状态机组件。
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("Game Framework/FSM")]
public sealed class FsmComponent : MonoBehaviour
{
private IFsmModule _mFsmModule = null;
private void Awake()
{
_mFsmModule = ModuleSystem.RegisterModule<IFsmModule, FsmModule>();
if (_mFsmModule == null)
{
Log.Error("FSM manager is invalid.");
return;
}
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: a69e41ab65d84e83a0468f1a2cc3926f
timeCreated: 1712641057

View File

@ -1,84 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Scripting;
using Object = UnityEngine.Object;
namespace AlicizaX
{
[Preserve]
internal sealed class FsmModule : IFsmModule
{
private readonly List<IFsmRunner> _active = new List<IFsmRunner>(256);
private readonly List<IFsmRunner> _toRemove = new List<IFsmRunner>(64);
public int Priority => 0;
void IModuleLateUpdate.LateUpdate()
{
RemoveFsm();
}
private void RemoveFsm()
{
if (_toRemove.Count > 0)
{
for (int i = 0; i < _toRemove.Count; i++)
{
var f = _toRemove[i];
MemoryPool.Release(f);
f.Dispose();
_active.Remove(f);
}
_toRemove.Clear();
}
}
void IModuleUpdate.Update(float elapseSeconds, float realElapseSeconds)
{
float dt = Time.deltaTime;
for (int i = 0; i < _active.Count; i++)
{
_active[i].Tick(dt);
}
}
void IModuleAwake.Awake()
{
}
void IModule.Dispose()
{
for (int i = _active.Count - 1; _active.Count > 0; i--)
{
_toRemove.Add(_active[i]);
}
RemoveFsm();
}
private Fsm<T> CreatePooled<T>(FsmConfig<T> cfg, T blackboard, UnityEngine.Object owner = null, Func<int, string> stateNameGetter = null)
where T : class, IMemory
{
var fsm = Fsm<T>.Rent(cfg, blackboard, owner, stateNameGetter);
_active.Add(fsm);
return fsm;
}
public void DestroyFsm<T>(Fsm<T> fsm) where T : class, IMemory
{
if (fsm == null) return;
_toRemove.Add(fsm);
}
public Fsm<T> Create<T>(FsmConfig<T> cfg, UnityEngine.Object owner = null, Func<int, string> stateNameGetter = null)
where T : class, IMemory, new()
{
var bb = MemoryPool.Acquire<T>();
var fsm = CreatePooled(cfg, bb, owner, stateNameGetter);
return fsm;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 9eb47e20b70b4505bc1ac91a2669c2db
timeCreated: 1745559879

View File

@ -1,414 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
namespace AlicizaX
{
internal interface IFsmRunner : IDisposable, IMemory
{
int Id { get; }
string DisplayName { get; }
UnityEngine.Object Owner { get; }
void Tick(float deltaTime);
}
public delegate void StateEnter<T>(T bb) where T : class, IMemory;
public delegate int StateUpdate<T>(T bb) where T : class, IMemory; // -1 = stay
public delegate void StateExit<T>(T bb) where T : class, IMemory;
public delegate bool Condition<T>(T bb) where T : class, IMemory;
// ===================== StateFunc =====================
public sealed class StateFunc<T> where T : class, IMemory
{
public StateEnter<T> OnEnter;
public StateUpdate<T> OnUpdate;
public StateExit<T> OnExit;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static StateFunc<T> Make(StateEnter<T> enter = null, StateUpdate<T> update = null, StateExit<T> exit = null)
{
return new StateFunc<T>
{
OnEnter = enter ?? EmptyEnter,
OnUpdate = update ?? Stay,
OnExit = exit ?? EmptyExit,
};
}
private static void EmptyEnter(T bb)
{
}
private static int Stay(T bb) => -1;
private static void EmptyExit(T bb)
{
}
}
// ===================== Transition =====================
public struct Transition<T> where T : class, IMemory
{
public int From;
public int To;
public Condition<T> Cond; // may be null
public int Priority; // smaller first
public float Timeout; // >0 enables timeout
public Transition(int from, int to, Condition<T> cond, int priority = 0, float timeout = 0f)
{
From = from;
To = to;
Cond = cond;
Priority = priority;
Timeout = timeout;
}
}
internal struct TransitionIndex
{
public int Start; // start index in _trans
public int Length; // number of entries
}
public readonly struct FsmConfig<T> where T : class, IMemory
{
public readonly StateFunc<T>[] Funcs; // [state] -> funcs
public readonly Transition<T>[] Transitions; // flat transitions list
public readonly int StateCount; // >0
public readonly int DefaultState; // initial state
public FsmConfig(StateFunc<T>[] func, Transition<T>[] transition, int defaultState = -1)
{
Funcs = func;
Transitions = transition;
StateCount = Funcs.Length;
DefaultState = defaultState;
if (Funcs == null || Funcs.Length == 0)
throw new ArgumentException("Funcs must not be null/empty");
if (StateCount <= 0) StateCount = Funcs.Length;
if ((uint)DefaultState >= (uint)StateCount)
throw new ArgumentOutOfRangeException(nameof(DefaultState));
}
}
public sealed class Fsm<T> : IFsmRunner where T : class, IMemory
{
private static int _nextId;
public static Fsm<T> Rent(FsmConfig<T> cfg, T blackboard, UnityEngine.Object owner = null, Func<int, string> stateNameGetter = null)
{
Fsm<T> fsm = MemoryPool.Acquire<Fsm<T>>();
fsm.Init(cfg, blackboard, owner, stateNameGetter);
return fsm;
}
public static void Return(Fsm<T> fsm)
{
if (fsm == null) return;
MemoryPool.Release(fsm);
}
// ---- Instance ----
private StateFunc<T>[] _funcs;
private Transition<T>[] _trans;
private TransitionIndex[] _index;
private int _stateCount;
private T _bb;
private bool _disposed;
public int Id { get; private set; }
public string DisplayName { get; private set; }
public int Current { get; private set; }
public float TimeInState { get; private set; }
public bool Initialized { get; private set; }
public UnityEngine.Object Owner { get; private set; }
private Func<int, string> _stateNameGetter;
public T Blackboard
{
get => _bb;
}
public Fsm()
{
}
private void Init(FsmConfig<T> cfg, T blackboard, UnityEngine.Object owner, Func<int, string> stateNameGetter)
{
Id = Interlocked.Increment(ref _nextId);
DisplayName = typeof(T).Name;
_funcs = cfg.Funcs;
_trans = cfg.Transitions ?? Array.Empty<Transition<T>>();
_index = BuildIndex(_trans, cfg.StateCount);
_stateCount = cfg.StateCount;
_bb = blackboard;
Owner = owner;
_stateNameGetter = stateNameGetter;
Current = cfg.DefaultState;
TimeInState = 0f;
Initialized = false;
_disposed = false;
#if UNITY_EDITOR
FSMDebugger.Register(this, typeof(T));
FSMDebugger.BindProvider(Id, owner, BlackboardSnapshot, _stateNameGetter);
#endif
}
private object BlackboardSnapshot() => _bb;
private static TransitionIndex[] BuildIndex(Transition<T>[] t, int stateCount)
{
if (t.Length > 1)
{
Array.Sort(t, (a, b) =>
{
int f = a.From.CompareTo(b.From);
return (f != 0) ? f : a.Priority.CompareTo(b.Priority);
});
}
var idx = new TransitionIndex[stateCount];
int cur = 0;
while (cur < t.Length)
{
int from = t[cur].From;
int end = cur + 1;
while (end < t.Length && t[end].From == from) end++;
if ((uint)from < (uint)stateCount)
{
idx[from].Start = cur;
idx[from].Length = end - cur;
}
cur = end;
}
return idx;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset(int state)
{
if (_disposed) return;
if ((uint)state >= (uint)_stateCount) return;
if (Initialized) _funcs[Current].OnExit(_bb);
Current = state;
TimeInState = 0f;
_funcs[Current].OnEnter(_bb);
Initialized = true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Tick(float deltaTime)
{
if (_disposed) return;
bool flag = false;
if (!Initialized)
{
Reset(Current);
flag = true;
}
if (!flag)
{
TimeInState += deltaTime;
// 1) state internal update (may suggest next state)
int suggested = _funcs[Current].OnUpdate(_bb);
if (suggested >= 0 && suggested != Current)
{
ChangeState(suggested);
}
else
{
// 2) transitions (timeout first, then condition)
ref readonly TransitionIndex ti = ref _index[Current];
for (int i = 0; i < ti.Length; i++)
{
ref readonly var tr = ref _trans[ti.Start + i];
bool timeoutOk = (tr.Timeout > 0f && TimeInState >= tr.Timeout);
bool condOk = (!timeoutOk && tr.Cond != null && tr.Cond(_bb));
if (timeoutOk || condOk)
{
ChangeState(tr.To);
break;
}
}
}
}
#if UNITY_EDITOR
if (FSMDebugger.Enabled)
FSMDebugger.Track(this);
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ChangeState(int next)
{
if ((uint)next >= (uint)_stateCount || next == Current) return;
_funcs[Current].OnExit(_bb);
Current = next;
TimeInState = 0f;
_funcs[Current].OnEnter(_bb);
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
#if UNITY_EDITOR
FSMDebugger.Unregister(Id);
#endif
}
public void Clear()
{
_funcs = null;
_trans = null;
_index = null;
_stateCount = 0;
_stateNameGetter = null;
Owner = null;
Initialized = false;
TimeInState = 0f;
DisplayName = null;
MemoryPool.Release(_bb);
_bb = null;
}
}
#if UNITY_EDITOR
// ===================== FSMDebugger (Editor Only) =====================
public static class FSMDebugger
{
public sealed class Entry
{
public int Id;
public string Name; // Blackboard type name
public int StateIndex;
public double LastSeenEditorTime;
public float TimeInState;
public FieldInfo[] Fields; // cached fields of blackboard
public WeakReference<UnityEngine.Object> Owner; // may be null
public Func<object> BlackboardGetter; // snapshot getter (only queried when painting)
public Func<int, string> StateNameGetter; // may be null
}
private static readonly Dictionary<int, Entry> _entries = new Dictionary<int, Entry>(256);
private const double PRUNE_INTERVAL_SEC = 3.0;
private const double STALE_SEC = 10.0;
private static double _lastPruneCheck;
public static bool Enabled { get; private set; } = true;
static FSMDebugger()
{
UnityEditor.EditorApplication.update += PruneLoop;
}
public static void SetEnabled(bool enabled) => Enabled = enabled;
private static void PruneLoop()
{
double now = UnityEditor.EditorApplication.timeSinceStartup;
if (now - _lastPruneCheck < PRUNE_INTERVAL_SEC) return;
_lastPruneCheck = now;
var toRemove = ListPool<int>.Get();
foreach (var kv in _entries)
{
var e = kv.Value;
bool deadOwner = false;
if (e.Owner != null && e.Owner.TryGetTarget(out var target))
{
deadOwner = target == null;
}
else if (e.Owner != null)
{
deadOwner = true;
}
bool stale = (now - e.LastSeenEditorTime) > STALE_SEC;
if (deadOwner || stale)
toRemove.Add(kv.Key);
}
for (int i = 0; i < toRemove.Count; i++)
_entries.Remove(toRemove[i]);
ListPool<int>.Release(toRemove);
}
internal static void Register<T>(in Fsm<T> fsm, Type blackboardType) where T : class, IMemory
{
var id = fsm.Id;
if (_entries.ContainsKey(id)) return;
var fields = blackboardType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
_entries[id] = new Entry
{
Id = id,
Name = blackboardType.Name,
StateIndex = -1,
LastSeenEditorTime = UnityEditor.EditorApplication.timeSinceStartup,
TimeInState = 0f,
Fields = fields,
Owner = null,
BlackboardGetter = null,
StateNameGetter = null
};
}
internal static void BindProvider(int id, UnityEngine.Object owner, Func<object> bbGetter, Func<int, string> stateNameGetter)
{
if (!_entries.TryGetValue(id, out var e))
return;
e.Owner = owner != null ? new WeakReference<UnityEngine.Object>(owner) : null;
e.BlackboardGetter = bbGetter;
e.StateNameGetter = stateNameGetter;
}
internal static void Track<T>(in Fsm<T> fsm) where T : class, IMemory
{
if (!_entries.TryGetValue(fsm.Id, out var e))
return;
e.StateIndex = fsm.Current;
e.TimeInState = fsm.TimeInState;
e.LastSeenEditorTime = UnityEditor.EditorApplication.timeSinceStartup;
}
public static void Unregister(int id) => _entries.Remove(id);
public static IReadOnlyDictionary<int, Entry> Entries => _entries;
// --- tiny List pool ---
private static class ListPool<TItem>
{
private static readonly Stack<List<TItem>> _pool = new Stack<List<TItem>>(8);
public static List<TItem> Get() => _pool.Count > 0 ? _pool.Pop() : new List<TItem>(16);
public static void Release(List<TItem> list)
{
list.Clear();
_pool.Push(list);
}
}
}
#endif
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 0e40b7705a0b45a3b1e46ad7e89a5ebd
timeCreated: 1745547602

View File

@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
namespace AlicizaX
{
public interface IFsmModule : IModule, IModuleUpdate, IModuleAwake, IModuleLateUpdate
{
Fsm<T> Create<T>(FsmConfig<T> cfg, UnityEngine.Object owner = null, Func<int, string> stateNameGetter = null)
where T : class, IMemory, new();
void DestroyFsm<T>(Fsm<T> fsm) where T : class, IMemory;
}
}

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 5710f02ccd444b9c9c5d02d8bb2c3368