From 1a0e3f91e0613b10dad55f2a121834050d0f3d97 Mon Sep 17 00:00:00 2001
From: ALEXTANG <574809918@qq.com>
Date: Tue, 28 Nov 2023 15:27:34 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96/=E6=96=B0=E5=A2=9E=E8=B6=85?=
=?UTF-8?q?=E7=89=9B=E9=80=BC=E4=B8=94=E5=BE=88=E6=96=B9=E4=BE=BF=E4=BD=BF?=
=?UTF-8?q?=E7=94=A8=E7=9A=84=E5=AF=B9=E8=B1=A1=E6=B1=A0=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
优化/新增超牛逼且很方便使用的对象池。
---
.../ResourceModule/IResourceManager.cs | 11 +-
.../Pool/CreatePoolOperation.cs | 70 --
.../Pool/CreatePoolOperation.cs.meta | 3 -
.../ResourceModule/Pool/DelayDestroyGo.cs | 12 +
.../Pool/DelayDestroyGo.cs.meta | 11 +
.../ResourceModule/Pool/GameObjectPool.cs | 234 -------
.../Pool/GameObjectPool.cs.meta | 3 -
.../Modules/ResourceModule/Pool/GoPoolNode.cs | 25 +
.../ResourceModule/Pool/GoPoolNode.cs.meta | 11 +
.../Modules/ResourceModule/Pool/GoProperty.cs | 13 +
.../ResourceModule/Pool/GoProperty.cs.meta | 11 +
.../ResourceModule/Pool/ResCacheData.cs | 38 ++
.../ResourceModule/Pool/ResCacheData.cs.meta | 11 +
.../Pool/ResourceCacheConfig.cs | 25 +
.../Pool/ResourceCacheConfig.cs.meta | 3 +
.../ResourceModule/Pool/ResourceCacheMgr.cs | 294 ++++++++
.../Pool/ResourceCacheMgr.cs.meta | 11 +
.../ResourceModule/Pool/ResourcePool.cs | 645 ++++++++++++------
.../ResourceModule/Pool/ResourcePool.cs.meta | 12 +-
.../ResourceModule/Pool/SpawnHandle.cs | 152 -----
.../ResourceModule/Pool/SpawnHandle.cs.meta | 3 -
.../Modules/ResourceModule/Pool/Spawner.cs | 262 -------
.../ResourceModule/Pool/Spawner.cs.meta | 3 -
.../Modules/ResourceModule/ResourceManager.cs | 317 +++++----
.../Modules/ResourceModule/ResourceModule.cs | 12 +-
25 files changed, 1124 insertions(+), 1068 deletions(-)
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs.meta
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs.meta
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs.meta
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs.meta
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs.meta
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs.meta
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs.meta
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs
create mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs.meta
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs.meta
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs
delete mode 100644 UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs.meta
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs
index 912044ea..4c2ef5e8 100644
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs
@@ -95,6 +95,14 @@ namespace TEngine
///
/// 要卸载的资源。
void UnloadAsset(object asset);
+
+ ///
+ /// 释放游戏物体。
+ ///
+ /// 游戏物体。
+ /// 强制不入回收池。
+ /// 延迟时间。
+ void FreeGameObject(GameObject gameObject, bool forceNoPool = false, float delayTime = 0f);
///
/// 资源回收(卸载引用计数为零的资源)
@@ -282,10 +290,11 @@ namespace TEngine
/// 是否需要实例化。
/// 是否需要缓存。
/// 指定资源包的名称。不传使用默认资源包
+ /// 资源实例父节点。
/// 要加载资源的类型。
/// 异步资源实例。
UniTask LoadAssetAsync(string location, CancellationToken cancellationToken = default,
- bool needInstance = true, bool needCache = false, string packageName = "") where T : Object;
+ bool needInstance = true, bool needCache = false, string packageName = "", Transform parent = null) where T : Object;
///
/// 异步加载游戏物体。
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs
deleted file mode 100644
index 00328027..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-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/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs.meta
deleted file mode 100644
index dada4ead..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/CreatePoolOperation.cs.meta
+++ /dev/null
@@ -1,3 +0,0 @@
-fileFormatVersion: 2
-guid: 4e1853e7ff624c639fba990079beeee5
-timeCreated: 1693831296
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs
new file mode 100644
index 00000000..198580c7
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs
@@ -0,0 +1,12 @@
+using UnityEngine;
+
+namespace TEngine
+{
+ internal class DelayDestroyGo
+ {
+ public GoProperty Property;
+ public GameObject Asset;
+ public int HashId;
+ public float DestroyTime;
+ }
+}
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs.meta
new file mode 100644
index 00000000..5534ce0c
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/DelayDestroyGo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7e03aac69e9233b488725725586c612d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs
deleted file mode 100644
index aecf11bf..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs
+++ /dev/null
@@ -1,234 +0,0 @@
-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/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs.meta
deleted file mode 100644
index e1ae77bb..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GameObjectPool.cs.meta
+++ /dev/null
@@ -1,3 +0,0 @@
-fileFormatVersion: 2
-guid: 3f0c9bab3d1243fda94ec9a08844ceee
-timeCreated: 1693831296
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs
new file mode 100644
index 00000000..11f5cf4e
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace TEngine
+{
+ internal class GoPoolNode
+ {
+ public readonly List ListGameObjects = new List();
+ public int MaxCacheCnt = 10;
+ public int GoRefCnt;
+ public int MinCacheCnt;
+ public int CacheFreeTime;
+ public float PoolGoRefreshTime;
+
+ public bool AddCacheGo(GameObject go)
+ {
+ if (ListGameObjects.Count >= MaxCacheCnt)
+ {
+ return false;
+ }
+ ListGameObjects.Add(go);
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs.meta
new file mode 100644
index 00000000..090aa3a0
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoPoolNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4e42a95f042081047b9105a70252b9f0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs
new file mode 100644
index 00000000..c7c5c44d
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs
@@ -0,0 +1,13 @@
+using UnityEngine;
+
+namespace TEngine
+{
+ internal struct GoProperty
+ {
+ public string ResPath;
+ public int Layer;
+ public uint FrameID;
+ public float FrameTime;
+ public Vector3 InitScale;
+ }
+}
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs.meta
new file mode 100644
index 00000000..d5e491aa
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/GoProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c868a337f95e6ad4e94ee4ed5b0485e9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs
new file mode 100644
index 00000000..d439abab
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs
@@ -0,0 +1,38 @@
+using UnityEngine;
+
+namespace TEngine
+{
+ ///
+ /// 资源缓存数据。
+ ///
+ internal class ResCacheData : IMemory
+ {
+ ///
+ /// 资源实例。
+ ///
+ public Object Asset;
+
+ ///
+ /// 缓存刷新时间。
+ ///
+ public float CacheRefreshTime;
+
+ ///
+ /// 是否自动过期。
+ ///
+ public bool AutoExpire;
+
+ ///
+ /// 缓存过期时间。
+ ///
+ public int CacheExpireTime;
+
+ public void Clear()
+ {
+ Asset = null;
+ CacheRefreshTime = 0f;
+ AutoExpire = false;
+ CacheExpireTime = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs.meta
new file mode 100644
index 00000000..f6751cfd
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResCacheData.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e6b38fc58dc07ab4da453ee3d4d02c20
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs
new file mode 100644
index 00000000..3eca3116
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs
@@ -0,0 +1,25 @@
+namespace TEngine
+{
+ internal struct ResourceCacheConfig
+ {
+ public readonly string ResPath;
+ public readonly int CacheTime;
+ public readonly int MaxPoolCnt;
+ public readonly int PoolGoFreeTime;
+ public readonly int MinPoolCnt;
+
+ public ResourceCacheConfig(
+ string resPath,
+ int cacheTime,
+ int maxPoolCnt,
+ int poolGoFreeTime,
+ int minPoolCnt)
+ {
+ ResPath = resPath;
+ CacheTime = cacheTime;
+ MaxPoolCnt = maxPoolCnt;
+ PoolGoFreeTime = poolGoFreeTime;
+ MinPoolCnt = minPoolCnt;
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs.meta
new file mode 100644
index 00000000..365c56b6
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheConfig.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5100cbca9f2a42ecb050957a3552d43a
+timeCreated: 1701085446
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs
new file mode 100644
index 00000000..c1e49f3c
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs
@@ -0,0 +1,294 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using YooAsset;
+using Object = UnityEngine.Object;
+
+namespace TEngine
+{
+ public class ResourceCacheMgr
+ {
+ private static ResourceCacheMgr _instance;
+
+ public static ResourceCacheMgr Instance => _instance ??= new ResourceCacheMgr();
+
+ private readonly Dictionary _cachePool = new Dictionary();
+ private readonly Dictionary _persistCachePool = new Dictionary();
+ private bool _enableLog = true;
+ private readonly List _needCacheResList = new List();
+ private readonly List _needPersistResList = new List();
+ private GameTimerTick _tickCheckExpire;
+ private readonly List _listToDel = new List();
+ private bool _pauseCache;
+
+ public int PersistCachePoolCount = 30;
+
+ public bool PauseCache
+ {
+ set => _pauseCache = value;
+ get => _pauseCache;
+ }
+
+ internal Dictionary CachePoolAllData => _cachePool;
+
+ internal Dictionary PersistPoolAllData => _persistCachePool;
+
+ public int CacheCount => _cachePool.Count;
+
+ public int PersistCount => _persistCachePool.Count;
+
+ public void SetLogEnable(bool enable) => _enableLog = enable;
+
+ ///
+ /// 注册持久化的资源。
+ ///
+ /// 持久化的资源起始路径。存在这个路径开始的资源不会释放。
+ public void RegPersistResPath(List resList) => _needPersistResList.AddRange((IEnumerable)resList);
+
+ ///
+ /// 注册缓存池的资源。
+ ///
+ /// 缓存池的资源起始路径。存在这个路径开始的资源则加入对象池。
+ /// 缓存时间。
+ /// 缓存池最大容量。
+ /// 缓存池释放时间。
+ /// 缓存池最小容量。
+ /// ResourceCacheMgr.Instance.RegCacheResPath("Assets/AssetRaw/Effects"); 所有特效相关资源都加入对象池。
+ public void RegCacheResPath(
+ string resPath,
+ int cacheTime = 0,
+ int maxPoolCnt = 30,
+ int poolGoFreeTime = 120,
+ int minPoolCnt = 0)
+ {
+ _needCacheResList.Add(new ResourceCacheConfig(resPath, cacheTime, maxPoolCnt, poolGoFreeTime, minPoolCnt));
+ }
+
+ public void RefreshCacheTime(string resPath)
+ {
+ if (!_cachePool.TryGetValue(resPath, out ResCacheData resCacheData))
+ {
+ return;
+ }
+ resCacheData.CacheRefreshTime = Time.time;
+ }
+
+ public bool IsResourceCached(string resPath)
+ {
+ string key = resPath;
+ return _cachePool.ContainsKey(key) || _persistCachePool.ContainsKey(key);
+ }
+
+ public Object GetCacheDataByLocation(string location)
+ {
+ AssetInfo assetInfo = GameModule.Resource.GetAssetInfo(location);
+ return GetCacheData(assetInfo.AssetPath);
+ }
+
+ public Object GetCacheData(string resPath)
+ {
+ string key = resPath;
+ if (_cachePool.TryGetValue(key, out ResCacheData resCacheData))
+ {
+ resCacheData.CacheRefreshTime = Time.time;
+ return resCacheData.Asset;
+ }
+ else if (_persistCachePool.TryGetValue(key, out resCacheData))
+ {
+ resCacheData.CacheRefreshTime = Time.time;
+ return resCacheData.Asset;
+ }
+ return null;
+ }
+
+ public int GetMaxGoPoolCnt(string resPath)
+ {
+ return IsNeedCache(resPath, out int _, out var maxPoolCnt) ? maxPoolCnt : 0;
+ }
+
+ public bool GetCacheCfg(
+ string resPath,
+ out int maxPoolCnt,
+ out int cacheFreeTime,
+ out int minPoolCnt)
+ {
+ return IsNeedCache(resPath, out int _, out maxPoolCnt, out cacheFreeTime, out minPoolCnt);
+ }
+
+ public bool IsNeedCache(string resPath, out int cacheTime)
+ {
+ return IsNeedCache(resPath, out cacheTime, out _);
+ }
+
+ public bool IsNeedCache(string resPath, out int cacheTime, out int maxPoolCnt)
+ {
+ return IsNeedCache(resPath, out cacheTime, out maxPoolCnt, out _, out _);
+ }
+
+ public bool IsNeedCache(
+ string resPath,
+ out int cacheTime,
+ out int maxPoolCnt,
+ out int poolGoFreeTime,
+ out int minPoolCnt)
+ {
+ cacheTime = 0;
+ maxPoolCnt = 0;
+ poolGoFreeTime = 0;
+ minPoolCnt = 0;
+ foreach (var needCacheRes in _needCacheResList)
+ {
+ if (resPath.StartsWith(needCacheRes.ResPath))
+ {
+ cacheTime = needCacheRes.CacheTime;
+ maxPoolCnt = needCacheRes.MaxPoolCnt;
+ poolGoFreeTime = needCacheRes.PoolGoFreeTime;
+ minPoolCnt = needCacheRes.MinPoolCnt;
+ return true;
+ }
+ }
+
+ if (!IsNeedPersist(resPath))
+ {
+ return false;
+ }
+ cacheTime = 0;
+ maxPoolCnt = PersistCachePoolCount;
+ poolGoFreeTime = 0;
+ minPoolCnt = 0;
+ return true;
+ }
+
+ public bool IsNeedPersist(string resPath)
+ {
+ foreach (var persistKey in _needPersistResList)
+ {
+ if (resPath.IndexOf(persistKey, StringComparison.Ordinal) >= 0)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public List GetAllPersistCache()
+ {
+ List allPersistCache = new List();
+ using Dictionary.Enumerator enumerator = _persistCachePool.GetEnumerator();
+ while (enumerator.MoveNext())
+ {
+ allPersistCache.Add(enumerator.Current.Key);
+ }
+ return allPersistCache;
+ }
+
+ public bool AddCache(
+ string resPath,
+ Object obj,
+ int cacheTime,
+ bool forcePersist = false)
+ {
+ if (null == obj)
+ {
+ Log.Info("add cache failed, resPath: {0}", resPath);
+ return false;
+ }
+
+ bool flag = IsNeedPersist(resPath) || forcePersist;
+ string str = resPath;
+ if (_persistCachePool.ContainsKey(str))
+ {
+ return true;
+ }
+ if (_cachePool.TryGetValue(str, out ResCacheData resCacheData1))
+ {
+ if (flag)
+ {
+ _cachePool.Remove(str);
+ _persistCachePool.Add(str, resCacheData1);
+ }
+
+ return true;
+ }
+
+ if (PauseCache)
+ {
+ return true;
+ }
+ ResCacheData resCacheData2 = MemoryPool.Acquire();
+ resCacheData2.Asset = obj;
+ resCacheData2.AutoExpire = false;
+ resCacheData2.CacheRefreshTime = Time.time;
+ resCacheData2.CacheExpireTime = cacheTime;
+ if (cacheTime > 0)
+ {
+ resCacheData2.AutoExpire = true;
+ }
+ if (flag)
+ {
+ _persistCachePool.Add(str, resCacheData2);
+ }
+ else
+ {
+ _cachePool.Add(str, resCacheData2);
+ }
+
+ return true;
+ }
+
+ public void RemoveAllCache() => _cachePool.Clear();
+
+ public void RemoveCache(string resPath)
+ {
+ if (!_cachePool.TryGetValue(resPath,out ResCacheData resCacheData))
+ {
+ return;
+ }
+ MemoryPool.Release(resCacheData);
+ _cachePool.Remove(resPath);
+ }
+
+ public int GetCacheCount() => _cachePool.Count + _persistCachePool.Count;
+
+ internal void Init() => _tickCheckExpire = new GameTimerTick(1f,CheckExpireCache);
+
+ internal void OnUpdate() => _tickCheckExpire.OnUpdate();
+
+ private void CheckExpireCache()
+ {
+ float time = Time.time;
+ ResourcePool instance = ResourcePool.Instance;
+ using Dictionary.Enumerator enumerator = _cachePool.GetEnumerator();
+ while (enumerator.MoveNext())
+ {
+ KeyValuePair current = enumerator.Current;
+ string key1 = current.Key;
+ current = enumerator.Current;
+ ResCacheData resCacheData = current.Value;
+ if (resCacheData.AutoExpire && resCacheData.CacheRefreshTime + resCacheData.CacheExpireTime < time)
+ {
+ if (resCacheData.Asset is GameObject && !instance.IsNeedAutoFree(key1))
+ {
+ resCacheData.CacheRefreshTime = Time.time;
+ }
+ else
+ {
+ List listToDel = _listToDel;
+ current = enumerator.Current;
+ string key2 = current.Key;
+ listToDel.Add(key2);
+ }
+ }
+ }
+
+ foreach (var resPath in _listToDel)
+ {
+ MemoryPool.Release(_cachePool[resPath]);
+ _cachePool.Remove(resPath);
+ ResourcePool.Instance.FreeGoByResPath(resPath);
+ }
+
+ _listToDel.Clear();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs.meta
new file mode 100644
index 00000000..49dd7400
--- /dev/null
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourceCacheMgr.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8e211ca9bbc0ef74ca63508c6b10c380
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs
index 4294045a..49cdbf17 100644
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs
@@ -1,261 +1,512 @@
-using System;
+#region Class Documentation
+/************************************************************************************************************
+Class Name: ResourcePool对象池。
+Type: Util, Singleton
+
+Example:
+ //注册 - 添加对象池路径,满足这个路径开头的GameObject开启对象池:
+ ResourceCacheMgr.Instance.RegCacheResPath("Assets/AssetRaw/Effects");
+
+ //正常引用资源。
+ var obj = await GameModule.Resource.LoadAssetAsync("Sprite",parent:transform);
+
+ //回收资源
+ GameModule.Resource.FreeGameObject(obj);
+
+ //删除资源 放心资源不存在泄露。
+ Unity Engine.Object。Destroy(obj);
+************************************************************************************************************/
+#endregion
+
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace TEngine
{
- ///
- /// 游戏对象池系统。
- /// 用法 SpawnHandle handle = ResourcePool.SpawnAsync("Cube");
- ///
- public static class ResourcePool
+ internal class ResourcePool
{
- private static bool _isInitialize = false;
- private static readonly List Spawners = new List();
- private static GameObject _root;
- private static Spawner _defaultSpawner = null;
+ private static ResourcePool _instance;
- ///
- /// 默认Package对象生成器。
- ///
- private static Spawner DefaultSpawner => _defaultSpawner ??= CreateSpawner();
+ internal static ResourcePool Instance => _instance ??= new ResourcePool();
- ///
- /// 初始化游戏对象池系统
- ///
- internal static void Initialize(GameObject root)
+ private readonly Dictionary _cacheGo = new Dictionary();
+ private readonly Dictionary _goProperty = new Dictionary();
+ private readonly List _delayDestroyList = new List();
+ private readonly List _freeDelayNode = new List();
+ private readonly List _listToDelete = new List();
+ private Transform _poolRootTrans;
+ private uint _frameID = 1;
+ private float _frameTime;
+ private float _tickLogTime;
+ private bool _pauseGoPool;
+ private int _totalPoolObjectCount;
+ public bool LogWhenPoolFull = true;
+
+ public bool PoolCacheFreeEnable = true;
+
+ public int TotalPoolObjectCount => _totalPoolObjectCount;
+
+ public int DelayDestroyCount => _delayDestroyList.Count;
+
+ public int FreedDestroyCount => _freeDelayNode.Count;
+
+ public static float PoolWaitReuseTime = 0.2f;
+
+ public bool PauseGoPool
{
- if (_isInitialize)
- throw new Exception($"{nameof(ResourcePool)} is initialized !");
-
- if (_isInitialize == false)
- {
- _root = root;
- _isInitialize = true;
- Log.Info($"{nameof(ResourcePool)} Initialize !");
- }
+ set => _pauseGoPool = value;
+ get => _pauseGoPool;
}
- ///
- /// 销毁游戏对象池系统
- ///
- internal static void Destroy()
+ public void OnAwake()
{
- if (_isInitialize)
+ GetRootTrans();
+ ResourceCacheMgr.Instance.Init();
+ }
+
+ private Transform GetRootTrans()
+ {
+ if (!Application.isPlaying)
{
- foreach (var spawner in Spawners)
+ return null;
+ }
+
+ if (_poolRootTrans != null)
+ {
+ return _poolRootTrans;
+ }
+
+ GameObject target = new GameObject("_GO_POOL_ROOT");
+ Object.DontDestroyOnLoad(target);
+ _poolRootTrans = target.transform;
+ return _poolRootTrans;
+ }
+
+ public void OnDestroy()
+ {
+ FreeAllCacheAndGo();
+ }
+
+ public void AddCacheGo(string resPath, GameObject go)
+ {
+ GoProperty property;
+ property.ResPath = resPath;
+ property.Layer = go.layer;
+ property.FrameID = _frameID;
+ property.FrameTime = _frameTime;
+ property.InitScale = go.transform.localScale;
+ AddCacheGo(resPath, go, property);
+ }
+
+ private DelayDestroyGo AllocDelayNode()
+ {
+ if (_freeDelayNode.Count <= 0)
+ {
+ return new DelayDestroyGo();
+ }
+ int index = _freeDelayNode.Count - 1;
+ DelayDestroyGo delayDestroyGo = _freeDelayNode[index];
+ _freeDelayNode.RemoveAt(index);
+ return delayDestroyGo;
+ }
+
+ private void FreeDelayNode(DelayDestroyGo node) => _freeDelayNode.Add(node);
+
+ public void DelayDestroy(GameObject go, GoProperty property, float delayTime)
+ {
+ if (delayTime <= 1.0 / 1000.0)
+ {
+ AddCacheGo(property.ResPath, go, property);
+ }
+ else
+ {
+ DelayDestroyGo delayDestroyGo = AllocDelayNode();
+ delayDestroyGo.Asset = go;
+ delayDestroyGo.HashId = go.GetHashCode();
+ delayDestroyGo.Property = property;
+ float num = Time.time + delayTime;
+ delayDestroyGo.DestroyTime = num;
+ int index1 = -1;
+ for (int index2 = 0; index2 < _delayDestroyList.Count; ++index2)
{
- spawner.Destroy();
+ if (_delayDestroyList[index2].DestroyTime >= num)
+ {
+ index1 = index2;
+ break;
+ }
}
- Spawners.Clear();
-
- _isInitialize = false;
-
- Log.Info($"{nameof(ResourcePool)} destroy all !");
- }
- }
-
- ///
- /// 更新游戏对象池系统
- ///
- internal static void Update()
- {
- if (_isInitialize)
- {
- foreach (var spawner in Spawners)
+ if (index1 >= 0)
{
- spawner.Update();
+ _delayDestroyList.Insert(index1, delayDestroyGo);
+ }
+ else
+ {
+ _delayDestroyList.Add(delayDestroyGo);
}
}
}
- ///
- /// 创建游戏对象生成器
- ///
- /// 资源包名称
- public static Spawner CreateSpawner(string packageName = "")
+ public bool AddCacheGo(string resPath, GameObject go, GoProperty property)
{
- if (string.IsNullOrEmpty(packageName))
+ if (_poolRootTrans == null)
{
- packageName = GameModule.Resource.packageName;
+ DoDestroy(go);
+ return false;
}
- // 获取资源包
- var assetPackage = YooAssets.GetPackage(packageName);
- if (assetPackage == null)
- throw new Exception($"Not found asset package : {packageName}");
+ go.SetActive(false);
+ GoPoolNode orNewResourceNode = GetOrNewResourceNode(resPath);
+ if (!orNewResourceNode.AddCacheGo(go))
+ {
+ if (LogWhenPoolFull)
+ {
+ Log.Info("cache is full, ResPath[{0}] Max cache count:{1}", resPath, orNewResourceNode.MaxCacheCnt);
+ }
- // 检测资源包初始化状态
- 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 !");
+ DoDestroy(go);
+ return false;
+ }
- if (HasSpawner(packageName))
- return GetSpawner(packageName);
+ go.transform.SetParent(GetRootTrans(), false);
+ int hashCode = go.GetHashCode();
+ property.FrameID = _frameID;
+ property.FrameTime = _frameTime;
+ AddGoProperty(hashCode, property);
+ ++_totalPoolObjectCount;
+ if (orNewResourceNode.CacheFreeTime != 0)
+ {
+ orNewResourceNode.PoolGoRefreshTime = _frameTime;
+ }
- Spawner spawner = new Spawner(_root, assetPackage);
- Spawners.Add(spawner);
- return spawner;
+ return true;
}
- ///
- /// 获取游戏对象生成器。
- ///
- /// 资源包名称。
- public static Spawner GetSpawner(string packageName = "")
+ public void AddNewRecycleProperty(GameObject go, string resPath, Vector3 initScale)
{
- if (string.IsNullOrEmpty(packageName))
+ if (PauseGoPool)
{
- packageName = GameModule.Resource.packageName;
+ return;
}
- foreach (var spawner in Spawners)
+ GoProperty property;
+ property.ResPath = resPath;
+ property.Layer = go.layer;
+ property.FrameID = _frameID;
+ property.FrameTime = _frameTime;
+ property.InitScale = initScale;
+ AddGoProperty(go.GetHashCode(), property);
+ }
+
+ public GameObject AllocCacheGoByLocation(
+ string location,
+ Transform parentTrans = null,
+ bool haveLocalPos = false,
+ Vector3 localPos = default,
+ Quaternion localRot = default,
+ bool initEnable = true)
+ {
+ AssetInfo assetInfo = GameModule.Resource.GetAssetInfo(location);
+ return AllocCacheGo(assetInfo.AssetPath, parentTrans, haveLocalPos, localPos, localRot, initEnable);
+ }
+
+ public GameObject AllocCacheGo(
+ string resPath,
+ Transform parentTrans = null,
+ bool haveLocalPos = false,
+ Vector3 localPos = default,
+ Quaternion localRot = default,
+ bool initEnable = true)
+ {
+ if (_cacheGo.TryGetValue(resPath, out GoPoolNode goPoolNode))
{
- if (spawner.PackageName == packageName)
- return spawner;
+ List listGo = goPoolNode.ListGameObjects;
+ ResourceCacheMgr.Instance.GetCacheData(resPath);
+ for (int index = 0; index < listGo.Count; ++index)
+ {
+ GameObject gameObject = listGo[index];
+ if (gameObject == null)
+ {
+ --_totalPoolObjectCount;
+ listGo[index] = listGo[^1];
+ listGo.RemoveAt(listGo.Count - 1);
+ --index;
+ }
+ else
+ {
+ int hashCode = gameObject.GetHashCode();
+ if (!_goProperty.TryGetValue(hashCode, out GoProperty goProperty))
+ {
+ --_totalPoolObjectCount;
+ Log.Warning("AllocCacheGo Find property failed, bug [{0}]", gameObject.name);
+ listGo[index] = listGo[^1];
+ listGo.RemoveAt(listGo.Count - 1);
+ --index;
+ }
+ else if (goProperty.FrameTime > _frameTime || goProperty.FrameTime + PoolWaitReuseTime < _frameTime)
+ {
+ gameObject.transform.SetParent(null);
+ gameObject.transform.localScale = goProperty.InitScale;
+ if (PauseGoPool)
+ {
+ RemoveGoProperty(hashCode);
+ }
+
+ Transform transform = gameObject.transform;
+ transform.SetParent(parentTrans);
+ gameObject.layer = goProperty.Layer;
+ if (haveLocalPos)
+ {
+ transform.localPosition = localPos;
+ transform.localRotation = localRot;
+ }
+
+ gameObject.SetActive(initEnable);
+ listGo[index] = listGo[^1];
+ listGo.RemoveAt(listGo.Count - 1);
+ --_totalPoolObjectCount;
+ return gameObject;
+ }
+ }
+ }
}
- Log.Warning($"Not found spawner : {packageName}");
return null;
}
- ///
- /// 检测游戏对象生成器是否存在。
- ///
- /// 资源包名称。
- public static bool HasSpawner(string packageName = "")
+ public static void FreeAllCacheAndGo()
{
- if (string.IsNullOrEmpty(packageName))
+ ResourcePool.Instance.FreeAllCacheGo();
+ ResourceCacheMgr.Instance.RemoveAllCache();
+ }
+
+ public static void FreeAllPoolGo()
+ {
+ Instance.FreeAllCacheGo();
+ }
+
+ public void FreeAllCacheGo()
+ {
+ using Dictionary.Enumerator enumerator = _cacheGo.GetEnumerator();
+ while (enumerator.MoveNext())
{
- packageName = GameModule.Resource.packageName;
+ List listGo = enumerator.Current.Value.ListGameObjects;
+ for (int index = 0; index < listGo.Count; ++index)
+ {
+ GameObject go = listGo[index];
+ if (go != null)
+ {
+ go.transform.SetParent(null, false);
+ DoDestroy(go);
+ }
+ }
+
+ listGo.Clear();
}
- foreach (var spawner in Spawners)
+ _cacheGo.Clear();
+ _goProperty.Clear();
+ _totalPoolObjectCount = 0;
+ }
+
+ private GoPoolNode GetOrNewResourceNode(string resPath)
+ {
+ if (!_cacheGo.TryGetValue(resPath, out GoPoolNode orNewResourceNode))
{
- if (spawner.PackageName == packageName)
- return true;
+ orNewResourceNode = new GoPoolNode();
+ ResourceCacheMgr.Instance.GetCacheCfg(resPath, out orNewResourceNode.MaxCacheCnt, out orNewResourceNode.CacheFreeTime,
+ out orNewResourceNode.MinCacheCnt);
+ _cacheGo.Add(resPath, orNewResourceNode);
}
+ return orNewResourceNode;
+ }
+
+ private void AddGoProperty(int hashCode, GoProperty property)
+ {
+ if (!_goProperty.ContainsKey(hashCode))
+ ++GetOrNewResourceNode(property.ResPath).GoRefCnt;
+ _goProperty[hashCode] = property;
+ }
+
+ private void RemoveGoProperty(int hashCode)
+ {
+ if (!_goProperty.TryGetValue(hashCode, out GoProperty goProperty))
+ {
+ return;
+ }
+
+ --GetOrNewResourceNode(goProperty.ResPath).GoRefCnt;
+ _goProperty.Remove(hashCode);
+ }
+
+ private void DoDestroy(GameObject go)
+ {
+ RemoveGoProperty(go.GetHashCode());
+ Object.Destroy(go);
+ }
+
+ public bool IsNeedAutoFree(string resPath)
+ {
+ return !_cacheGo.TryGetValue(resPath, out GoPoolNode goPoolNode) || goPoolNode.GoRefCnt <= goPoolNode.ListGameObjects.Count;
+ }
+
+ public void FreeGoByResPath(string resPath)
+ {
+ if (!_cacheGo.TryGetValue(resPath, out GoPoolNode goPoolNode))
+ {
+ return;
+ }
+
+ List listGo = goPoolNode.ListGameObjects;
+ Log.Assert(goPoolNode.GoRefCnt <= listGo.Count);
+ foreach (var go in listGo)
+ {
+ if (!(go == null))
+ {
+ DoDestroy(go);
+ }
+ }
+
+ listGo.Clear();
+ _cacheGo.Remove(resPath);
+ }
+
+ public bool IsExistInCache(string resPath)
+ {
+ return _cacheGo.TryGetValue(resPath, out GoPoolNode goPoolNode) && goPoolNode.GoRefCnt > 0;
+ }
+
+ public bool IsNeedRecycle(GameObject go, out GoProperty property, bool forceNoPool)
+ {
+ int hashCode = go.GetHashCode();
+ if (!_goProperty.TryGetValue(hashCode, out property))
+ return false;
+ if (PauseGoPool)
+ {
+ RemoveGoProperty(hashCode);
+ return false;
+ }
+
+ if (!ResourceCacheMgr.Instance.IsResourceCached(property.ResPath))
+ {
+ RemoveGoProperty(hashCode);
+ return false;
+ }
+
+ if (!forceNoPool)
+ {
+ return true;
+ }
+
+ RemoveGoProperty(hashCode);
return false;
}
- #region 操作接口
-
- ///
- /// 销毁所有对象池及其资源。
- ///
- /// 销毁所有对象池,包括常驻对象池。
- public static void DestroyAll(bool includeAll)
+ public void ClearAllDelayDestroy()
{
- DefaultSpawner.DestroyAll(includeAll);
+ List delayDestroyList = _delayDestroyList;
+ for (int index = 0; index < delayDestroyList.Count; ++index)
+ {
+ DelayDestroyGo node = delayDestroyList[index];
+ AddCacheGo(node.Property.ResPath, node.Asset, node.Property);
+ FreeDelayNode(node);
+ }
+
+ delayDestroyList.Clear();
+ _freeDelayNode.Clear();
}
-
- ///
- /// 异步创建指定资源的游戏对象池。
- ///
- /// 资源定位地址。
- /// 资源常驻不销毁。
- /// 对象池的初始容量。
- /// 对象池的最大容量。
- /// 静默销毁时间(注意:小于零代表不主动销毁)。
- public static CreatePoolOperation CreateGameObjectPoolAsync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue,
- float destroyTime = -1f)
+ public void CheckPoolCacheFree()
{
- return DefaultSpawner.CreateGameObjectPoolAsync(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
+ if (!PoolCacheFreeEnable)
+ {
+ return;
+ }
+
+ using Dictionary.Enumerator enumerator = _cacheGo.GetEnumerator();
+ while (enumerator.MoveNext())
+ {
+ GoPoolNode goPoolNode = enumerator.Current.Value;
+ string key = enumerator.Current.Key;
+ if (goPoolNode.CacheFreeTime != 0 && goPoolNode.CacheFreeTime + goPoolNode.PoolGoRefreshTime < _frameTime)
+ {
+ List listGo = goPoolNode.ListGameObjects;
+ for (int index = 0; index < listGo.Count; ++index)
+ {
+ GameObject go = listGo[index];
+ if (go != null)
+ {
+ go.transform.SetParent(null, false);
+ DoDestroy(go);
+ }
+ }
+
+ listGo.Clear();
+ _listToDelete.Add(key);
+ }
+ }
+
+ foreach (var location in _listToDelete)
+ {
+ _cacheGo.Remove(location);
+ }
+
+ if (_listToDelete.Count <= 0)
+ {
+ return;
+ }
+
+ _listToDelete.Clear();
}
- ///
- /// 同步创建指定资源的游戏对象池。
- ///
- /// 资源定位地址。
- /// 资源常驻不销毁。
- /// 对象池的初始容量。
- /// 对象池的最大容量。
- /// 静默销毁时间(注意:小于零代表不主动销毁)。
- public static CreatePoolOperation CreateGameObjectPoolSync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue,
- float destroyTime = -1f)
+ public void OnUpdate()
{
- return DefaultSpawner.CreateGameObjectPoolSync(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
+ float time = Time.time;
+ int num = -1;
+ for (int index = 0; index < _delayDestroyList.Count; ++index)
+ {
+ DelayDestroyGo delayDestroy = _delayDestroyList[index];
+ if (delayDestroy.DestroyTime <= time)
+ {
+ num = index;
+ if (delayDestroy.Asset == null)
+ {
+ Log.Warning("delay destroy gameobject is freed: {0}", delayDestroy.Property.ResPath);
+ RemoveGoProperty(delayDestroy.HashId);
+ }
+ else
+ {
+ AddCacheGo(delayDestroy.Property.ResPath, delayDestroy.Asset, delayDestroy.Property);
+ }
+
+ {
+ FreeDelayNode(delayDestroy);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (num >= 0)
+ {
+ _delayDestroyList.RemoveRange(0, num + 1);
+ }
+
+ CheckPoolCacheFree();
+
+ LateUpdate();
+
+ ResourceCacheMgr.Instance.OnUpdate();
}
- ///
- /// 异步实例化一个游戏对象。
- ///
- /// 资源定位地址。
- /// 强制克隆游戏对象,忽略缓存池里的对象。
- /// 用户自定义数据。
- public static SpawnHandle SpawnAsync(string location, bool forceClone = false, params System.Object[] userDatas)
+ private void LateUpdate()
{
- return DefaultSpawner.SpawnAsync(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
+ ++_frameID;
+ _frameTime = Time.time;
}
-
- ///
- /// 异步实例化一个游戏对象。
- ///
- /// 资源定位地址。
- /// 父物体。
- /// 强制克隆游戏对象,忽略缓存池里的对象。
- /// 用户自定义数据。
- 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/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs.meta
index de4fb438..47980603 100644
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs.meta
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/ResourcePool.cs.meta
@@ -1,3 +1,11 @@
fileFormatVersion: 2
-guid: be208ee3e46e4243b9a68d4c7212015e
-timeCreated: 1693831058
\ No newline at end of file
+guid: 94ab30a1ade3e8f4ca3656bc73c1892c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs
deleted file mode 100644
index 5fc230e0..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-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/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs.meta
deleted file mode 100644
index e0f0e6ec..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/SpawnHandle.cs.meta
+++ /dev/null
@@ -1,3 +0,0 @@
-fileFormatVersion: 2
-guid: eb2cdce8eb814f7c92c74199d065688a
-timeCreated: 1693831296
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs
deleted file mode 100644
index c7754e82..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs
+++ /dev/null
@@ -1,262 +0,0 @@
-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/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs.meta b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs.meta
deleted file mode 100644
index 947f1af0..00000000
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/Pool/Spawner.cs.meta
+++ /dev/null
@@ -1,3 +0,0 @@
-fileFormatVersion: 2
-guid: 570ac9abe8a04e77b49c42719a9fa93b
-timeCreated: 1693831272
\ No newline at end of file
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs
index 048317f6..5ea920c8 100644
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs
@@ -1,8 +1,10 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using YooAsset;
+using Object = UnityEngine.Object;
namespace TEngine
{
@@ -90,22 +92,33 @@ namespace TEngine
///
public int ARCTableCapacity { get; set; }
+ ///
+ /// 是否开启对象池。
+ ///
+ public static bool EnableGoPool { get; set; } = true;
+
+ private readonly Dictionary _assetInfoMap = new Dictionary();
+
+ private static readonly Type _typeOfGameObject = typeof(GameObject);
+
#endregion
#region 生命周期
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
- ResourcePool.Update();
+ ResourcePool.Instance.OnUpdate();
}
internal override void Shutdown()
{
+ _assetInfoMap.Clear();
+
ReleasePreLoadAssets(isShutDown: true);
#if !UNITY_WEBGL
YooAssets.Destroy();
#endif
- ResourcePool.Destroy();
+ ResourcePool.Instance.OnDestroy();
}
private void ReleaseAllHandle()
@@ -320,7 +333,7 @@ namespace TEngine
YooAssets.SetDefaultPackage(defaultPackage);
}
- ResourcePool.Initialize(GameModule.Get().gameObject);
+ ResourcePool.Instance.OnAwake();
_releaseMaps ??= new Dictionary(ARCTableCapacity);
_operationHandlesMaps ??= new Dictionary(ARCTableCapacity);
@@ -415,6 +428,60 @@ namespace TEngine
throw new GameFrameworkException("System.NotImplementedException.");
}
+ ///
+ /// 释放游戏物体。
+ ///
+ /// 游戏物体。
+ /// 强制不入回收池。
+ /// 延迟时间。
+ public void FreeGameObject(GameObject gameObject, bool forceNoPool = false, float delayTime = 0f)
+ {
+ if (Application.isPlaying)
+ {
+ if (EnableGoPool && ResourcePool.Instance.IsNeedRecycle(gameObject, out GoProperty property, forceNoPool))
+ {
+ if (delayTime > 0f)
+ {
+ ResourcePool.Instance.DelayDestroy(gameObject, property, delayTime);
+ return;
+ }
+
+ ResourcePool.Instance.AddCacheGo(property.ResPath, gameObject, property);
+ }
+ else
+ {
+ if (delayTime > 0f)
+ {
+ Object.Destroy(gameObject, delayTime);
+ return;
+ }
+
+ Object.Destroy(gameObject);
+ }
+ }
+ else
+ {
+ if (delayTime > 0f)
+ {
+ Object.Destroy(gameObject, delayTime);
+ return;
+ }
+
+ Object.Destroy(gameObject);
+ }
+ }
+
+ private void AddRecycleGoProperty(string location, GameObject go, Vector3 initScale)
+ {
+ bool flag = ResourceCacheMgr.Instance.IsNeedCache(location, out int _, out int maxPoolCnt);
+ if (!(EnableGoPool & flag) || maxPoolCnt <= 0)
+ {
+ return;
+ }
+
+ ResourcePool.Instance.AddNewRecycleProperty(go, location, initScale);
+ }
+
///
/// 资源回收(卸载引用计数为零的资源)。
///
@@ -459,7 +526,7 @@ namespace TEngine
#endif
}
- ///
+
public HasAssetResult HasAsset(string location, string packageName = "")
{
if (string.IsNullOrEmpty(location))
@@ -467,21 +534,7 @@ namespace TEngine
throw new GameFrameworkException("Asset name is invalid.");
}
- AssetInfo assetInfo;
- if (string.IsNullOrEmpty(packageName))
- {
- assetInfo = YooAssets.GetAssetInfo(location);
- }
- else
- {
- var package = YooAssets.GetPackage(packageName);
- if (package == null)
- {
- throw new GameFrameworkException($"The package does not exist. Package Name :{packageName}");
- }
-
- assetInfo = package.GetAssetInfo(location);
- }
+ AssetInfo assetInfo = GetAssetInfo(location, packageName);
if (!CheckLocationValid(location))
{
@@ -512,7 +565,6 @@ namespace TEngine
#region 资源信息
- ///
public bool IsNeedDownloadFromRemote(string location, string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
@@ -526,7 +578,7 @@ namespace TEngine
}
}
- ///
+
public bool IsNeedDownloadFromRemote(AssetInfo assetInfo, string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
@@ -540,7 +592,7 @@ namespace TEngine
}
}
- ///
+
public AssetInfo[] GetAssetInfos(string tag, string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
@@ -554,7 +606,7 @@ namespace TEngine
}
}
- ///
+
public AssetInfo[] GetAssetInfos(string[] tags, string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
@@ -568,21 +620,46 @@ namespace TEngine
}
}
- ///
+
public AssetInfo GetAssetInfo(string location, string packageName = "")
{
+ if (string.IsNullOrEmpty(location))
+ {
+ throw new GameFrameworkException("Asset name is invalid.");
+ }
+
if (string.IsNullOrEmpty(packageName))
{
- return YooAssets.GetAssetInfo(location);
+ if (_assetInfoMap.TryGetValue(location, out AssetInfo assetInfo))
+ {
+ return assetInfo;
+ }
+
+ assetInfo = YooAssets.GetAssetInfo(location);
+ _assetInfoMap[location] = assetInfo;
+ return assetInfo;
}
else
{
+ string key = $"{packageName}/{location}";
+ if (_assetInfoMap.TryGetValue(key, out AssetInfo assetInfo))
+ {
+ return assetInfo;
+ }
+
var package = YooAssets.GetPackage(packageName);
- return package.GetAssetInfo(location);
+ if (package == null)
+ {
+ throw new GameFrameworkException($"The package does not exist. Package Name :{packageName}");
+ }
+
+ assetInfo = package.GetAssetInfo(location);
+ _assetInfoMap[key] = assetInfo;
+ return assetInfo;
}
}
- ///
+
public bool CheckLocationValid(string location, string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
@@ -598,44 +675,12 @@ namespace TEngine
#endregion
- ///
- public T LoadAsset(string location, bool needInstance = true, bool needCache = false,
- string packageName = "") where T : Object
+ public T LoadAsset(string location, bool needInstance = true, bool needCache = false, string packageName = "") where T : Object
{
- if (string.IsNullOrEmpty(location))
- {
- Log.Error("Asset name is invalid.");
- return default;
- }
-
- AssetOperationHandle handle = GetHandleSync(location, needCache, packageName);
-
- if (typeof(T) == typeof(GameObject))
- {
- if (needInstance)
- {
- GameObject gameObject = handle.InstantiateSync();
- if (!needCache)
- {
- AssetReference.BindAssetReference(gameObject, handle, location, packageName: packageName);
- }
-
- return gameObject as T;
- }
- }
-
- T ret = handle.AssetObject as T;
- if (!needCache)
- {
- handle.Dispose();
- }
-
- return ret;
+ return LoadAsset(location, parent: null, needInstance, needCache, packageName);
}
- ///
- public T LoadAsset(string location, Transform parent, bool needInstance = true, bool needCache = false,
- string packageName = "")
+ public T LoadAsset(string location, Transform parent, bool needInstance = true, bool needCache = false, string packageName = "")
where T : Object
{
if (string.IsNullOrEmpty(location))
@@ -644,9 +689,30 @@ namespace TEngine
return default;
}
+ Type assetType = typeof(T);
+
+ if (EnableGoPool && assetType == _typeOfGameObject)
+ {
+ GameObject go = ResourcePool.Instance.AllocCacheGoByLocation(location, parentTrans: parent);
+
+ if (go != null)
+ {
+ return go as T;
+ }
+ }
+
AssetOperationHandle handle = GetHandleSync(location, needCache, packageName: packageName);
- if (typeof(T) == typeof(GameObject))
+ AssetInfo assetInfo = GetAssetInfo(location, packageName);
+ if (EnableGoPool && handle.AssetObject != null)
+ {
+ if (ResourceCacheMgr.Instance.IsNeedCache(assetInfo.AssetPath, out var cacheTime))
+ {
+ ResourceCacheMgr.Instance.AddCache(assetInfo.AssetPath, handle.AssetObject, cacheTime);
+ }
+ }
+
+ if (assetType == _typeOfGameObject)
{
if (needInstance)
{
@@ -656,6 +722,11 @@ namespace TEngine
AssetReference.BindAssetReference(gameObject, handle, location, packageName: packageName);
}
+ if (EnableGoPool)
+ {
+ AddRecycleGoProperty(assetInfo.AssetPath, gameObject, gameObject.transform.localScale);
+ }
+
return gameObject as T;
}
}
@@ -669,38 +740,12 @@ namespace TEngine
return ret;
}
- ///
public T LoadAsset(string location, out AssetOperationHandle handle, bool needCache = false,
string packageName = "") where T : Object
{
- handle = GetHandleSync(location, needCache, packageName: packageName);
- if (string.IsNullOrEmpty(location))
- {
- Log.Error("Asset name is invalid.");
- return default;
- }
-
- if (typeof(T) == typeof(GameObject))
- {
- GameObject gameObject = handle.InstantiateSync();
- if (!needCache)
- {
- AssetReference.BindAssetReference(gameObject, handle, location, packageName: packageName);
- }
-
- return gameObject as T;
- }
-
- T ret = handle.AssetObject as T;
- if (!needCache)
- {
- handle.Dispose();
- }
-
- return ret;
+ return LoadAsset(location, null, out handle, needCache, packageName);
}
- ///
public T LoadAsset(string location, Transform parent, out AssetOperationHandle handle,
bool needCache = false, string packageName = "") where T : Object
{
@@ -712,7 +757,7 @@ namespace TEngine
return default;
}
- if (typeof(T) == typeof(GameObject))
+ if (typeof(T) == _typeOfGameObject)
{
GameObject gameObject = handle.InstantiateSync(parent);
if (!needCache)
@@ -732,21 +777,18 @@ namespace TEngine
return ret;
}
- ///
public AssetOperationHandle LoadAssetGetOperation(string location, bool needCache = false,
string packageName = "") where T : Object
{
return GetHandleSync(location, needCache, packageName: packageName);
}
- ///
public AssetOperationHandle LoadAssetAsyncHandle(string location, bool needCache = false,
string packageName = "") where T : Object
{
return GetHandleAsync(location, needCache, packageName: packageName);
}
- ///
public SubAssetsOperationHandle LoadSubAssetsSync(string location, string packageName = "")
where TObject : Object
{
@@ -759,7 +801,6 @@ namespace TEngine
return package.LoadSubAssetsSync(location);
}
- ///
public SubAssetsOperationHandle LoadSubAssetsAsync(string location, string packageName = "")
where TObject : Object
{
@@ -772,7 +813,6 @@ namespace TEngine
return package.LoadSubAssetsAsync(location: location);
}
- ///
public SubAssetsOperationHandle LoadSubAssetsSync(AssetInfo assetInfo, string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
@@ -784,7 +824,6 @@ namespace TEngine
return package.LoadSubAssetsSync(assetInfo);
}
- ///
public async UniTask> LoadAssetsByTagAsync(string assetTag, string packageName = "")
where T : UnityEngine.Object
{
@@ -796,10 +835,27 @@ namespace TEngine
return assetObjects;
}
- ///
public async UniTask LoadAssetAsync(string location, CancellationToken cancellationToken = default,
- bool needInstance = true, bool needCache = false, string packageName = "") where T : Object
+ bool needInstance = true, bool needCache = false, string packageName = "", Transform parent = null) where T : Object
{
+ if (string.IsNullOrEmpty(location))
+ {
+ Log.Error("Asset name is invalid.");
+ return default;
+ }
+
+ Type assetType = typeof(T);
+
+ if (EnableGoPool && assetType == _typeOfGameObject)
+ {
+ GameObject go = ResourcePool.Instance.AllocCacheGoByLocation(location, parentTrans: parent);
+
+ if (go != null)
+ {
+ return go as T;
+ }
+ }
+
AssetOperationHandle handle = LoadAssetAsyncHandle(location, needCache, packageName: packageName);
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken)
@@ -810,16 +866,30 @@ namespace TEngine
return null;
}
- if (typeof(T) == typeof(GameObject))
+ AssetInfo assetInfo = GetAssetInfo(location, packageName);
+ if (EnableGoPool && handle.AssetObject != null)
+ {
+ if (ResourceCacheMgr.Instance.IsNeedCache(assetInfo.AssetPath, out var cacheTime))
+ {
+ ResourceCacheMgr.Instance.AddCache(assetInfo.AssetPath, handle.AssetObject, cacheTime);
+ }
+ }
+
+ if (typeof(T) == _typeOfGameObject)
{
if (needInstance)
{
- GameObject gameObject = handle.InstantiateSync();
+ GameObject gameObject = handle.InstantiateSync(parent);
if (!needCache)
{
AssetReference.BindAssetReference(gameObject, handle, location, packageName: packageName);
}
+ if (EnableGoPool)
+ {
+ AddRecycleGoProperty(assetInfo.AssetPath, gameObject, gameObject.transform.localScale);
+ }
+
return gameObject as T;
}
}
@@ -833,49 +903,30 @@ namespace TEngine
return ret;
}
- ///
public async UniTask LoadGameObjectAsync(string location,
CancellationToken cancellationToken = default, bool needCache = false, string packageName = "")
{
- AssetOperationHandle handle =
- LoadAssetAsyncHandle(location, needCache, packageName: packageName);
-
- bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken)
- .SuppressCancellationThrow();
-
- if (cancelOrFailed)
- {
- return null;
- }
-
- GameObject gameObject = handle.InstantiateSync();
- if (!needCache)
- {
- AssetReference.BindAssetReference(gameObject, handle, location, packageName: packageName);
- }
-
- return gameObject;
+ return await LoadGameObjectAsync(location, null, cancellationToken, needCache, packageName);
}
- ///
public async UniTask LoadGameObjectAsync(string location, Transform parent,
CancellationToken cancellationToken = default, bool needCache = false, string packageName = "")
{
- GameObject gameObject =
- await LoadGameObjectAsync(location, cancellationToken, needCache, packageName: packageName);
- if (parent != null)
+ if (EnableGoPool)
{
- gameObject.transform.SetParent(parent);
- }
- else
- {
- Log.Error("Set Parent Failed");
+ GameObject go = ResourcePool.Instance.AllocCacheGoByLocation(location, parentTrans: parent);
+
+ if (go != null)
+ {
+ return go;
+ }
}
+ GameObject gameObject = await LoadAssetAsync(location, cancellationToken, needCache, packageName: packageName, parent: parent);
+
return gameObject;
}
- ///
public async UniTask LoadRawAssetAsync(string location,
CancellationToken cancellationToken = default, string packageName = "")
{
@@ -896,7 +947,6 @@ namespace TEngine
return cancelOrFailed ? null : handle;
}
- ///
public async UniTask LoadSubAssetAsync(string location, string assetName,
CancellationToken cancellationToken = default, string packageName = "") where T : Object
{
@@ -926,7 +976,6 @@ namespace TEngine
return cancelOrFailed ? null : handle.GetSubAssetObject(assetName);
}
- ///
public async UniTask LoadAllSubAssetAsync(string location,
CancellationToken cancellationToken = default, string packageName = "") where T : Object
{
@@ -960,7 +1009,6 @@ namespace TEngine
private readonly Dictionary _preLoadMaps = new Dictionary();
- ///
public void PushPreLoadAsset(string location, Object assetObject, string packageName = "")
{
var cacheKey = string.IsNullOrEmpty(packageName) || packageName.Equals(PackageName)
@@ -974,7 +1022,6 @@ namespace TEngine
_preLoadMaps.Add(cacheKey, assetObject);
}
- ///
public T GetPreLoadAsset(string location, string packageName = "") where T : Object
{
var cacheKey = string.IsNullOrEmpty(packageName) || packageName.Equals(PackageName)
diff --git a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs
index 6c1a79d7..df6f0d21 100644
--- a/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs
+++ b/UnityProject/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs
@@ -361,6 +361,11 @@ namespace TEngine
m_ResourceManager.UnloadAsset(asset);
}
+ public void FreeGameObject(GameObject go, bool forceNoPool = false, float delayTime = 0f)
+ {
+ m_ResourceManager.FreeGameObject(go, forceNoPool, delayTime);
+ }
+
///
/// 预订执行释放未被使用的资源。
///
@@ -672,15 +677,16 @@ namespace TEngine
/// 取消操作Token。
/// 是否需要实例化。
/// 是否需要缓存。
- /// 指定资源包的名称。不传使用默认资源包
+ /// 指定资源包的名称。不传使用默认资源包。
+ /// 资源实例父节点。
/// 要加载资源的类型。
/// 异步资源实例。
public async UniTask LoadAssetAsync(string location, CancellationToken cancellationToken = default,
- bool needInstance = true, bool needCache = false, string customPackageName = "")
+ bool needInstance = true, bool needCache = false, string customPackageName = "", Transform parent = null)
where T : UnityEngine.Object
{
return await m_ResourceManager.LoadAssetAsync(location, cancellationToken, needInstance, needCache,
- packageName: customPackageName);
+ packageName: customPackageName,parent:parent);
}
///