EP 实验性框架
This commit is contained in:
@@ -6,70 +6,90 @@ namespace Convention.Experimental
|
|||||||
{
|
{
|
||||||
public static class Architecture
|
public static class Architecture
|
||||||
{
|
{
|
||||||
private static readonly LinkedCacheList<GameModule> s_GameFrameworkModules = new();
|
private static readonly LinkedCacheList<object> s_GameFrameworkModules = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <20><><EFBFBD><EFBFBD><see cref="GameModule"/>
|
/// <20><><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="moduleType">Ҫ<><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><see cref="GameModule"/><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
/// <param name="instanceType">Ҫ<><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||||
/// <returns>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><see cref="GameModule"/></returns>
|
/// <returns>Ŀ<EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD></returns>
|
||||||
private static GameModule CreateModule(Type moduleType, int stackLayer = 0)
|
private static object Create(Type instanceType, int stackLayer = 0)
|
||||||
{
|
{
|
||||||
if (stackLayer >= 100)
|
if (stackLayer >= 100)
|
||||||
{
|
{
|
||||||
throw new GameException($"Create module '{moduleType.FullName}' failed, recursion too deep, there may be a circular dependency.");
|
throw new GameException($"Create instance '{instanceType.FullName}' failed, recursion too deep, there may be a circular dependency.");
|
||||||
}
|
}
|
||||||
|
|
||||||
GameModule module = (GameModule)Activator.CreateInstance(moduleType);
|
object instance = Activator.CreateInstance(instanceType);
|
||||||
if (module == null)
|
if (instance == null)
|
||||||
{
|
{
|
||||||
throw new GameException($"Can not create module '{moduleType.FullName}'");
|
throw new GameException($"Can not create instance '{instanceType.FullName}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// <20>ݹ鴴<DDB9><E9B4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3>
|
if (instance is GameModule module)
|
||||||
foreach (var dependenceType in module.Dependences())
|
|
||||||
_ = GetModule(dependenceType, stackLayer + 1);
|
|
||||||
|
|
||||||
LinkedListNode<GameModule> current = s_GameFrameworkModules.First;
|
|
||||||
while (current != null)
|
|
||||||
{
|
{
|
||||||
if (module.Priority > current.Value.Priority)
|
// <20>ݹ鴴<DDB9><E9B4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3>
|
||||||
|
foreach (var dependenceType in module.Dependences())
|
||||||
|
_ = Get(dependenceType, stackLayer + 1);
|
||||||
|
|
||||||
|
var current = s_GameFrameworkModules.First;
|
||||||
|
while (current != null)
|
||||||
{
|
{
|
||||||
break;
|
if (current.Value is GameModule nextModule && module.Priority > nextModule.Priority)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = current.Next;
|
if (current != null)
|
||||||
|
{
|
||||||
|
s_GameFrameworkModules.AddBefore(current, module);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_GameFrameworkModules.AddLast(module);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current != null)
|
return instance;
|
||||||
{
|
|
||||||
s_GameFrameworkModules.AddBefore(current, module);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_GameFrameworkModules.AddLast(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
return module;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <20><>ȡ<see cref="GameModule"/>
|
/// <20><>ȡʵ<EFBFBD><EFBFBD>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="moduleType">Ҫ<><D2AA>ȡ<EFBFBD><C8A1><see cref="GameModule"/></param>
|
/// <param name="instanceType">Ҫ<><D2AA>ȡ<EFBFBD><C8A1>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||||
/// <returns>Ҫ<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><see cref="GameModule"/></returns>
|
/// <returns>ʵ<EFBFBD><EFBFBD></returns>
|
||||||
/// <remarks><3E><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>ȡ<EFBFBD><C8A1><see cref="GameModule"/><3E><><EFBFBD><EFBFBD><EFBFBD>ڣ<EFBFBD><DAA3><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><see cref="GameModule"/>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD></remarks>
|
/// <remarks><3E><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>ȡ<EFBFBD><C8A1>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD></remarks>
|
||||||
private static GameModule GetModule(Type moduleType, int stackLayer = 0)
|
public static object Get(Type instanceType, int stackLayer = 0)
|
||||||
{
|
{
|
||||||
foreach (GameModule module in s_GameFrameworkModules)
|
foreach (object obj in s_GameFrameworkModules)
|
||||||
{
|
{
|
||||||
if (module.GetType() == moduleType)
|
if (obj.GetType() == instanceType)
|
||||||
{
|
{
|
||||||
return module;
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateModule(moduleType, stackLayer + 1);
|
return Create(instanceType, stackLayer + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Ҫ<><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||||
|
/// <returns>ʵ<><CAB5><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD></returns>
|
||||||
|
public static bool Contains(Type type)
|
||||||
|
{
|
||||||
|
foreach (object obj in s_GameFrameworkModules)
|
||||||
|
{
|
||||||
|
if (obj.GetType() == type)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -80,7 +100,7 @@ namespace Convention.Experimental
|
|||||||
/// <remarks><3E><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>ģ<EFBFBD>鲻<EFBFBD><E9B2BB><EFBFBD>ڣ<EFBFBD><DAA3><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>ģ<EFBFBD>顣</remarks>
|
/// <remarks><3E><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>ģ<EFBFBD>鲻<EFBFBD><E9B2BB><EFBFBD>ڣ<EFBFBD><DAA3><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>ģ<EFBFBD>顣</remarks>
|
||||||
public static T GetModule<T>() where T : GameModule
|
public static T GetModule<T>() where T : GameModule
|
||||||
{
|
{
|
||||||
return (T)GetModule(typeof(T));
|
return (T)Get(typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -90,7 +110,8 @@ namespace Convention.Experimental
|
|||||||
{
|
{
|
||||||
for (var current = s_GameFrameworkModules.Last; current != null; current = current.Previous)
|
for (var current = s_GameFrameworkModules.Last; current != null; current = current.Previous)
|
||||||
{
|
{
|
||||||
current.Value.Shutdown();
|
if (current.Value is GameModule module)
|
||||||
|
module.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
s_GameFrameworkModules.Clear();
|
s_GameFrameworkModules.Clear();
|
||||||
@@ -105,9 +126,10 @@ namespace Convention.Experimental
|
|||||||
/// <param name="realElapseSeconds"><3E><>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ʱ<EFBFBD>䣬<EFBFBD><E4A3AC><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>λ<EFBFBD><CEBB></param>
|
/// <param name="realElapseSeconds"><3E><>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ʱ<EFBFBD>䣬<EFBFBD><E4A3AC><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>λ<EFBFBD><CEBB></param>
|
||||||
public static void Update(float elapseSeconds, float realElapseSeconds)
|
public static void Update(float elapseSeconds, float realElapseSeconds)
|
||||||
{
|
{
|
||||||
foreach (var module in s_GameFrameworkModules)
|
foreach (object obj in s_GameFrameworkModules)
|
||||||
{
|
{
|
||||||
module.Update(elapseSeconds, realElapseSeconds);
|
if (obj is GameModule module)
|
||||||
|
module.Update(elapseSeconds, realElapseSeconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
111
Convention/[Architecture]/Modules/ActionManager.cs
Normal file
111
Convention/[Architecture]/Modules/ActionManager.cs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Convention.Experimental.Modules
|
||||||
|
{
|
||||||
|
public partial class ActionManager : PublicType.GameModule
|
||||||
|
{
|
||||||
|
public interface IActor
|
||||||
|
{
|
||||||
|
void Execute();
|
||||||
|
void Undo();
|
||||||
|
string Description { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly object m_lock = new();
|
||||||
|
private readonly LinkedList<IActor> m_history = new();
|
||||||
|
private readonly Stack<IActor> m_redoStack = new();
|
||||||
|
private int m_historyLimit = 100;
|
||||||
|
public int HistoryLimit
|
||||||
|
{
|
||||||
|
get => m_historyLimit;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_historyLimit = value;
|
||||||
|
while (m_history.Count > m_historyLimit)
|
||||||
|
{
|
||||||
|
m_history.RemoveFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanUndo => m_history.Count > 0;
|
||||||
|
|
||||||
|
public int UndoCount => m_history.Count;
|
||||||
|
|
||||||
|
public List<string> GetHistoryDescription()
|
||||||
|
{
|
||||||
|
lock (m_lock)
|
||||||
|
{
|
||||||
|
var descriptions = new List<string>();
|
||||||
|
foreach (var actor in m_history)
|
||||||
|
{
|
||||||
|
descriptions.Add(actor.Description);
|
||||||
|
}
|
||||||
|
return descriptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanRedo => m_redoStack.Count > 0;
|
||||||
|
|
||||||
|
public int RedoCount => m_redoStack.Count;
|
||||||
|
|
||||||
|
public List<string> GetRedoDescription()
|
||||||
|
{
|
||||||
|
lock (m_lock)
|
||||||
|
{
|
||||||
|
var descriptions = new List<string>();
|
||||||
|
foreach (var actor in m_redoStack)
|
||||||
|
{
|
||||||
|
descriptions.Add(actor.Description);
|
||||||
|
}
|
||||||
|
return descriptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(IActor actor)
|
||||||
|
{
|
||||||
|
lock (m_lock)
|
||||||
|
{
|
||||||
|
actor.Execute();
|
||||||
|
m_history.AddLast(actor);
|
||||||
|
m_redoStack.Clear();
|
||||||
|
if (m_history.Count > m_historyLimit)
|
||||||
|
{
|
||||||
|
m_history.RemoveFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Undo()
|
||||||
|
{
|
||||||
|
lock (m_lock)
|
||||||
|
{
|
||||||
|
if (CanUndo)
|
||||||
|
{
|
||||||
|
var actor = m_history.Last.Value;
|
||||||
|
m_history.RemoveLast();
|
||||||
|
actor.Undo();
|
||||||
|
m_redoStack.Push(actor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Redo()
|
||||||
|
{
|
||||||
|
lock (m_lock)
|
||||||
|
{
|
||||||
|
if (CanRedo)
|
||||||
|
{
|
||||||
|
var actor = m_redoStack.Pop();
|
||||||
|
actor.Execute();
|
||||||
|
m_history.AddLast(actor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,13 +5,13 @@ namespace Convention.Experimental.Modules
|
|||||||
{
|
{
|
||||||
public class ConfigManager : PublicType.GameModule
|
public class ConfigManager : PublicType.GameModule
|
||||||
{
|
{
|
||||||
public readonly ProjectConfig m_ProjectConfig = new();
|
public readonly ProjectConfig Config = new();
|
||||||
public bool IsSavePropertiesWhenShutdown = false;
|
public bool IsSavePropertiesWhenShutdown = false;
|
||||||
|
|
||||||
internal override void Shutdown()
|
internal override void Shutdown()
|
||||||
{
|
{
|
||||||
if (IsSavePropertiesWhenShutdown)
|
if (IsSavePropertiesWhenShutdown)
|
||||||
m_ProjectConfig.SaveProperties();
|
Config.SaveProperties();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +1,333 @@
|
|||||||
|
using Convention.Experimental.PublicType;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Convention.Experimental.Modules
|
namespace Convention.Experimental.Modules
|
||||||
{
|
{
|
||||||
public class ObjectPoolManager : PublicType.GameModule
|
public class GameObjectPoolManager : GameModule
|
||||||
{
|
{
|
||||||
public interface IPawn
|
/// <summary>
|
||||||
|
/// <para><3E>̳иýӿڵ<D3BF>Component<6E><74><EFBFBD>ڻ<EFBFBD><DABB>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><see cref="Release"/></para>
|
||||||
|
/// <para><b><see cref="Release"/><3E>н<EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD><see cref="Unspawn(GameObject)"/></b></para>
|
||||||
|
/// </summary>
|
||||||
|
public interface IPoolPawn
|
||||||
{
|
{
|
||||||
void Release();
|
void Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Dictionary<GameObject, Stack<GameObject>> ObjectPools = new();
|
private readonly Dictionary<GameObject, Stack<GameObject>> GameObjectPools = new();
|
||||||
private readonly Dictionary<GameObject, GameObject> LeavePoolObjects = new();
|
private readonly Dictionary<GameObject, GameObject> LeaveGameObjectPoolObjects = new();
|
||||||
|
private bool GameObjectPoolStatus = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prefab"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool Contains(GameObject prefab)
|
||||||
|
{
|
||||||
|
return GameObjectPools.ContainsKey(prefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><EFBFBD><D7B5><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="GameException"></exception>
|
||||||
|
private void EnsureSafeStatus()
|
||||||
|
{
|
||||||
|
if (GameObjectPoolStatus == false)
|
||||||
|
{
|
||||||
|
throw new GameException("GameObjectPool is busy now.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prefab"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public GameObject Spawn(GameObject prefab)
|
public GameObject Spawn(GameObject prefab)
|
||||||
{
|
{
|
||||||
if (!ObjectPools.ContainsKey(prefab))
|
EnsureSafeStatus();
|
||||||
|
lock (GameObjectPools)
|
||||||
{
|
{
|
||||||
ObjectPools[prefab] = new();
|
if (!GameObjectPools.ContainsKey(prefab))
|
||||||
|
{
|
||||||
|
GameObjectPools[prefab] = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
var pool = GameObjectPools[prefab];
|
||||||
|
GameObject instance;
|
||||||
|
if (pool.Count > 0)
|
||||||
|
{
|
||||||
|
instance = pool.Pop();
|
||||||
|
instance.SetActive(true);
|
||||||
|
instance.transform.SetParent(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instance = GameObject.Instantiate(prefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (LeaveGameObjectPoolObjects)
|
||||||
|
{
|
||||||
|
LeaveGameObjectPoolObjects[instance] = prefab;
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
var pool = ObjectPools[prefab];
|
}
|
||||||
GameObject instance;
|
|
||||||
if (pool.Count > 0)
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
/// <exception cref="PublicType.GameException"></exception>
|
||||||
|
public void Unspawn(GameObject instance)
|
||||||
|
{
|
||||||
|
EnsureSafeStatus();
|
||||||
|
lock (LeaveGameObjectPoolObjects)
|
||||||
{
|
{
|
||||||
instance = pool.Pop();
|
if (LeaveGameObjectPoolObjects.TryGetValue(instance, out var prefab))
|
||||||
instance.SetActive(true);
|
{
|
||||||
instance.transform.SetParent(null);
|
var releaser = instance.GetComponents<IPoolPawn>();
|
||||||
|
GameObjectPoolStatus = false;
|
||||||
|
foreach (var r in releaser)
|
||||||
|
{
|
||||||
|
r.Release();
|
||||||
|
}
|
||||||
|
GameObjectPoolStatus = true;
|
||||||
|
instance.SetActive(false);
|
||||||
|
instance.transform.SetParent(ConventionUtility.Singleton.transform);
|
||||||
|
lock (GameObjectPools)
|
||||||
|
{
|
||||||
|
GameObjectPools[prefab].Push(instance);
|
||||||
|
LeaveGameObjectPoolObjects.Remove(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PublicType.GameException("This object does not belong to any pool.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear(GameObject prefab)
|
||||||
|
{
|
||||||
|
EnsureSafeStatus();
|
||||||
|
lock (GameObjectPools)
|
||||||
|
{
|
||||||
|
lock (LeaveGameObjectPoolObjects)
|
||||||
|
{
|
||||||
|
// <20><><EFBFBD>ٳ<EFBFBD><D9B3>ж<EFBFBD><D0B6><EFBFBD>
|
||||||
|
if (GameObjectPools.TryGetValue(prefab, out var pool))
|
||||||
|
{
|
||||||
|
while (pool.Count > 0)
|
||||||
|
{
|
||||||
|
var instance = pool.Pop();
|
||||||
|
GameObject.Destroy(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PublicType.GameException("This pool does not exist.");
|
||||||
|
}
|
||||||
|
// <20><><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD>ն<EFBFBD><D5B6><EFBFBD>
|
||||||
|
var unbackInstances = from item in LeaveGameObjectPoolObjects
|
||||||
|
where item.Value == prefab
|
||||||
|
select item.Key;
|
||||||
|
foreach (var instance in unbackInstances)
|
||||||
|
{
|
||||||
|
LeaveGameObjectPoolObjects.Remove(instance);
|
||||||
|
}
|
||||||
|
foreach (var instance in unbackInstances)
|
||||||
|
{
|
||||||
|
GameObject.Destroy(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ObjectPoolManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para><3E>̳иýӿڵ<D3BF>Component<6E><74><EFBFBD>ڻ<EFBFBD><DABB>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><see cref="Release"/></para>
|
||||||
|
/// <para><b><see cref="Release"/><3E>н<EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD><see cref="Reclaim(object)"/></b></para>
|
||||||
|
/// </summary>
|
||||||
|
public interface IPoolPawn
|
||||||
|
{
|
||||||
|
void Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<Type, object> ObjectPools = new();
|
||||||
|
private readonly Dictionary<object, Type> LeaveObjectPoolObjects = new();
|
||||||
|
|
||||||
|
private bool GameObjectPoolStatus = true;
|
||||||
|
private void EnsureSafeStatus()
|
||||||
|
{
|
||||||
|
if (GameObjectPoolStatus == false)
|
||||||
|
{
|
||||||
|
throw new GameException("ObjectPool is busy now.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(Type type)
|
||||||
|
{
|
||||||
|
return ObjectPools.ContainsKey(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains<T>() where T : class, new()
|
||||||
|
{
|
||||||
|
return ObjectPools.ContainsKey(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><F3B5BDB6><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||||
|
/// <param name="value">ʵ<><CAB5></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="GameException"></exception>
|
||||||
|
public object Insert(Type type, object value)
|
||||||
|
{
|
||||||
|
if(LeaveObjectPoolObjects.ContainsKey(value))
|
||||||
|
{
|
||||||
|
throw new PublicType.GameException("This object is already registered in pool");
|
||||||
|
}
|
||||||
|
if (!ObjectPools.ContainsKey(type))
|
||||||
|
{
|
||||||
|
ObjectPools[type] = Utility.CreateStack(type);
|
||||||
|
}
|
||||||
|
var pool = ObjectPools[type];
|
||||||
|
var methodInfo = pool.GetType().GetMethod("Push");
|
||||||
|
methodInfo.Invoke(pool, new object[] { value });
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F3B2A2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></typeparam>
|
||||||
|
/// <param name="value">ʵ<><CAB5></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="PublicType.GameException"></exception>
|
||||||
|
public T Insert<T>(T value) where T : class
|
||||||
|
{
|
||||||
|
if(LeaveObjectPoolObjects.ContainsKey(value))
|
||||||
|
{
|
||||||
|
throw new PublicType.GameException("This object is already registered in pool");
|
||||||
|
}
|
||||||
|
var type = typeof(T);
|
||||||
|
if (!ObjectPools.ContainsKey(type))
|
||||||
|
{
|
||||||
|
ObjectPools[type] = new Stack<T>();
|
||||||
|
}
|
||||||
|
var pool = (Stack<T>)ObjectPools[type];
|
||||||
|
pool.Push(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F3B2A2B7><EFBFBD>ʵ<EFBFBD><CAB5>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public object Summon(Type type)
|
||||||
|
{
|
||||||
|
if (!ObjectPools.ContainsKey(type))
|
||||||
|
{
|
||||||
|
ObjectPools[type] = Utility.CreateStack(type);
|
||||||
|
}
|
||||||
|
var pool = ObjectPools[type];
|
||||||
|
var methodInfo = pool.GetType().GetMethod("Pop");
|
||||||
|
object instance;
|
||||||
|
var countProperty = pool.GetType().GetProperty("Count");
|
||||||
|
var count = (int)countProperty.GetValue(pool);
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
instance = methodInfo.Invoke(pool, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
instance = GameObject.Instantiate(prefab);
|
instance = Activator.CreateInstance(type);
|
||||||
}
|
}
|
||||||
LeavePoolObjects[instance] = prefab;
|
LeaveObjectPoolObjects[instance] = type;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BackPool(GameObject instance)
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F3B2A2B7><EFBFBD>ʵ<EFBFBD><CAB5>
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public T Summon<T>() where T : class, new()
|
||||||
{
|
{
|
||||||
if(LeavePoolObjects.TryGetValue(instance,out var prefab))
|
var type = typeof(T);
|
||||||
|
if (!ObjectPools.ContainsKey(type))
|
||||||
{
|
{
|
||||||
var releaser = instance.GetComponents<IPawn>();
|
ObjectPools[type] = new Stack<T>();
|
||||||
foreach (var r in releaser)
|
}
|
||||||
{
|
var pool = (Stack<T>)ObjectPools[type];
|
||||||
r.Release();
|
T instance;
|
||||||
}
|
if (pool.Count > 0)
|
||||||
instance.SetActive(false);
|
{
|
||||||
instance.transform.SetParent(ConventionUtility.Singleton.transform);
|
instance = pool.Pop();
|
||||||
ObjectPools[prefab].Push(instance);
|
|
||||||
LeavePoolObjects.Remove(instance);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PublicType.GameException("This object does not belong to any pool.");
|
instance = new T();
|
||||||
|
}
|
||||||
|
LeaveObjectPoolObjects[instance] = type;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD>ն<EFBFBD><D5B6><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">ʵ<><CAB5></param>
|
||||||
|
/// <exception cref="PublicType.GameException"></exception>
|
||||||
|
public void Reclaim(object instance)
|
||||||
|
{
|
||||||
|
if (LeaveObjectPoolObjects.TryGetValue(instance, out var objType))
|
||||||
|
{
|
||||||
|
var pool = ObjectPools[objType];
|
||||||
|
var methodInfo = pool.GetType().GetMethod("Push");
|
||||||
|
if(instance is IPoolPawn pawn)
|
||||||
|
{
|
||||||
|
pawn.Release();
|
||||||
|
}
|
||||||
|
methodInfo.Invoke(pool, new object[] { instance });
|
||||||
|
LeaveObjectPoolObjects.Remove(instance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new GameException("This object does not belong to any pool.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearPool(GameObject prefab)
|
public void Clear(Type type)
|
||||||
{
|
{
|
||||||
if (ObjectPools.TryGetValue(prefab, out var pool))
|
if (ObjectPools.TryGetValue(type, out var pool))
|
||||||
{
|
{
|
||||||
while (pool.Count > 0)
|
var clearMethod = pool.GetType().GetMethod("Clear");
|
||||||
{
|
clearMethod.Invoke(pool, null);
|
||||||
var instance = pool.Pop();
|
}
|
||||||
GameObject.Destroy(instance);
|
else
|
||||||
}
|
{
|
||||||
|
throw new PublicType.GameException("This pool does not exist.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear<T>() where T : class, new()
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
if (ObjectPools.TryGetValue(type, out var pool))
|
||||||
|
{
|
||||||
|
var clearMethod = pool.GetType().GetMethod("Clear");
|
||||||
|
clearMethod.Invoke(pool, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2475,7 +2475,62 @@ namespace Convention
|
|||||||
|
|
||||||
namespace Convention
|
namespace Convention
|
||||||
{
|
{
|
||||||
public static partial class ConventionUtility
|
public static partial class Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 生成期望类型的栈实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">期望类型</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object CreateStack([In] Type type)
|
||||||
|
{
|
||||||
|
var stackType = typeof(Stack<>).MakeGenericType(type);
|
||||||
|
var stackInstance = Activator.CreateInstance(stackType);
|
||||||
|
return stackInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成期望类型的队列实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">期望类型</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object CreateQueue([In] Type type)
|
||||||
|
{
|
||||||
|
var queueType = typeof(Queue<>).MakeGenericType(type);
|
||||||
|
var queueInstance = Activator.CreateInstance(queueType);
|
||||||
|
return queueInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成期望类型的列表实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">期望类型</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object CreateList([In] Type type)
|
||||||
|
{
|
||||||
|
var listType = typeof(List<>).MakeGenericType(type);
|
||||||
|
var listInstance = Activator.CreateInstance(listType);
|
||||||
|
return listInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成期望键值对类型的字典实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keyType">期望键类型</param>
|
||||||
|
/// <param name="valueType">期望值类型</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object CreateDictionary([In] Type keyType, [In] Type valueType)
|
||||||
|
{
|
||||||
|
var dictType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
|
||||||
|
var dictInstance = Activator.CreateInstance(dictType);
|
||||||
|
return dictInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Convention.Collections
|
||||||
|
{
|
||||||
|
namespace Generic
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user