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); } ///