From e3a47393f4c5b7b6c340da9ace84003d1bc14b3b Mon Sep 17 00:00:00 2001
From: ALEXTANG <574809918@qq.com>
Date: Tue, 5 Sep 2023 14:35:19 +0800
Subject: [PATCH] =?UTF-8?q?[+]=20=E6=96=B0=E5=A2=9E=E6=B8=B8=E6=88=8F?=
=?UTF-8?q?=E7=89=A9=E4=BD=93=E7=BC=93=E5=AD=98=E6=B1=A0ResourcePool?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[+] 新增游戏物体缓存池ResourcePool
---
.../Runtime/GameFramework/Resource/Pool.meta | 3 +
.../Resource/Pool/CreatePoolOperation.cs | 70 +++++
.../Resource/Pool/CreatePoolOperation.cs.meta | 3 +
.../Resource/Pool/GameObjectPool.cs | 234 ++++++++++++++++
.../Resource/Pool/GameObjectPool.cs.meta | 3 +
.../Resource/Pool/ResourcePool.cs | 253 +++++++++++++++++
.../Resource/Pool/ResourcePool.cs.meta | 3 +
.../Resource/Pool/SpawnHandle.cs | 152 ++++++++++
.../Resource/Pool/SpawnHandle.cs.meta | 3 +
.../GameFramework/Resource/Pool/Spawner.cs | 262 ++++++++++++++++++
.../Resource/Pool/Spawner.cs.meta | 3 +
.../GameFramework/Resource/ResourceManager.cs | 112 ++++----
12 files changed, 1053 insertions(+), 48 deletions(-)
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool.meta
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs.meta
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs.meta
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs.meta
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs.meta
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs
create mode 100644 Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs.meta
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool.meta b/Assets/TEngine/Runtime/GameFramework/Resource/Pool.meta
new file mode 100644
index 00000000..ce80b4ec
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 62c8f710f3264758a89eaefc4ae88921
+timeCreated: 1693831262
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs
new file mode 100644
index 00000000..00328027
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs
@@ -0,0 +1,70 @@
+using YooAsset;
+
+namespace TEngine
+{
+ public class CreatePoolOperation : GameAsyncOperation
+ {
+ private enum ESteps
+ {
+ None,
+ Waiting,
+ Done,
+ }
+
+ private readonly AssetOperationHandle _handle;
+ private ESteps _steps = ESteps.None;
+
+ internal CreatePoolOperation(AssetOperationHandle handle)
+ {
+ _handle = handle;
+ }
+ protected override void OnStart()
+ {
+ _steps = ESteps.Waiting;
+ }
+ protected override void OnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.Waiting)
+ {
+ if (_handle.IsValid == false)
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = $"{nameof(AssetOperationHandle)} is invalid.";
+ return;
+ }
+
+ if (_handle.IsDone == false)
+ return;
+
+ if (_handle.AssetObject == null)
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = $"{nameof(AssetOperationHandle.AssetObject)} is null.";
+ return;
+ }
+
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Succeed;
+ }
+ }
+
+ ///
+ /// 等待异步实例化结束。
+ ///
+ public void WaitForAsyncComplete()
+ {
+ if (_handle != null)
+ {
+ if (_steps == ESteps.Done)
+ return;
+ _handle.WaitForAsyncComplete();
+ OnUpdate();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs.meta b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs.meta
new file mode 100644
index 00000000..dada4ead
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/CreatePoolOperation.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 4e1853e7ff624c639fba990079beeee5
+timeCreated: 1693831296
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs
new file mode 100644
index 00000000..aecf11bf
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs
@@ -0,0 +1,234 @@
+using System.Collections.Generic;
+using UnityEngine;
+using YooAsset;
+
+namespace TEngine
+{
+ ///
+ /// 游戏物体对象池。
+ ///
+ internal class GameObjectPool
+ {
+ private readonly GameObject _root;
+ private readonly Queue _cacheOperations;
+ private readonly bool _dontDestroy;
+ private readonly int _initCapacity;
+ private readonly int _maxCapacity;
+ private readonly float _destroyTime;
+ private float _lastRestoreRealTime = -1f;
+
+ ///
+ /// 资源句柄。
+ ///
+ public AssetOperationHandle AssetHandle { private set; get; }
+
+ ///
+ /// 资源定位地址。
+ ///
+ public string Location { private set; get; }
+
+ ///
+ /// 内部缓存总数。
+ ///
+ public int CacheCount => _cacheOperations.Count;
+
+ ///
+ /// 外部使用总数。
+ ///
+ public int SpawnCount { private set; get; } = 0;
+
+ ///
+ /// 是否常驻不销毁。
+ ///
+ public bool DontDestroy => _dontDestroy;
+
+ ///
+ /// 游戏物体对象池。
+ ///
+ /// 对象池根节点。
+ /// 资源定位地址。
+ /// 是否常驻不销毁。
+ /// 初始容量。
+ /// 最大容量。
+ /// 对象池销毁时间。
+ public GameObjectPool(GameObject poolingRoot, string location, bool dontDestroy, int initCapacity, int maxCapacity, float destroyTime)
+ {
+ _root = new GameObject(location);
+ _root.transform.parent = poolingRoot.transform;
+ Location = location;
+
+ _dontDestroy = dontDestroy;
+ _initCapacity = initCapacity;
+ _maxCapacity = maxCapacity;
+ _destroyTime = destroyTime;
+
+ // 创建缓存池
+ _cacheOperations = new Queue(initCapacity);
+ }
+
+ ///
+ /// 创建对象池。
+ ///
+ /// 资源包。
+ public void CreatePool(ResourcePackage package)
+ {
+ // 加载游戏对象
+ AssetHandle = package.LoadAssetAsync(Location);
+
+ // 创建初始对象
+ for (int i = 0; i < _initCapacity; i++)
+ {
+ var operation = AssetHandle.InstantiateAsync(_root.transform);
+ operation.Completed += Operation_Completed;
+ _cacheOperations.Enqueue(operation);
+ }
+ }
+ private void Operation_Completed(AsyncOperationBase obj)
+ {
+ if (obj.Status == EOperationStatus.Succeed)
+ {
+ var op = obj as InstantiateOperation;
+ if (op.Result != null)
+ op.Result.SetActive(false);
+ }
+ }
+
+ ///
+ /// 销毁游戏对象池。
+ ///
+ public void DestroyPool()
+ {
+ // 卸载资源对象
+ AssetHandle.Release();
+ AssetHandle = null;
+
+ // 销毁游戏对象
+ Object.Destroy(_root);
+ _cacheOperations.Clear();
+
+ SpawnCount = 0;
+ }
+
+ ///
+ /// 查询静默时间内是否可以销毁。
+ ///
+ public bool CanAutoDestroy()
+ {
+ if (_dontDestroy)
+ return false;
+ if (_destroyTime < 0)
+ return false;
+
+ if (_lastRestoreRealTime > 0 && SpawnCount <= 0)
+ return (Time.realtimeSinceStartup - _lastRestoreRealTime) > _destroyTime;
+ else
+ return false;
+ }
+
+ ///
+ /// 游戏对象池是否已经销毁。
+ ///
+ public bool IsDestroyed()
+ {
+ return AssetHandle == null;
+ }
+
+ ///
+ /// 回收操作。
+ ///
+ /// 资源实例化操作句柄。
+ public void Restore(InstantiateOperation operation)
+ {
+ if (IsDestroyed())
+ {
+ DestroyInstantiateOperation(operation);
+ return;
+ }
+
+ SpawnCount--;
+ if (SpawnCount <= 0)
+ _lastRestoreRealTime = Time.realtimeSinceStartup;
+
+ // 如果外部逻辑销毁了游戏对象
+ if (operation.Status == EOperationStatus.Succeed)
+ {
+ if (operation.Result == null)
+ return;
+ }
+
+ // 如果缓存池还未满员
+ if (_cacheOperations.Count < _maxCapacity)
+ {
+ SetRestoreGameObject(operation.Result);
+ _cacheOperations.Enqueue(operation);
+ }
+ else
+ {
+ DestroyInstantiateOperation(operation);
+ }
+ }
+
+ ///
+ /// 丢弃操作。
+ ///
+ /// 资源实例化操作句柄。
+ public void Discard(InstantiateOperation operation)
+ {
+ if (IsDestroyed())
+ {
+ DestroyInstantiateOperation(operation);
+ return;
+ }
+
+ SpawnCount--;
+ if (SpawnCount <= 0)
+ _lastRestoreRealTime = Time.realtimeSinceStartup;
+
+ DestroyInstantiateOperation(operation);
+ }
+
+ ///
+ /// 获取一个游戏对象。
+ ///
+ /// 父节点位置。
+ /// 位置。
+ /// 旋转。
+ /// 是否强制克隆。
+ /// 用户自定义数据。
+ /// Spawn操作句柄。
+ public SpawnHandle Spawn(Transform parent, Vector3 position, Quaternion rotation, bool forceClone, params System.Object[] userDatas)
+ {
+ InstantiateOperation operation;
+ if (forceClone == false && _cacheOperations.Count > 0)
+ operation = _cacheOperations.Dequeue();
+ else
+ operation = AssetHandle.InstantiateAsync();
+
+ SpawnCount++;
+ SpawnHandle handle = new SpawnHandle(this, operation, parent, position, rotation, userDatas);
+ YooAssets.StartOperation(handle);
+ return handle;
+ }
+
+ private void DestroyInstantiateOperation(InstantiateOperation operation)
+ {
+ // 取消异步操作
+ operation.Cancel();
+
+ // 销毁游戏对象
+ if (operation.Result != null)
+ {
+ Object.Destroy(operation.Result);
+ }
+ }
+ private void SetRestoreGameObject(GameObject gameObj)
+ {
+ if (gameObj != null)
+ {
+ gameObj.SetActive(false);
+ gameObj.transform.SetParent(_root.transform);
+ gameObj.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs.meta b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs.meta
new file mode 100644
index 00000000..e1ae77bb
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/GameObjectPool.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 3f0c9bab3d1243fda94ec9a08844ceee
+timeCreated: 1693831296
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs
new file mode 100644
index 00000000..5b54398b
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using YooAsset;
+
+namespace TEngine
+{
+ ///
+ /// 游戏对象池系统。
+ /// 用法 SpawnHandle handle = ResourcePool.SpawnAsync("Cube");
+ ///
+ public static class ResourcePool
+ {
+ private static bool _isInitialize = false;
+ private static readonly List Spawners = new List();
+ private static GameObject _root;
+ private static Spawner _defaultSpawner = null;
+
+ ///
+ /// 默认Package对象生成器。
+ ///
+ private static Spawner DefaultSpawner => _defaultSpawner ??= CreateSpawner();
+
+ ///
+ /// 初始化游戏对象池系统
+ ///
+ internal static void Initialize(GameObject root)
+ {
+ if (_isInitialize)
+ throw new Exception($"{nameof(ResourcePool)} is initialized !");
+
+ if (_isInitialize == false)
+ {
+ _root = root;
+ _isInitialize = true;
+ Log.Info($"{nameof(ResourcePool)} Initialize !");
+ }
+ }
+
+ ///
+ /// 销毁游戏对象池系统
+ ///
+ internal static void Destroy()
+ {
+ if (_isInitialize)
+ {
+ foreach (var spawner in Spawners)
+ {
+ spawner.Destroy();
+ }
+ Spawners.Clear();
+
+ _isInitialize = false;
+
+ Log.Debug($"{nameof(ResourcePool)} destroy all !");
+ }
+ }
+
+ ///
+ /// 更新游戏对象池系统
+ ///
+ internal static void Update()
+ {
+ if (_isInitialize)
+ {
+ foreach (var spawner in Spawners)
+ {
+ spawner.Update();
+ }
+ }
+ }
+
+ ///
+ /// 创建游戏对象生成器
+ ///
+ /// 资源包名称
+ public static Spawner CreateSpawner(string packageName = "")
+ {
+ if (string.IsNullOrEmpty(packageName))
+ {
+ packageName = GameModule.Resource.packageName;
+ }
+ // 获取资源包
+ var assetPackage = YooAssets.GetPackage(packageName);
+ if (assetPackage == null)
+ throw new Exception($"Not found asset package : {packageName}");
+
+ // 检测资源包初始化状态
+ if (assetPackage.InitializeStatus == EOperationStatus.None)
+ throw new Exception($"Asset package {packageName} not initialize !");
+ if (assetPackage.InitializeStatus == EOperationStatus.Failed)
+ throw new Exception($"Asset package {packageName} initialize failed !");
+
+ if (HasSpawner(packageName))
+ return GetSpawner(packageName);
+
+ Spawner spawner = new Spawner(_root, assetPackage);
+ Spawners.Add(spawner);
+ return spawner;
+ }
+
+ ///
+ /// 获取游戏对象生成器。
+ ///
+ /// 资源包名称。
+ public static Spawner GetSpawner(string packageName = "")
+ {
+ if (string.IsNullOrEmpty(packageName))
+ {
+ packageName = GameModule.Resource.packageName;
+ }
+ foreach (var spawner in Spawners)
+ {
+ if (spawner.PackageName == packageName)
+ return spawner;
+ }
+
+ Log.Warning($"Not found spawner : {packageName}");
+ return null;
+ }
+
+ ///
+ /// 检测游戏对象生成器是否存在。
+ ///
+ /// 资源包名称。
+ public static bool HasSpawner(string packageName = "")
+ {
+ if (string.IsNullOrEmpty(packageName))
+ {
+ packageName = GameModule.Resource.packageName;
+ }
+ foreach (var spawner in Spawners)
+ {
+ if (spawner.PackageName == packageName)
+ return true;
+ }
+ return false;
+ }
+
+ #region 操作接口
+
+ ///
+ /// 销毁所有对象池及其资源。
+ ///
+ /// 销毁所有对象池,包括常驻对象池。
+ public static void DestroyAll(bool includeAll)
+ {
+ DefaultSpawner.DestroyAll(includeAll);
+ }
+
+
+ ///
+ /// 异步创建指定资源的游戏对象池。
+ ///
+ /// 资源定位地址。
+ /// 资源常驻不销毁。
+ /// 对象池的初始容量。
+ /// 对象池的最大容量。
+ /// 静默销毁时间(注意:小于零代表不主动销毁)。
+ public static CreatePoolOperation CreateGameObjectPoolAsync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
+ {
+ return DefaultSpawner.CreateGameObjectPoolAsync(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
+ }
+
+ ///
+ /// 同步创建指定资源的游戏对象池。
+ ///
+ /// 资源定位地址。
+ /// 资源常驻不销毁。
+ /// 对象池的初始容量。
+ /// 对象池的最大容量。
+ /// 静默销毁时间(注意:小于零代表不主动销毁)。
+ public static CreatePoolOperation CreateGameObjectPoolSync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
+ {
+ return DefaultSpawner.CreateGameObjectPoolSync(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
+ }
+
+ ///
+ /// 异步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public static SpawnHandle SpawnAsync(string location, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return DefaultSpawner.SpawnAsync(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ }
+
+ ///
+ /// 异步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public static SpawnHandle SpawnAsync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return DefaultSpawner.SpawnAsync(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ }
+
+ ///
+ /// 异步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体。
+ /// 世界坐标。
+ /// 世界角度。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public static SpawnHandle SpawnAsync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return DefaultSpawner.SpawnAsync(location, parent, position, rotation, forceClone, userDatas);
+ }
+
+ ///
+ /// 同步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public static SpawnHandle SpawnSync(string location, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return DefaultSpawner.SpawnSync(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ }
+
+ ///
+ /// 同步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public static SpawnHandle SpawnSync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return DefaultSpawner.SpawnAsync(location, parent, forceClone, userDatas);
+ }
+
+ ///
+ /// 同步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体。
+ /// 世界坐标。
+ /// 世界角度。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public static SpawnHandle SpawnSync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return DefaultSpawner.SpawnSync(location,parent,position,rotation,forceClone,userDatas);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs.meta b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs.meta
new file mode 100644
index 00000000..de4fb438
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/ResourcePool.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: be208ee3e46e4243b9a68d4c7212015e
+timeCreated: 1693831058
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs
new file mode 100644
index 00000000..5fc230e0
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs
@@ -0,0 +1,152 @@
+using UnityEngine;
+using YooAsset;
+
+namespace TEngine
+{
+ public sealed class SpawnHandle : GameAsyncOperation
+ {
+ private enum ESteps
+ {
+ None,
+ Waiting,
+ Done,
+ }
+
+ private readonly GameObjectPool _pool;
+ private InstantiateOperation _operation;
+ private readonly Transform _parent;
+ private readonly Vector3 _position;
+ private readonly Quaternion _rotation;
+ private ESteps _steps = ESteps.None;
+
+ ///
+ /// 实例化的游戏对象。
+ ///
+ public GameObject GameObj
+ {
+ get
+ {
+ if (_operation == null)
+ {
+ Log.Warning("The spawn handle is invalid !");
+ return null;
+ }
+
+ return _operation.Result;
+ }
+ }
+
+ ///
+ /// 用户自定义数据集。
+ ///
+ public System.Object[] UserDatas { private set; get; }
+
+ private SpawnHandle()
+ {
+ }
+
+ internal SpawnHandle(GameObjectPool pool, InstantiateOperation operation, Transform parent, Vector3 position, Quaternion rotation,
+ params System.Object[] userDatas)
+ {
+ _pool = pool;
+ _operation = operation;
+ _parent = parent;
+ _position = position;
+ _rotation = rotation;
+ UserDatas = userDatas;
+ }
+
+ protected override void OnStart()
+ {
+ _steps = ESteps.Waiting;
+ }
+
+ protected override void OnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.Waiting)
+ {
+ if (_operation.IsDone == false)
+ return;
+
+ if (_operation.Status != EOperationStatus.Succeed)
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _operation.Error;
+ return;
+ }
+
+ if (_operation.Result == null)
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = $"Clone game object is null.";
+ return;
+ }
+
+ // 设置参数
+ _operation.Result.transform.SetParent(_parent);
+ _operation.Result.transform.SetPositionAndRotation(_position, _rotation);
+ _operation.Result.SetActive(true);
+
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Succeed;
+ }
+ }
+
+ ///
+ /// 回收对象。
+ ///
+ public void Restore()
+ {
+ if (_operation != null)
+ {
+ ClearCompletedCallback();
+ CancelHandle();
+ _pool.Restore(_operation);
+ _operation = null;
+ }
+ }
+
+ ///
+ /// 丢弃对象。
+ ///
+ public void Discard()
+ {
+ if (_operation != null)
+ {
+ ClearCompletedCallback();
+ CancelHandle();
+ _pool.Discard(_operation);
+ _operation = null;
+ }
+ }
+
+ ///
+ /// 等待异步实例化结束。
+ ///
+ public void WaitForAsyncComplete()
+ {
+ if (_operation != null)
+ {
+ if (_steps == ESteps.Done)
+ return;
+ _operation.WaitForAsyncComplete();
+ OnUpdate();
+ }
+ }
+
+ private void CancelHandle()
+ {
+ if (IsDone == false)
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = $"User cancelled !";
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs.meta b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs.meta
new file mode 100644
index 00000000..e0f0e6ec
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/SpawnHandle.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: eb2cdce8eb814f7c92c74199d065688a
+timeCreated: 1693831296
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs
new file mode 100644
index 00000000..c7754e82
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs
@@ -0,0 +1,262 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using YooAsset;
+
+namespace TEngine
+{
+ ///
+ /// 对象生成器。
+ ///
+ public class Spawner
+ {
+ private readonly List _gameObjectPools = new List(100);
+ private readonly List _removeList = new List(100);
+ private readonly GameObject _spawnerRoot;
+ private readonly ResourcePackage _package;
+
+ public string PackageName
+ {
+ get
+ {
+ return _package.PackageName;
+ }
+ }
+
+
+ private Spawner()
+ {
+ }
+ internal Spawner(GameObject poolingRoot, ResourcePackage package)
+ {
+ _spawnerRoot = new GameObject($"{package.PackageName}");
+ _spawnerRoot.transform.SetParent(poolingRoot.transform);
+ _package = package;
+ }
+
+ ///
+ /// 更新游戏对象池系统。
+ ///
+ internal void Update()
+ {
+ _removeList.Clear();
+ foreach (var pool in _gameObjectPools)
+ {
+ if (pool.CanAutoDestroy())
+ _removeList.Add(pool);
+ }
+
+ foreach (var pool in _removeList)
+ {
+ _gameObjectPools.Remove(pool);
+ pool.DestroyPool();
+ }
+ }
+
+ ///
+ /// 销毁游戏对象池系统。
+ ///
+ internal void Destroy()
+ {
+ DestroyAll(true);
+ }
+
+ ///
+ /// 销毁所有对象池及其资源。
+ ///
+ /// 销毁所有对象池,包括常驻对象池。
+ public void DestroyAll(bool includeAll)
+ {
+ if (includeAll)
+ {
+ foreach (var pool in _gameObjectPools)
+ {
+ pool.DestroyPool();
+ }
+ _gameObjectPools.Clear();
+ }
+ else
+ {
+ List removeList = new List();
+ foreach (var pool in _gameObjectPools)
+ {
+ if (pool.DontDestroy == false)
+ removeList.Add(pool);
+ }
+ foreach (var pool in removeList)
+ {
+ _gameObjectPools.Remove(pool);
+ pool.DestroyPool();
+ }
+ }
+ }
+
+
+ ///
+ /// 异步创建指定资源的游戏对象池。
+ ///
+ /// 资源定位地址。
+ /// 资源常驻不销毁。
+ /// 对象池的初始容量。
+ /// 对象池的最大容量。
+ /// 静默销毁时间(注意:小于零代表不主动销毁)。
+ public CreatePoolOperation CreateGameObjectPoolAsync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
+ {
+ return CreateGameObjectPoolInternal(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
+ }
+
+ ///
+ /// 同步创建指定资源的游戏对象池。
+ ///
+ /// 资源定位地址。
+ /// 资源常驻不销毁。
+ /// 对象池的初始容量。
+ /// 对象池的最大容量。
+ /// 静默销毁时间(注意:小于零代表不主动销毁)。
+ public CreatePoolOperation CreateGameObjectPoolSync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
+ {
+ var operation = CreateGameObjectPoolInternal(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
+ operation.WaitForAsyncComplete();
+ return operation;
+ }
+
+ ///
+ /// 创建指定资源的游戏对象池。
+ ///
+ private CreatePoolOperation CreateGameObjectPoolInternal(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
+ {
+ if (maxCapacity < initCapacity)
+ throw new Exception("The max capacity value must be greater the init capacity value.");
+
+ GameObjectPool pool = TryGetGameObjectPool(location);
+ if (pool != null)
+ {
+ Log.Warning($"GameObject pool is already existed : {location}");
+ var operation = new CreatePoolOperation(pool.AssetHandle);
+ YooAssets.StartOperation(operation);
+ return operation;
+ }
+ else
+ {
+ pool = new GameObjectPool(_spawnerRoot, location, dontDestroy, initCapacity, maxCapacity, destroyTime);
+ pool.CreatePool(_package);
+ _gameObjectPools.Add(pool);
+
+ var operation = new CreatePoolOperation(pool.AssetHandle);
+ YooAssets.StartOperation(operation);
+ return operation;
+ }
+ }
+
+
+ ///
+ /// 异步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public SpawnHandle SpawnAsync(string location, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return SpawnInternal(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ }
+
+ ///
+ /// 异步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public SpawnHandle SpawnAsync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return SpawnInternal(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ }
+
+ ///
+ /// 异步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体。
+ /// 世界坐标。
+ /// 世界角度。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public SpawnHandle SpawnAsync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
+ {
+ return SpawnInternal(location, parent, position, rotation, forceClone, userDatas);
+ }
+
+ ///
+ /// 同步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public SpawnHandle SpawnSync(string location, bool forceClone = false, params System.Object[] userDatas)
+ {
+ SpawnHandle handle = SpawnInternal(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ handle.WaitForAsyncComplete();
+ return handle;
+ }
+
+ ///
+ /// 同步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public SpawnHandle SpawnSync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
+ {
+ SpawnHandle handle = SpawnInternal(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ handle.WaitForAsyncComplete();
+ return handle;
+ }
+
+ ///
+ /// 同步实例化一个游戏对象。
+ ///
+ /// 资源定位地址。
+ /// 父物体。
+ /// 世界坐标。
+ /// 世界角度。
+ /// 强制克隆游戏对象,忽略缓存池里的对象。
+ /// 用户自定义数据。
+ public SpawnHandle SpawnSync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
+ {
+ SpawnHandle handle = SpawnInternal(location, parent, position, rotation, forceClone, userDatas);
+ handle.WaitForAsyncComplete();
+ return handle;
+ }
+
+ ///
+ /// 实例化一个游戏对象。
+ ///
+ private SpawnHandle SpawnInternal(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone, params System.Object[] userDatas)
+ {
+ var pool = TryGetGameObjectPool(location);
+ if (pool != null)
+ {
+ return pool.Spawn(parent, position, rotation, forceClone, userDatas);
+ }
+
+ // 如果不存在创建游戏对象池
+ pool = new GameObjectPool(_spawnerRoot, location, false, 0, int.MaxValue, -1f);
+ pool.CreatePool(_package);
+ _gameObjectPools.Add(pool);
+ return pool.Spawn(parent, position, rotation, forceClone, userDatas);
+ }
+
+
+ private GameObjectPool TryGetGameObjectPool(string location)
+ {
+ foreach (var pool in _gameObjectPools)
+ {
+ if (pool.Location == location)
+ return pool;
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs.meta b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs.meta
new file mode 100644
index 00000000..947f1af0
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/Pool/Spawner.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 570ac9abe8a04e77b49c42719a9fa93b
+timeCreated: 1693831272
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs b/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs
index 102d26c3..59dae045 100644
--- a/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs
+++ b/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs
@@ -9,9 +9,10 @@ namespace TEngine
///
/// 资源管理器。
///
- internal partial class ResourceManager: GameFrameworkModule,IResourceManager
+ internal partial class ResourceManager : GameFrameworkModule, IResourceManager
{
#region Propreties
+
///
/// 资源包名称。
///
@@ -21,21 +22,21 @@ namespace TEngine
/// 获取当前资源适用的游戏版本号。
///
public string ApplicableGameVersion => m_ApplicableGameVersion;
-
+
private string m_ApplicableGameVersion;
///
/// 获取当前内部资源版本号。
///
public int InternalResourceVersion => m_InternalResourceVersion;
-
+
private int m_InternalResourceVersion;
-
+
///
/// 同时下载的最大数目。
///
public int DownloadingMaxNum { get; set; }
-
+
///
/// 失败重试最大数目。
///
@@ -45,50 +46,56 @@ namespace TEngine
/// 获取资源只读区路径。
///
public string ReadOnlyPath => m_ReadOnlyPath;
-
+
private string m_ReadOnlyPath;
///
/// 获取资源读写区路径。
///
public string ReadWritePath => m_ReadWritePath;
-
+
private string m_ReadWritePath;
-
+
///
/// 资源系统运行模式。
///
public EPlayMode PlayMode { get; set; }
-
+
///
/// 下载文件校验等级。
///
public EVerifyLevel VerifyLevel { get; set; }
-
+
///
/// 设置异步系统参数,每帧执行消耗的最大时间切片(单位:毫秒)。
///
public long Milliseconds { get; set; }
-
+
///
/// 获取游戏框架模块优先级。
///
/// 优先级较高的模块会优先轮询,并且关闭操作会后进行。
internal override int Priority => 4;
+
#endregion
#region 生命周期
+
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
+ ResourcePool.Update();
}
internal override void Shutdown()
{
YooAssets.Destroy();
+ ResourcePool.Destroy();
}
+
#endregion
#region 设置接口
+
///
/// 设置资源只读区路径。
///
@@ -116,6 +123,7 @@ namespace TEngine
m_ReadWritePath = readWritePath;
}
+
#endregion
public void Initialize()
@@ -133,6 +141,7 @@ namespace TEngine
defaultPackage = YooAssets.CreatePackage(packageName);
YooAssets.SetDefaultPackage(defaultPackage);
}
+ ResourcePool.Initialize(GameModule.Resource.gameObject);
}
public InitializationOperation InitPackage()
@@ -154,7 +163,7 @@ namespace TEngine
//运行时使用。
EPlayMode playMode = PlayMode;
#endif
-
+
// 编辑器下的模拟模式
InitializationOperation initializationOperation = null;
if (playMode == EPlayMode.EditorSimulateMode)
@@ -185,7 +194,7 @@ namespace TEngine
return initializationOperation;
}
-
+
public void UnloadAsset(object asset)
{
throw new System.NotImplementedException();
@@ -207,14 +216,14 @@ namespace TEngine
{
throw new GameFrameworkException("Asset name is invalid.");
}
-
+
AssetInfo assetInfo = YooAssets.GetAssetInfo(assetName);
-
+
if (!CheckLocationValid(assetName))
{
return HasAssetResult.Valid;
}
-
+
if (assetInfo == null)
{
return HasAssetResult.NotExist;
@@ -296,6 +305,7 @@ namespace TEngine
}
#endregion
+
///
/// 同步加载资源。
///
@@ -309,6 +319,7 @@ namespace TEngine
Log.Error("Asset name is invalid.");
return default;
}
+
AssetOperationHandle handle = YooAssets.LoadAssetSync(assetName);
if (typeof(T) == typeof(GameObject))
@@ -339,6 +350,7 @@ namespace TEngine
Log.Error("Asset name is invalid.");
return default;
}
+
AssetOperationHandle handle = YooAssets.LoadAssetSync(assetName);
if (typeof(T) == typeof(GameObject))
@@ -362,7 +374,7 @@ namespace TEngine
/// 要加载资源的名称。
/// 要加载资源的类型。
/// 资源实例。
- public T LoadAsset(string assetName,out AssetOperationHandle handle) where T : Object
+ public T LoadAsset(string assetName, out AssetOperationHandle handle) where T : Object
{
handle = YooAssets.LoadAssetSync(assetName);
@@ -391,7 +403,7 @@ namespace TEngine
/// 父节点位置。
/// 要加载资源的类型。
/// 资源实例。
- public T LoadAsset(string assetName, Transform parent,out AssetOperationHandle handle) where T : Object
+ public T LoadAsset(string assetName, Transform parent, out AssetOperationHandle handle) where T : Object
{
handle = YooAssets.LoadAssetSync(assetName);
@@ -453,7 +465,7 @@ namespace TEngine
{
return YooAssets.LoadSubAssetsAsync(location: location);
}
-
+
///
/// 同步加载子资源对象
///
@@ -471,9 +483,10 @@ namespace TEngine
/// 加载完毕时是否主动激活
/// 优先级
/// 异步加载场景句柄。
- public SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100)
+ public SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true,
+ int priority = 100)
{
- return YooAssets.LoadSceneAsync(location,sceneMode,activateOnLoad,priority);
+ return YooAssets.LoadSceneAsync(location, sceneMode, activateOnLoad, priority);
}
///
@@ -484,12 +497,13 @@ namespace TEngine
/// 加载完毕时是否主动激活
/// 优先级
/// 异步加载场景句柄。
- public SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100)
+ public SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true,
+ int priority = 100)
{
- return YooAssets.LoadSceneAsync(assetInfo,sceneMode,activateOnLoad,priority);
+ return YooAssets.LoadSceneAsync(assetInfo, sceneMode, activateOnLoad, priority);
}
-
-
+
+
///
/// 异步加载资源实例。
///
@@ -499,20 +513,20 @@ namespace TEngine
public async UniTask LoadAssetAsync(string assetName, CancellationToken cancellationToken) where T : Object
{
AssetOperationHandle handle = LoadAssetAsyncHandle(assetName);
-
+
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
if (cancelOrFailed)
{
return null;
}
-
+
if (typeof(T) == typeof(GameObject))
{
GameObject ret = handle.InstantiateSync();
-
+
AssetReference.BindAssetReference(ret, handle, assetName);
-
+
return ret as T;
}
else
@@ -530,7 +544,7 @@ namespace TEngine
public async UniTask LoadGameObjectAsync(string assetName, CancellationToken cancellationToken)
{
AssetOperationHandle handle = LoadAssetAsyncHandle(assetName);
-
+
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
if (cancelOrFailed)
@@ -539,12 +553,12 @@ namespace TEngine
}
GameObject ret = handle.InstantiateSync();
-
+
AssetReference.BindAssetReference(ret, handle, assetName);
-
+
return ret;
}
-
+
///
/// 异步加载游戏物体。
///
@@ -554,7 +568,7 @@ namespace TEngine
/// 异步游戏物体实例。
public async UniTask LoadGameObjectAsync(string location, Transform parent, CancellationToken cancellationToken)
{
- GameObject gameObject = await LoadGameObjectAsync(location,cancellationToken);
+ GameObject gameObject = await LoadGameObjectAsync(location, cancellationToken);
if (parent != null)
{
gameObject.transform.SetParent(parent);
@@ -563,6 +577,7 @@ namespace TEngine
{
Log.Error("Set Parent Failed");
}
+
return gameObject;
}
@@ -575,11 +590,11 @@ namespace TEngine
public async UniTask LoadRawAssetAsync(string location, CancellationToken cancellationToken)
{
RawFileOperationHandle handle = YooAssets.LoadRawFileAsync(location);
-
+
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
handle.Dispose();
-
+
return cancelOrFailed ? null : handle;
}
@@ -591,7 +606,7 @@ namespace TEngine
/// 取消操作Token。
/// 资源实例类型。
/// 原生文件资源实例。
- public async UniTask LoadSubAssetAsync(string location,string assetName, CancellationToken cancellationToken) where T : Object
+ public async UniTask LoadSubAssetAsync(string location, string assetName, CancellationToken cancellationToken) where T : Object
{
var assetInfo = GetAssetInfo(location);
if (assetInfo == null)
@@ -599,16 +614,16 @@ namespace TEngine
Log.Fatal($"AssetsInfo is null");
return null;
}
-
+
SubAssetsOperationHandle handle = YooAssets.LoadSubAssetsAsync(assetInfo);
-
+
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
handle.Dispose();
-
+
return cancelOrFailed ? null : handle.GetSubAssetObject(assetName);
}
-
+
///
/// 异步加载子文件。
///
@@ -616,7 +631,7 @@ namespace TEngine
/// 取消操作Token。
/// 资源实例类型。
/// 原生文件资源实例。
- public async UniTask LoadAllSubAssetAsync(string location,CancellationToken cancellationToken) where T : Object
+ public async UniTask LoadAllSubAssetAsync(string location, CancellationToken cancellationToken) where T : Object
{
var assetInfo = GetAssetInfo(location);
if (assetInfo == null)
@@ -624,13 +639,13 @@ namespace TEngine
Log.Fatal($"AssetsInfo is null");
return null;
}
-
+
SubAssetsOperationHandle handle = YooAssets.LoadSubAssetsAsync(assetInfo);
-
+
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
handle.Dispose();
-
+
return cancelOrFailed ? null : handle.GetSubAssetObjects();
}
@@ -643,11 +658,12 @@ namespace TEngine
/// 加载完毕时是否主动激活.
/// 优先级.
/// 场景资源实例。
- public async UniTask LoadSceneAsyncByUniTask(string location,CancellationToken cancellationToken,LoadSceneMode sceneMode = LoadSceneMode.Single,
+ public async UniTask LoadSceneAsyncByUniTask(string location, CancellationToken cancellationToken,
+ LoadSceneMode sceneMode = LoadSceneMode.Single,
bool activateOnLoad = true, int priority = 100)
{
- SceneOperationHandle handle = YooAssets.LoadSceneAsync(location,sceneMode,activateOnLoad,priority);
-
+ SceneOperationHandle handle = YooAssets.LoadSceneAsync(location, sceneMode, activateOnLoad, priority);
+
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
return cancelOrFailed ? default : handle.SceneObject;