[Opt]轻量化Procudure模块
This commit is contained in:
parent
9afd5d9ff9
commit
bbced819dc
@ -69,26 +69,7 @@ public static partial class GameApp
|
||||
}
|
||||
|
||||
private static IObjectPoolService _objectPool;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取有限状态机组件。
|
||||
/// </summary>
|
||||
public static IProcedureService Procedure
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_procedure == null)
|
||||
{
|
||||
_procedure = AppServices.RequireApp<IProcedureService>();
|
||||
}
|
||||
|
||||
return _procedure;
|
||||
}
|
||||
}
|
||||
|
||||
private static IProcedureService _procedure;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取Asset组件。
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AlicizaX
|
||||
{
|
||||
public interface IProcedureService : IService
|
||||
{
|
||||
Type CurrentProcedureType { get; }
|
||||
void InitializeProcedure(IEnumerable<IProcedure> availableProcedures, Type defaultProcedureType);
|
||||
void ClearAllProcedures();
|
||||
bool ContainsProcedure(Type procedureType);
|
||||
bool TrySwitchProcedure(Type procedureType);
|
||||
}
|
||||
|
||||
public static class ProcedureServiceExtensions
|
||||
{
|
||||
public static bool SwitchProcedure<T>(this IProcedureService procedureService) where T : IProcedure
|
||||
{
|
||||
return procedureService.TrySwitchProcedure(typeof(T));
|
||||
}
|
||||
|
||||
public static bool SwitchProcedure(this IProcedureService procedureService, Type procedureType)
|
||||
{
|
||||
return procedureService.TrySwitchProcedure(procedureType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18d5ca3d17384612b2d2023084b6a97b
|
||||
timeCreated: 1763451617
|
||||
@ -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();
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// 流程基类 - 使用模板方法模式定义流程生命周期
|
||||
/// </summary>
|
||||
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<T>() where T : ProcedureBase
|
||||
{
|
||||
ProcedureService.SwitchProcedure<T>();
|
||||
ProcedureBuilder.SwitchProcedure<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
418
Runtime/Procedure/ProcedureBuilder.cs
Normal file
418
Runtime/Procedure/ProcedureBuilder.cs
Normal file
@ -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<ProcedureBase> availableProcedures, Type defaultProcedureType)
|
||||
{
|
||||
DestroyProcedure();
|
||||
|
||||
var gameObject = new GameObject(ProcedureRunnerName);
|
||||
UnityEngine.Object.DontDestroyOnLoad(gameObject);
|
||||
|
||||
_runner = gameObject.AddComponent<ProcedureRunner>();
|
||||
_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<ProcedureRunner>();
|
||||
_runner.InitializeProcedure(availableProcedures, defaultProcedureType);
|
||||
}
|
||||
|
||||
public static void InitializeProcedure(List<ProcedureBase> availableProcedures, Type defaultProcedureType)
|
||||
{
|
||||
DestroyProcedure();
|
||||
|
||||
var gameObject = new GameObject(ProcedureRunnerName);
|
||||
UnityEngine.Object.DontDestroyOnLoad(gameObject);
|
||||
|
||||
_runner = gameObject.AddComponent<ProcedureRunner>();
|
||||
_runner.InitializeProcedure(availableProcedures, defaultProcedureType);
|
||||
}
|
||||
|
||||
public static bool SwitchProcedure<T>() 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<T>() 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<ProcedureBase> 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<ProcedureBase> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Runtime/Procedure/ProcedureBuilder.cs.meta
Normal file
3
Runtime/Procedure/ProcedureBuilder.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c4b9af55d3c4f53a8d9e58a45d8a2b1
|
||||
timeCreated: 1777305600
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0a419f3af614cdda5267671f803dfdb
|
||||
timeCreated: 1763451994
|
||||
@ -1,102 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX
|
||||
{
|
||||
internal class ProcedureService : ServiceBase, IProcedureService, IServiceTickable
|
||||
{
|
||||
private readonly Dictionary<Type, IProcedure> _procedures = new Dictionary<Type, IProcedure>();
|
||||
private IProcedure _currentProcedure;
|
||||
private IProcedure _defaultProcedure;
|
||||
|
||||
public Type CurrentProcedureType => _currentProcedure?.GetType();
|
||||
|
||||
public void InitializeProcedure(IEnumerable<IProcedure> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4272c5c31b6b4a459f1da37a228cfd3f
|
||||
timeCreated: 1763450372
|
||||
Loading…
Reference in New Issue
Block a user