mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-07 16:45:10 +00:00
优化/新增超牛逼且很方便使用的对象池。
优化/新增超牛逼且很方便使用的对象池。
This commit is contained in:
@@ -95,6 +95,14 @@ namespace TEngine
|
||||
/// </summary>
|
||||
/// <param name="asset">要卸载的资源。</param>
|
||||
void UnloadAsset(object asset);
|
||||
|
||||
/// <summary>
|
||||
/// 释放游戏物体。
|
||||
/// </summary>
|
||||
/// <param name="gameObject">游戏物体。</param>
|
||||
/// <param name="forceNoPool">强制不入回收池。</param>
|
||||
/// <param name="delayTime">延迟时间。</param>
|
||||
void FreeGameObject(GameObject gameObject, bool forceNoPool = false, float delayTime = 0f);
|
||||
|
||||
/// <summary>
|
||||
/// 资源回收(卸载引用计数为零的资源)
|
||||
@@ -282,10 +290,11 @@ namespace TEngine
|
||||
/// <param name="needInstance">是否需要实例化。</param>
|
||||
/// <param name="needCache">是否需要缓存。</param>
|
||||
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
|
||||
/// <param name="parent">资源实例父节点。</param>
|
||||
/// <typeparam name="T">要加载资源的类型。</typeparam>
|
||||
/// <returns>异步资源实例。</returns>
|
||||
UniTask<T> LoadAssetAsync<T>(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;
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载游戏物体。
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待异步实例化结束。
|
||||
/// </summary>
|
||||
public void WaitForAsyncComplete()
|
||||
{
|
||||
if (_handle != null)
|
||||
{
|
||||
if (_steps == ESteps.Done)
|
||||
return;
|
||||
_handle.WaitForAsyncComplete();
|
||||
OnUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e1853e7ff624c639fba990079beeee5
|
||||
timeCreated: 1693831296
|
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal class DelayDestroyGo
|
||||
{
|
||||
public GoProperty Property;
|
||||
public GameObject Asset;
|
||||
public int HashId;
|
||||
public float DestroyTime;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e03aac69e9233b488725725586c612d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,234 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏物体对象池。
|
||||
/// </summary>
|
||||
internal class GameObjectPool
|
||||
{
|
||||
private readonly GameObject _root;
|
||||
private readonly Queue<InstantiateOperation> _cacheOperations;
|
||||
private readonly bool _dontDestroy;
|
||||
private readonly int _initCapacity;
|
||||
private readonly int _maxCapacity;
|
||||
private readonly float _destroyTime;
|
||||
private float _lastRestoreRealTime = -1f;
|
||||
|
||||
/// <summary>
|
||||
/// 资源句柄。
|
||||
/// </summary>
|
||||
public AssetOperationHandle AssetHandle { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源定位地址。
|
||||
/// </summary>
|
||||
public string Location { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部缓存总数。
|
||||
/// </summary>
|
||||
public int CacheCount => _cacheOperations.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 外部使用总数。
|
||||
/// </summary>
|
||||
public int SpawnCount { private set; get; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 是否常驻不销毁。
|
||||
/// </summary>
|
||||
public bool DontDestroy => _dontDestroy;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏物体对象池。
|
||||
/// </summary>
|
||||
/// <param name="poolingRoot">对象池根节点。</param>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="dontDestroy">是否常驻不销毁。</param>
|
||||
/// <param name="initCapacity">初始容量。</param>
|
||||
/// <param name="maxCapacity">最大容量。</param>
|
||||
/// <param name="destroyTime">对象池销毁时间。</param>
|
||||
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<InstantiateOperation>(initCapacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建对象池。
|
||||
/// </summary>
|
||||
/// <param name="package">资源包。</param>
|
||||
public void CreatePool(ResourcePackage package)
|
||||
{
|
||||
// 加载游戏对象
|
||||
AssetHandle = package.LoadAssetAsync<GameObject>(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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁游戏对象池。
|
||||
/// </summary>
|
||||
public void DestroyPool()
|
||||
{
|
||||
// 卸载资源对象
|
||||
AssetHandle.Release();
|
||||
AssetHandle = null;
|
||||
|
||||
// 销毁游戏对象
|
||||
Object.Destroy(_root);
|
||||
_cacheOperations.Clear();
|
||||
|
||||
SpawnCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询静默时间内是否可以销毁。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏对象池是否已经销毁。
|
||||
/// </summary>
|
||||
public bool IsDestroyed()
|
||||
{
|
||||
return AssetHandle == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收操作。
|
||||
/// </summary>
|
||||
/// <param name="operation">资源实例化操作句柄。</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 丢弃操作。
|
||||
/// </summary>
|
||||
/// <param name="operation">资源实例化操作句柄。</param>
|
||||
public void Discard(InstantiateOperation operation)
|
||||
{
|
||||
if (IsDestroyed())
|
||||
{
|
||||
DestroyInstantiateOperation(operation);
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnCount--;
|
||||
if (SpawnCount <= 0)
|
||||
_lastRestoreRealTime = Time.realtimeSinceStartup;
|
||||
|
||||
DestroyInstantiateOperation(operation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="parent">父节点位置。</param>
|
||||
/// <param name="position">位置。</param>
|
||||
/// <param name="rotation">旋转。</param>
|
||||
/// <param name="forceClone">是否强制克隆。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
/// <returns>Spawn操作句柄。</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f0c9bab3d1243fda94ec9a08844ceee
|
||||
timeCreated: 1693831296
|
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal class GoPoolNode
|
||||
{
|
||||
public readonly List<GameObject> ListGameObjects = new List<GameObject>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e42a95f042081047b9105a70252b9f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c868a337f95e6ad4e94ee4ed5b0485e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,38 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源缓存数据。
|
||||
/// </summary>
|
||||
internal class ResCacheData : IMemory
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源实例。
|
||||
/// </summary>
|
||||
public Object Asset;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存刷新时间。
|
||||
/// </summary>
|
||||
public float CacheRefreshTime;
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动过期。
|
||||
/// </summary>
|
||||
public bool AutoExpire;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存过期时间。
|
||||
/// </summary>
|
||||
public int CacheExpireTime;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Asset = null;
|
||||
CacheRefreshTime = 0f;
|
||||
AutoExpire = false;
|
||||
CacheExpireTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6b38fc58dc07ab4da453ee3d4d02c20
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5100cbca9f2a42ecb050957a3552d43a
|
||||
timeCreated: 1701085446
|
@@ -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<string, ResCacheData> _cachePool = new Dictionary<string, ResCacheData>();
|
||||
private readonly Dictionary<string, ResCacheData> _persistCachePool = new Dictionary<string, ResCacheData>();
|
||||
private bool _enableLog = true;
|
||||
private readonly List<ResourceCacheConfig> _needCacheResList = new List<ResourceCacheConfig>();
|
||||
private readonly List<string> _needPersistResList = new List<string>();
|
||||
private GameTimerTick _tickCheckExpire;
|
||||
private readonly List<string> _listToDel = new List<string>();
|
||||
private bool _pauseCache;
|
||||
|
||||
public int PersistCachePoolCount = 30;
|
||||
|
||||
public bool PauseCache
|
||||
{
|
||||
set => _pauseCache = value;
|
||||
get => _pauseCache;
|
||||
}
|
||||
|
||||
internal Dictionary<string, ResCacheData> CachePoolAllData => _cachePool;
|
||||
|
||||
internal Dictionary<string, ResCacheData> PersistPoolAllData => _persistCachePool;
|
||||
|
||||
public int CacheCount => _cachePool.Count;
|
||||
|
||||
public int PersistCount => _persistCachePool.Count;
|
||||
|
||||
public void SetLogEnable(bool enable) => _enableLog = enable;
|
||||
|
||||
/// <summary>
|
||||
/// 注册持久化的资源。
|
||||
/// </summary>
|
||||
/// <param name="resList">持久化的资源起始路径。存在这个路径开始的资源不会释放。</param>
|
||||
public void RegPersistResPath(List<string> resList) => _needPersistResList.AddRange((IEnumerable<string>)resList);
|
||||
|
||||
/// <summary>
|
||||
/// 注册缓存池的资源。
|
||||
/// </summary>
|
||||
/// <param name="resPath">缓存池的资源起始路径。存在这个路径开始的资源则加入对象池。</param>
|
||||
/// <param name="cacheTime">缓存时间。</param>
|
||||
/// <param name="maxPoolCnt">缓存池最大容量。</param>
|
||||
/// <param name="poolGoFreeTime">缓存池释放时间。</param>
|
||||
/// <param name="minPoolCnt">缓存池最小容量。</param>
|
||||
/// <remarks> ResourceCacheMgr.Instance.RegCacheResPath("Assets/AssetRaw/Effects"); 所有特效相关资源都加入对象池。 </remarks>
|
||||
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<string> GetAllPersistCache()
|
||||
{
|
||||
List<string> allPersistCache = new List<string>();
|
||||
using Dictionary<string, ResCacheData>.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<ResCacheData>();
|
||||
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<string, ResCacheData>.Enumerator enumerator = _cachePool.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
KeyValuePair<string, ResCacheData> 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<string> 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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e211ca9bbc0ef74ca63508c6b10c380
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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<GameObject>("Sprite",parent:transform);
|
||||
|
||||
//回收资源
|
||||
GameModule.Resource.FreeGameObject(obj);
|
||||
|
||||
//删除资源 放心资源不存在泄露。
|
||||
Unity Engine.Object。Destroy(obj);
|
||||
************************************************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏对象池系统。
|
||||
/// <remarks>用法 SpawnHandle handle = ResourcePool.SpawnAsync("Cube");</remarks>
|
||||
/// </summary>
|
||||
public static class ResourcePool
|
||||
internal class ResourcePool
|
||||
{
|
||||
private static bool _isInitialize = false;
|
||||
private static readonly List<Spawner> Spawners = new List<Spawner>();
|
||||
private static GameObject _root;
|
||||
private static Spawner _defaultSpawner = null;
|
||||
private static ResourcePool _instance;
|
||||
|
||||
/// <summary>
|
||||
/// 默认Package对象生成器。
|
||||
/// </summary>
|
||||
private static Spawner DefaultSpawner => _defaultSpawner ??= CreateSpawner();
|
||||
internal static ResourcePool Instance => _instance ??= new ResourcePool();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化游戏对象池系统
|
||||
/// </summary>
|
||||
internal static void Initialize(GameObject root)
|
||||
private readonly Dictionary<string, GoPoolNode> _cacheGo = new Dictionary<string, GoPoolNode>();
|
||||
private readonly Dictionary<int, GoProperty> _goProperty = new Dictionary<int, GoProperty>();
|
||||
private readonly List<DelayDestroyGo> _delayDestroyList = new List<DelayDestroyGo>();
|
||||
private readonly List<DelayDestroyGo> _freeDelayNode = new List<DelayDestroyGo>();
|
||||
private readonly List<string> _listToDelete = new List<string>();
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁游戏对象池系统
|
||||
/// </summary>
|
||||
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 !");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新游戏对象池系统
|
||||
/// </summary>
|
||||
internal static void Update()
|
||||
{
|
||||
if (_isInitialize)
|
||||
{
|
||||
foreach (var spawner in Spawners)
|
||||
if (index1 >= 0)
|
||||
{
|
||||
spawner.Update();
|
||||
_delayDestroyList.Insert(index1, delayDestroyGo);
|
||||
}
|
||||
else
|
||||
{
|
||||
_delayDestroyList.Add(delayDestroyGo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建游戏对象生成器
|
||||
/// </summary>
|
||||
/// <param name="packageName">资源包名称</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取游戏对象生成器。
|
||||
/// </summary>
|
||||
/// <param name="packageName">资源包名称。</param>
|
||||
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<GameObject> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测游戏对象生成器是否存在。
|
||||
/// </summary>
|
||||
/// <param name="packageName">资源包名称。</param>
|
||||
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<string, GoPoolNode>.Enumerator enumerator = _cacheGo.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
packageName = GameModule.Resource.packageName;
|
||||
List<GameObject> 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<GameObject> 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 操作接口
|
||||
|
||||
/// <summary>
|
||||
/// 销毁所有对象池及其资源。
|
||||
/// </summary>
|
||||
/// <param name="includeAll">销毁所有对象池,包括常驻对象池。</param>
|
||||
public static void DestroyAll(bool includeAll)
|
||||
public void ClearAllDelayDestroy()
|
||||
{
|
||||
DefaultSpawner.DestroyAll(includeAll);
|
||||
List<DelayDestroyGo> 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();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步创建指定资源的游戏对象池。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="dontDestroy">资源常驻不销毁。</param>
|
||||
/// <param name="initCapacity">对象池的初始容量。</param>
|
||||
/// <param name="maxCapacity">对象池的最大容量。</param>
|
||||
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
|
||||
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<string, GoPoolNode>.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<GameObject> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步创建指定资源的游戏对象池。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="dontDestroy">资源常驻不销毁。</param>
|
||||
/// <param name="initCapacity">对象池的初始容量。</param>
|
||||
/// <param name="maxCapacity">对象池的最大容量。</param>
|
||||
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体。</param>
|
||||
/// <param name="position">世界坐标。</param>
|
||||
/// <param name="rotation">世界角度。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
public static SpawnHandle SpawnSync(string location, bool forceClone = false, params System.Object[] userDatas)
|
||||
{
|
||||
return DefaultSpawner.SpawnSync(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
public static SpawnHandle SpawnSync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
|
||||
{
|
||||
return DefaultSpawner.SpawnAsync(location, parent, forceClone, userDatas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体。</param>
|
||||
/// <param name="position">世界坐标。</param>
|
||||
/// <param name="rotation">世界角度。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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
|
||||
}
|
||||
}
|
@@ -1,3 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be208ee3e46e4243b9a68d4c7212015e
|
||||
timeCreated: 1693831058
|
||||
guid: 94ab30a1ade3e8f4ca3656bc73c1892c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 实例化的游戏对象。
|
||||
/// </summary>
|
||||
public GameObject GameObj
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_operation == null)
|
||||
{
|
||||
Log.Warning("The spawn handle is invalid !");
|
||||
return null;
|
||||
}
|
||||
|
||||
return _operation.Result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义数据集。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收对象。
|
||||
/// </summary>
|
||||
public void Restore()
|
||||
{
|
||||
if (_operation != null)
|
||||
{
|
||||
ClearCompletedCallback();
|
||||
CancelHandle();
|
||||
_pool.Restore(_operation);
|
||||
_operation = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 丢弃对象。
|
||||
/// </summary>
|
||||
public void Discard()
|
||||
{
|
||||
if (_operation != null)
|
||||
{
|
||||
ClearCompletedCallback();
|
||||
CancelHandle();
|
||||
_pool.Discard(_operation);
|
||||
_operation = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待异步实例化结束。
|
||||
/// </summary>
|
||||
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 !";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb2cdce8eb814f7c92c74199d065688a
|
||||
timeCreated: 1693831296
|
@@ -1,262 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象生成器。
|
||||
/// </summary>
|
||||
public class Spawner
|
||||
{
|
||||
private readonly List<GameObjectPool> _gameObjectPools = new List<GameObjectPool>(100);
|
||||
private readonly List<GameObjectPool> _removeList = new List<GameObjectPool>(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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新游戏对象池系统。
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁游戏对象池系统。
|
||||
/// </summary>
|
||||
internal void Destroy()
|
||||
{
|
||||
DestroyAll(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁所有对象池及其资源。
|
||||
/// </summary>
|
||||
/// <param name="includeAll">销毁所有对象池,包括常驻对象池。</param>
|
||||
public void DestroyAll(bool includeAll)
|
||||
{
|
||||
if (includeAll)
|
||||
{
|
||||
foreach (var pool in _gameObjectPools)
|
||||
{
|
||||
pool.DestroyPool();
|
||||
}
|
||||
_gameObjectPools.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
List<GameObjectPool> removeList = new List<GameObjectPool>();
|
||||
foreach (var pool in _gameObjectPools)
|
||||
{
|
||||
if (pool.DontDestroy == false)
|
||||
removeList.Add(pool);
|
||||
}
|
||||
foreach (var pool in removeList)
|
||||
{
|
||||
_gameObjectPools.Remove(pool);
|
||||
pool.DestroyPool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步创建指定资源的游戏对象池。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="dontDestroy">资源常驻不销毁。</param>
|
||||
/// <param name="initCapacity">对象池的初始容量。</param>
|
||||
/// <param name="maxCapacity">对象池的最大容量。</param>
|
||||
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步创建指定资源的游戏对象池。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="dontDestroy">资源常驻不销毁。</param>
|
||||
/// <param name="initCapacity">对象池的初始容量。</param>
|
||||
/// <param name="maxCapacity">对象池的最大容量。</param>
|
||||
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建指定资源的游戏对象池。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
public SpawnHandle SpawnAsync(string location, bool forceClone = false, params System.Object[] userDatas)
|
||||
{
|
||||
return SpawnInternal(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
public SpawnHandle SpawnAsync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
|
||||
{
|
||||
return SpawnInternal(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体。</param>
|
||||
/// <param name="position">世界坐标。</param>
|
||||
/// <param name="rotation">世界角度。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步实例化一个游戏对象。
|
||||
/// </summary>
|
||||
/// <param name="location">资源定位地址。</param>
|
||||
/// <param name="parent">父物体。</param>
|
||||
/// <param name="position">世界坐标。</param>
|
||||
/// <param name="rotation">世界角度。</param>
|
||||
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
|
||||
/// <param name="userDatas">用户自定义数据。</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实例化一个游戏对象。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 570ac9abe8a04e77b49c42719a9fa93b
|
||||
timeCreated: 1693831272
|
@@ -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
|
||||
/// </summary>
|
||||
public int ARCTableCapacity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启对象池。
|
||||
/// </summary>
|
||||
public static bool EnableGoPool { get; set; } = true;
|
||||
|
||||
private readonly Dictionary<string, AssetInfo> _assetInfoMap = new Dictionary<string, AssetInfo>();
|
||||
|
||||
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<ResourceModule>().gameObject);
|
||||
ResourcePool.Instance.OnAwake();
|
||||
|
||||
_releaseMaps ??= new Dictionary<string, AssetOperationHandle>(ARCTableCapacity);
|
||||
_operationHandlesMaps ??= new Dictionary<string, AssetOperationHandle>(ARCTableCapacity);
|
||||
@@ -415,6 +428,60 @@ namespace TEngine
|
||||
throw new GameFrameworkException("System.NotImplementedException.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放游戏物体。
|
||||
/// </summary>
|
||||
/// <param name="gameObject">游戏物体。</param>
|
||||
/// <param name="forceNoPool">强制不入回收池。</param>
|
||||
/// <param name="delayTime">延迟时间。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 资源回收(卸载引用计数为零的资源)。
|
||||
/// </summary>
|
||||
@@ -459,7 +526,7 @@ namespace TEngine
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
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 资源信息
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsNeedDownloadFromRemote(string location, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
@@ -526,7 +578,7 @@ namespace TEngine
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
public bool IsNeedDownloadFromRemote(AssetInfo assetInfo, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
@@ -540,7 +592,7 @@ namespace TEngine
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
public AssetInfo[] GetAssetInfos(string tag, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
@@ -554,7 +606,7 @@ namespace TEngine
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
public AssetInfo[] GetAssetInfos(string[] tags, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
@@ -568,21 +620,46 @@ namespace TEngine
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
public bool CheckLocationValid(string location, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
@@ -598,44 +675,12 @@ namespace TEngine
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public T LoadAsset<T>(string location, bool needInstance = true, bool needCache = false,
|
||||
string packageName = "") where T : Object
|
||||
public T LoadAsset<T>(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<T>(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<T>(location, parent: null, needInstance, needCache, packageName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public T LoadAsset<T>(string location, Transform parent, bool needInstance = true, bool needCache = false,
|
||||
string packageName = "")
|
||||
public T LoadAsset<T>(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<T>(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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public T LoadAsset<T>(string location, out AssetOperationHandle handle, bool needCache = false,
|
||||
string packageName = "") where T : Object
|
||||
{
|
||||
handle = GetHandleSync<T>(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<T>(location, null, out handle, needCache, packageName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public T LoadAsset<T>(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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public AssetOperationHandle LoadAssetGetOperation<T>(string location, bool needCache = false,
|
||||
string packageName = "") where T : Object
|
||||
{
|
||||
return GetHandleSync<T>(location, needCache, packageName: packageName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public AssetOperationHandle LoadAssetAsyncHandle<T>(string location, bool needCache = false,
|
||||
string packageName = "") where T : Object
|
||||
{
|
||||
return GetHandleAsync<T>(location, needCache, packageName: packageName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public SubAssetsOperationHandle LoadSubAssetsSync<TObject>(string location, string packageName = "")
|
||||
where TObject : Object
|
||||
{
|
||||
@@ -759,7 +801,6 @@ namespace TEngine
|
||||
return package.LoadSubAssetsSync<TObject>(location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public SubAssetsOperationHandle LoadSubAssetsAsync<TObject>(string location, string packageName = "")
|
||||
where TObject : Object
|
||||
{
|
||||
@@ -772,7 +813,6 @@ namespace TEngine
|
||||
return package.LoadSubAssetsAsync<TObject>(location: location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public SubAssetsOperationHandle LoadSubAssetsSync(AssetInfo assetInfo, string packageName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
@@ -784,7 +824,6 @@ namespace TEngine
|
||||
return package.LoadSubAssetsSync(assetInfo);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async UniTask<List<T>> LoadAssetsByTagAsync<T>(string assetTag, string packageName = "")
|
||||
where T : UnityEngine.Object
|
||||
{
|
||||
@@ -796,10 +835,27 @@ namespace TEngine
|
||||
return assetObjects;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async UniTask<T> LoadAssetAsync<T>(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<T>(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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async UniTask<GameObject> LoadGameObjectAsync(string location,
|
||||
CancellationToken cancellationToken = default, bool needCache = false, string packageName = "")
|
||||
{
|
||||
AssetOperationHandle handle =
|
||||
LoadAssetAsyncHandle<GameObject>(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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async UniTask<GameObject> 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<GameObject>(location, cancellationToken, needCache, packageName: packageName, parent: parent);
|
||||
|
||||
return gameObject;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async UniTask<RawFileOperationHandle> LoadRawAssetAsync(string location,
|
||||
CancellationToken cancellationToken = default, string packageName = "")
|
||||
{
|
||||
@@ -896,7 +947,6 @@ namespace TEngine
|
||||
return cancelOrFailed ? null : handle;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async UniTask<T> LoadSubAssetAsync<T>(string location, string assetName,
|
||||
CancellationToken cancellationToken = default, string packageName = "") where T : Object
|
||||
{
|
||||
@@ -926,7 +976,6 @@ namespace TEngine
|
||||
return cancelOrFailed ? null : handle.GetSubAssetObject<T>(assetName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async UniTask<T[]> LoadAllSubAssetAsync<T>(string location,
|
||||
CancellationToken cancellationToken = default, string packageName = "") where T : Object
|
||||
{
|
||||
@@ -960,7 +1009,6 @@ namespace TEngine
|
||||
|
||||
private readonly Dictionary<string, Object> _preLoadMaps = new Dictionary<string, Object>();
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public T GetPreLoadAsset<T>(string location, string packageName = "") where T : Object
|
||||
{
|
||||
var cacheKey = string.IsNullOrEmpty(packageName) || packageName.Equals(PackageName)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预订执行释放未被使用的资源。
|
||||
/// </summary>
|
||||
@@ -672,15 +677,16 @@ namespace TEngine
|
||||
/// <param name="cancellationToken">取消操作Token。</param>
|
||||
/// <param name="needInstance">是否需要实例化。</param>
|
||||
/// <param name="needCache">是否需要缓存。</param>
|
||||
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
|
||||
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包。</param>
|
||||
/// <param name="parent">资源实例父节点。</param>
|
||||
/// <typeparam name="T">要加载资源的类型。</typeparam>
|
||||
/// <returns>异步资源实例。</returns>
|
||||
public async UniTask<T> LoadAssetAsync<T>(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<T>(location, cancellationToken, needInstance, needCache,
|
||||
packageName: customPackageName);
|
||||
packageName: customPackageName,parent:parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Reference in New Issue
Block a user