diff --git a/Runtime/GameApp.cs b/Runtime/GameApp.cs index 854c88d..12b9c04 100644 --- a/Runtime/GameApp.cs +++ b/Runtime/GameApp.cs @@ -69,26 +69,7 @@ public static partial class GameApp } private static IObjectPoolService _objectPool; - - - /// - /// 获取有限状态机组件。 - /// - public static IProcedureService Procedure - { - get - { - if (_procedure == null) - { - _procedure = AppServices.RequireApp(); - } - - return _procedure; - } - } - - private static IProcedureService _procedure; - + /// /// 获取Asset组件。 diff --git a/Runtime/Procedure/IProcedureService.cs b/Runtime/Procedure/IProcedureService.cs deleted file mode 100644 index 893273a..0000000 --- a/Runtime/Procedure/IProcedureService.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace AlicizaX -{ - public interface IProcedureService : IService - { - Type CurrentProcedureType { get; } - void InitializeProcedure(IEnumerable availableProcedures, Type defaultProcedureType); - void ClearAllProcedures(); - bool ContainsProcedure(Type procedureType); - bool TrySwitchProcedure(Type procedureType); - } - - public static class ProcedureServiceExtensions - { - public static bool SwitchProcedure(this IProcedureService procedureService) where T : IProcedure - { - return procedureService.TrySwitchProcedure(typeof(T)); - } - - public static bool SwitchProcedure(this IProcedureService procedureService, Type procedureType) - { - return procedureService.TrySwitchProcedure(procedureType); - } - } -} diff --git a/Runtime/Procedure/IProcedureService.cs.meta b/Runtime/Procedure/IProcedureService.cs.meta deleted file mode 100644 index 4585a5c..0000000 --- a/Runtime/Procedure/IProcedureService.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 18d5ca3d17384612b2d2023084b6a97b -timeCreated: 1763451617 \ No newline at end of file diff --git a/Runtime/Procedure/ProcedureBase.cs b/Runtime/Procedure/ProcedureBase.cs index 8d3609e..57e5a6e 100644 --- a/Runtime/Procedure/ProcedureBase.cs +++ b/Runtime/Procedure/ProcedureBase.cs @@ -1,72 +1,43 @@ namespace AlicizaX { - public interface IProcedure - { - IProcedureService ProcedureService { get; set; } - void Init(); - void Enter(); - void Leave(); - void Update(); - void Destroy(); - } + // public interface IProcedure + // { + // void Init(); + // void Enter(); + // void Leave(); + // void Update(); + // void Destroy(); + // } /// /// 流程基类 - 使用模板方法模式定义流程生命周期 /// - public abstract class ProcedureBase : IProcedure + public abstract class ProcedureBase { - public IProcedureService ProcedureService { get; set; } - - void IProcedure.Init() - { - OnInit(); - } - - void IProcedure.Enter() - { - OnEnter(); - } - - void IProcedure.Leave() - { - OnLeave(); - } - - void IProcedure.Update() - { - OnUpdate(); - } - - void IProcedure.Destroy() - { - OnDestroy(); - } - - - protected virtual void OnInit() + protected internal virtual void OnInit() { } - protected virtual void OnEnter() + protected internal virtual void OnEnter() { } - protected virtual void OnLeave() + protected internal virtual void OnLeave() { } - protected virtual void OnUpdate() + protected internal virtual void OnUpdate() { } - protected virtual void OnDestroy() + protected internal virtual void OnDestroy() { } protected internal void SwitchProcedure() where T : ProcedureBase { - ProcedureService.SwitchProcedure(); + ProcedureBuilder.SwitchProcedure(); } } } diff --git a/Runtime/Procedure/ProcedureBuilder.cs b/Runtime/Procedure/ProcedureBuilder.cs new file mode 100644 index 0000000..ac6bb38 --- /dev/null +++ b/Runtime/Procedure/ProcedureBuilder.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AlicizaX +{ + public static class ProcedureBuilder + { + private const string ProcedureRunnerName = "[ProcedureRunner]"; + + private static ProcedureRunner _runner; + + public static Type CurrentProcedureType => _runner != null ? _runner.CurrentProcedureType : null; + + public static bool IsRunning => _runner != null; + + public static void InitializeProcedure(IEnumerable availableProcedures, Type defaultProcedureType) + { + DestroyProcedure(); + + var gameObject = new GameObject(ProcedureRunnerName); + UnityEngine.Object.DontDestroyOnLoad(gameObject); + + _runner = gameObject.AddComponent(); + _runner.InitializeProcedure(availableProcedures, defaultProcedureType); + } + + public static void InitializeProcedure(ProcedureBase[] availableProcedures, Type defaultProcedureType) + { + DestroyProcedure(); + + var gameObject = new GameObject(ProcedureRunnerName); + UnityEngine.Object.DontDestroyOnLoad(gameObject); + + _runner = gameObject.AddComponent(); + _runner.InitializeProcedure(availableProcedures, defaultProcedureType); + } + + public static void InitializeProcedure(List availableProcedures, Type defaultProcedureType) + { + DestroyProcedure(); + + var gameObject = new GameObject(ProcedureRunnerName); + UnityEngine.Object.DontDestroyOnLoad(gameObject); + + _runner = gameObject.AddComponent(); + _runner.InitializeProcedure(availableProcedures, defaultProcedureType); + } + + public static bool SwitchProcedure() where T : ProcedureBase + { + return _runner != null && _runner.TrySwitchProcedure(typeof(T)); + } + + public static bool SwitchProcedure(Type procedureType) + { + return _runner != null && _runner.TrySwitchProcedure(procedureType); + } + + public static bool ContainsProcedure() where T : ProcedureBase + { + return _runner != null && _runner.ContainsProcedure(typeof(T)); + } + + public static bool ContainsProcedure(Type procedureType) + { + return _runner != null && _runner.ContainsProcedure(procedureType); + } + + public static void DestroyProcedure() + { + if (_runner == null) + { + return; + } + + var gameObject = _runner.gameObject; + _runner.Shutdown(); + _runner = null; + + if (gameObject != null) + { + UnityEngine.Object.Destroy(gameObject); + } + } + + private sealed class ProcedureRunner : MonoBehaviour + { + private const int MaxLoadFactorNumerator = 7; + private const int MaxLoadFactorDenominator = 10; + + private Type[] _types; + private ProcedureBase[] _procedures; + private int[] _orderedIndices; + private ProcedureBase[] _orderedProcedures; + private int _procedureCount; + private int _bucketCount; + + private ProcedureBase _currentProcedure; + private ProcedureBase _defaultProcedure; + private bool _isDestroying; + + public Type CurrentProcedureType => _currentProcedure != null ? _currentProcedure.GetType() : null; + + public void InitializeProcedure(IEnumerable availableProcedures, Type defaultProcedureType) + { + ClearAllProcedures(); + + if (availableProcedures == null || defaultProcedureType == null) + { + return; + } + + foreach (var procedure in availableProcedures) + { + AddProcedure(procedure); + } + + if (TryGetProcedure(defaultProcedureType, out var defaultProcedure)) + { + _defaultProcedure = defaultProcedure; + TrySwitchProcedure(defaultProcedureType); + } + } + + public void InitializeProcedure(ProcedureBase[] availableProcedures, Type defaultProcedureType) + { + ClearAllProcedures(); + + if (availableProcedures == null || defaultProcedureType == null) + { + return; + } + + EnsureCapacity(availableProcedures.Length); + + for (var i = 0; i < availableProcedures.Length; i++) + { + AddProcedure(availableProcedures[i]); + } + + if (TryGetProcedure(defaultProcedureType, out var defaultProcedure)) + { + _defaultProcedure = defaultProcedure; + TrySwitchProcedure(defaultProcedureType); + } + } + + public void InitializeProcedure(List availableProcedures, Type defaultProcedureType) + { + ClearAllProcedures(); + + if (availableProcedures == null || defaultProcedureType == null) + { + return; + } + + EnsureCapacity(availableProcedures.Count); + + for (var i = 0; i < availableProcedures.Count; i++) + { + AddProcedure(availableProcedures[i]); + } + + if (TryGetProcedure(defaultProcedureType, out var defaultProcedure)) + { + _defaultProcedure = defaultProcedure; + TrySwitchProcedure(defaultProcedureType); + } + } + + public void ClearAllProcedures() + { + if (_currentProcedure != null) + { + _currentProcedure.OnLeave(); + _currentProcedure = null; + } + + for (var i = 0; i < _procedureCount; i++) + { + var procedure = _orderedProcedures[i]; + if (procedure == null) + { + continue; + } + + procedure.OnDestroy(); + _orderedProcedures[i] = null; + } + + if (_types != null) + { + for (var i = 0; i < _types.Length; i++) + { + _types[i] = null; + _procedures[i] = null; + } + } + + _procedureCount = 0; + _bucketCount = 0; + _defaultProcedure = null; + } + + public bool ContainsProcedure(Type procedureType) + { + return TryGetProcedure(procedureType, out _); + } + + public bool TrySwitchProcedure(Type procedureType) + { + if (procedureType == null || _isDestroying) + { + return false; + } + + if (!TryGetProcedure(procedureType, out var nextProcedure)) + { + nextProcedure = _defaultProcedure; + } + + if (nextProcedure == null) + { + return false; + } + + if (ReferenceEquals(_currentProcedure, nextProcedure)) + { + return true; + } + + var previousProcedure = _currentProcedure; + _currentProcedure = nextProcedure; + previousProcedure?.OnLeave(); + nextProcedure.OnEnter(); + return true; + } + + public void Shutdown() + { + _isDestroying = true; + ClearAllProcedures(); + } + + private void AddProcedure(ProcedureBase procedure) + { + if (procedure == null) + { + return; + } + + var type = procedure.GetType(); + EnsureCapacity(_procedureCount + 1); + + var index = FindIndex(type); + + if (index >= 0) + { + var previousProcedure = _procedures[index]; + if (previousProcedure != null) + { + if (ReferenceEquals(_currentProcedure, previousProcedure)) + { + _currentProcedure = null; + } + + if (ReferenceEquals(_defaultProcedure, previousProcedure)) + { + _defaultProcedure = procedure; + } + + previousProcedure.OnDestroy(); + } + + _procedures[index] = procedure; + _orderedProcedures[_orderedIndices[index]] = procedure; + procedure.OnInit(); + return; + } + + var insertIndex = FindInsertIndex(type); + _types[insertIndex] = type; + _procedures[insertIndex] = procedure; + _orderedIndices[insertIndex] = _procedureCount; + _orderedProcedures[_procedureCount] = procedure; + _procedureCount++; + _bucketCount++; + procedure.OnInit(); + } + + private bool TryGetProcedure(Type procedureType, out ProcedureBase procedure) + { + var index = FindIndex(procedureType); + if (index >= 0) + { + procedure = _procedures[index]; + return true; + } + + procedure = null; + return false; + } + + private int FindIndex(Type procedureType) + { + if (procedureType == null || _types == null) + { + return -1; + } + + var mask = _types.Length - 1; + var index = procedureType.GetHashCode() & mask; + + for (var i = 0; i < _types.Length; i++) + { + var type = _types[index]; + if (type == null) + { + return -1; + } + + if (type == procedureType) + { + return index; + } + + index = (index + 1) & mask; + } + + return -1; + } + + private int FindInsertIndex(Type procedureType) + { + var mask = _types.Length - 1; + var index = procedureType.GetHashCode() & mask; + + while (_types[index] != null) + { + index = (index + 1) & mask; + } + + return index; + } + + private void EnsureCapacity(int targetCapacity) + { + if (_types != null && _orderedProcedures.Length >= targetCapacity && (_bucketCount + 1) * MaxLoadFactorDenominator < _types.Length * MaxLoadFactorNumerator) + { + return; + } + + var newProcedureCapacity = _orderedProcedures == null ? 4 : _orderedProcedures.Length; + while (newProcedureCapacity < targetCapacity) + { + newProcedureCapacity <<= 1; + } + + var newBucketCapacity = _types == null ? 8 : _types.Length; + while (targetCapacity * MaxLoadFactorDenominator >= newBucketCapacity * MaxLoadFactorNumerator) + { + newBucketCapacity <<= 1; + } + + var newTypes = new Type[newBucketCapacity]; + var newProcedures = new ProcedureBase[newBucketCapacity]; + var newOrderedIndices = new int[newBucketCapacity]; + var newOrderedProcedures = new ProcedureBase[newProcedureCapacity]; + + for (var i = 0; i < _procedureCount; i++) + { + var procedure = _orderedProcedures[i]; + var type = procedure.GetType(); + var insertIndex = FindInsertIndex(newTypes, type); + newTypes[insertIndex] = type; + newProcedures[insertIndex] = procedure; + newOrderedIndices[insertIndex] = i; + newOrderedProcedures[i] = procedure; + } + + _types = newTypes; + _procedures = newProcedures; + _orderedIndices = newOrderedIndices; + _orderedProcedures = newOrderedProcedures; + _bucketCount = _procedureCount; + } + + private static int FindInsertIndex(Type[] types, Type procedureType) + { + var mask = types.Length - 1; + var index = procedureType.GetHashCode() & mask; + + while (types[index] != null) + { + index = (index + 1) & mask; + } + + return index; + } + + private void Update() + { + _currentProcedure?.OnUpdate(); + } + + private void OnDestroy() + { + if (_runner == this) + { + _runner = null; + } + + Shutdown(); + } + } + } +} diff --git a/Runtime/Procedure/ProcedureBuilder.cs.meta b/Runtime/Procedure/ProcedureBuilder.cs.meta new file mode 100644 index 0000000..f581fc0 --- /dev/null +++ b/Runtime/Procedure/ProcedureBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6c4b9af55d3c4f53a8d9e58a45d8a2b1 +timeCreated: 1777305600 diff --git a/Runtime/Procedure/ProcedureComponent.cs b/Runtime/Procedure/ProcedureComponent.cs deleted file mode 100644 index c85efd7..0000000 --- a/Runtime/Procedure/ProcedureComponent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using UnityEngine; - -namespace AlicizaX -{ - [DisallowMultipleComponent] - [AddComponentMenu("Game Framework/Procedure")] - public sealed class ProcedureComponent : MonoBehaviour - { - private void Awake() - { - AppServices.RegisterApp(new ProcedureService()); - } - } -} - diff --git a/Runtime/Procedure/ProcedureComponent.cs.meta b/Runtime/Procedure/ProcedureComponent.cs.meta deleted file mode 100644 index dce34ef..0000000 --- a/Runtime/Procedure/ProcedureComponent.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: c0a419f3af614cdda5267671f803dfdb -timeCreated: 1763451994 \ No newline at end of file diff --git a/Runtime/Procedure/ProcedureService.cs b/Runtime/Procedure/ProcedureService.cs deleted file mode 100644 index 1cfae19..0000000 --- a/Runtime/Procedure/ProcedureService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace AlicizaX -{ - internal class ProcedureService : ServiceBase, IProcedureService, IServiceTickable - { - private readonly Dictionary _procedures = new Dictionary(); - private IProcedure _currentProcedure; - private IProcedure _defaultProcedure; - - public Type CurrentProcedureType => _currentProcedure?.GetType(); - - public void InitializeProcedure(IEnumerable availableProcedures, Type defaultProcedureType) - { - _procedures.Clear(); - foreach (var procedure in availableProcedures) - { - if (procedure == null) - { - continue; - } - - var type = procedure.GetType(); - _procedures[type] = procedure; - procedure.ProcedureService = this; - procedure.Init(); - } - - if (_procedures.TryGetValue(defaultProcedureType, out var defaultProcedure)) - { - _defaultProcedure = defaultProcedure; - TrySwitchProcedure(defaultProcedureType); - } - else - { - Log.Info($"榛樿娴佺▼ {defaultProcedureType.Name} 鏈敞鍐?"); - } - } - - public void ClearAllProcedures() - { - foreach (var procedure in _procedures.Values) - { - procedure.Destroy(); - } - - _procedures.Clear(); - _currentProcedure = null; - _defaultProcedure = null; - } - - public bool ContainsProcedure(Type procedureType) - { - return procedureType != null && _procedures.ContainsKey(procedureType); - } - - public bool TrySwitchProcedure(Type procedureType) - { - if (procedureType == null) - { - return false; - } - - if (!_procedures.TryGetValue(procedureType, out var nextProcedure)) - { - if (_defaultProcedure == null) - { - return false; - } - - Debug.LogWarning($"娴佺▼ {procedureType.Name} 涓嶅瓨鍦紝鍒囨崲鍒伴粯璁ゆ祦绋?"); - nextProcedure = _defaultProcedure; - } - - if (ReferenceEquals(_currentProcedure, nextProcedure)) - { - return true; - } - - _currentProcedure?.Leave(); - nextProcedure.Enter(); - _currentProcedure = nextProcedure; - return true; - } - - protected override void OnInitialize() - { - } - - protected override void OnDestroyService() - { - ClearAllProcedures(); - } - - void IServiceTickable.Tick(float deltaTime) - { - _currentProcedure?.Update(); - } - } -} diff --git a/Runtime/Procedure/ProcedureService.cs.meta b/Runtime/Procedure/ProcedureService.cs.meta deleted file mode 100644 index 434e607..0000000 --- a/Runtime/Procedure/ProcedureService.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 4272c5c31b6b4a459f1da37a228cfd3f -timeCreated: 1763450372 \ No newline at end of file