213 lines
5.5 KiB
C#
213 lines
5.5 KiB
C#
|
|
namespace Guru
|
||
|
|
{
|
||
|
|
using System;
|
||
|
|
using Object = UnityEngine.Object;
|
||
|
|
using UnityEngine;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
|
||
|
|
|
||
|
|
public class GuruResManager : IResManager, IUpdater
|
||
|
|
{
|
||
|
|
public const string InstanceName = "guru_res_manager";
|
||
|
|
public static float CheckRequestInterval = 3; // 检查加载队列的频率
|
||
|
|
|
||
|
|
public string Name => "guru_res";
|
||
|
|
|
||
|
|
private bool _isReady;
|
||
|
|
public bool IsReady => _isReady;
|
||
|
|
|
||
|
|
public Context Context { get; set; }
|
||
|
|
|
||
|
|
private LoaderPool _loaderPool;
|
||
|
|
|
||
|
|
private Queue<ResRequest> _requests;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 注册资源管理器
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="context"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public static GuruResManager Create(Context context)
|
||
|
|
{
|
||
|
|
var mgr = new GuruResManager();
|
||
|
|
mgr.Init();
|
||
|
|
context.RegisterResManager(mgr, InstanceName);
|
||
|
|
return mgr;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Init()
|
||
|
|
{
|
||
|
|
_isReady = true;
|
||
|
|
_loaderPool = LoaderPool.CreatePool();
|
||
|
|
_requests = new Queue<ResRequest>(20);
|
||
|
|
}
|
||
|
|
|
||
|
|
public T CloneObject<T>(GameObject prefab, Transform container = null) where T :Component
|
||
|
|
{
|
||
|
|
var go = GameObject.Instantiate<GameObject>(prefab, container);
|
||
|
|
if (go != null)
|
||
|
|
{
|
||
|
|
go.name = nameof(T).ToLower();
|
||
|
|
return go.GetComponent<T>();
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 加载本地资源
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="resUri"></param>
|
||
|
|
/// <typeparam name="T"></typeparam>
|
||
|
|
/// <returns></returns>
|
||
|
|
public T Load<T>(string resUri) where T : Object
|
||
|
|
{
|
||
|
|
return Resources.Load<T>(resUri);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 异步加载资源
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="resUri"></param>
|
||
|
|
/// <param name="onLoadComplete"></param>
|
||
|
|
/// <typeparam name="T"></typeparam>
|
||
|
|
public void LoadAsync(string resUri, Action<ResLoadInfo> onLoadComplete)
|
||
|
|
{
|
||
|
|
ResRequest req = ResRequest.Create(resUri, onLoadComplete);
|
||
|
|
_requests.Enqueue(req); // 添加任务
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
#region 帧更新
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 帧更新
|
||
|
|
/// </summary>
|
||
|
|
public void OnUpdate()
|
||
|
|
{
|
||
|
|
CheckLoadingList();
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool IsStopped { get; set; } = false;
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
#region 加载队列
|
||
|
|
|
||
|
|
private float _checkLoadingDuration = 0;
|
||
|
|
/// <summary>
|
||
|
|
/// 检查加载队列
|
||
|
|
/// </summary>
|
||
|
|
private void CheckLoadingList()
|
||
|
|
{
|
||
|
|
if (_requests.Count > 0 && _loaderPool.FreeCount > 0)
|
||
|
|
{
|
||
|
|
_checkLoadingDuration = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新检查队列
|
||
|
|
if (_checkLoadingDuration > 0)
|
||
|
|
{
|
||
|
|
_checkLoadingDuration -= Time.deltaTime;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 检查队列
|
||
|
|
while (_requests.Count > 0 && _loaderPool.FreeCount > 0)
|
||
|
|
{
|
||
|
|
var loader = _loaderPool.Get();
|
||
|
|
if (loader != null)
|
||
|
|
{
|
||
|
|
var req = _requests.Dequeue();
|
||
|
|
loader.LoadAsync(req.resUri, req.callback);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
_checkLoadingDuration = CheckRequestInterval;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 加载器池
|
||
|
|
/// 默认同时持有 3 个加载器
|
||
|
|
/// </summary>
|
||
|
|
internal class LoaderPool: IPool<ResLoaderBase>
|
||
|
|
{
|
||
|
|
public string Name => "loader_pool";
|
||
|
|
public int PreSpawnCount { get; set; } = 3;
|
||
|
|
private Queue<ResLoaderBase> _freeLoaders;
|
||
|
|
|
||
|
|
|
||
|
|
public static LoaderPool CreatePool(int initCount = 3)
|
||
|
|
{
|
||
|
|
if (initCount < 2) initCount = 2; // 最小 2 个
|
||
|
|
var pool = new LoaderPool(initCount);
|
||
|
|
return pool;
|
||
|
|
}
|
||
|
|
|
||
|
|
public LoaderPool(int initCount = 0)
|
||
|
|
{
|
||
|
|
if (initCount > 0) PreSpawnCount = initCount;
|
||
|
|
_freeLoaders = new Queue<ResLoaderBase>();
|
||
|
|
if (PreSpawnCount > 0)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < PreSpawnCount; i++)
|
||
|
|
{
|
||
|
|
_freeLoaders.Enqueue(Create());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public ResLoaderBase Get()
|
||
|
|
{
|
||
|
|
if(FreeCount > 0)
|
||
|
|
{
|
||
|
|
return _freeLoaders.Dequeue();
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
public ResLoaderBase Create()
|
||
|
|
{
|
||
|
|
var loader = new ResLoaderBase();
|
||
|
|
loader.OnLoaderFree = Recycle;
|
||
|
|
return loader;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Recycle(ResLoaderBase obj)
|
||
|
|
{
|
||
|
|
_freeLoaders.Enqueue(obj);
|
||
|
|
}
|
||
|
|
|
||
|
|
public int FreeCount => _freeLoaders.Count;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 加载需求
|
||
|
|
/// </summary>
|
||
|
|
internal struct ResRequest
|
||
|
|
{
|
||
|
|
public string url;
|
||
|
|
public string resUri;
|
||
|
|
public Action<ResLoadInfo> callback;
|
||
|
|
|
||
|
|
public static ResRequest Create(string resUri, Action<ResLoadInfo> callback)
|
||
|
|
{
|
||
|
|
ResUriHelper.UriToType(resUri, out var type, out var url);
|
||
|
|
return new ResRequest()
|
||
|
|
{
|
||
|
|
url = url,
|
||
|
|
resUri = resUri,
|
||
|
|
callback = callback
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|