com.guru.unity.applit/Runtime/GuruApp/Code/Core/GuruResManager.cs

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