资源加载管理器模块的主要职责就是资源加载的管理,从物理结构上对该模块进行了拆分成了一个单独的文件,资源加载管理器是加载器中偏底层的一个部分;资源加载管理器负责AssetBundle的加载、Asset资源的加载、资源加载完成后缓存进对预制池、卸载功能;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YouYou;
using UnityEngine;
namespace Myh
{
//资源加载管理
public class ResourceLoaderManager : ManagerBase, IDisposable
{
//资源加载管理器
//资源分类:{资源名:资源实体}
private Dictionary> m_dicAssetInfo;
//资源包加载器链表
private LinkedList m_ListAssetBundleLoader;
//资源加载链表
private LinkedList m_ListAssetLoader;
//加载中的资源
private Dictionary>> m_dicLoadingAsset = new Dictionary>>();
//初始化资源信息完毕
private BaseAction m_InitAssetInfoComplete;
private Dictionary>> m_dicLoadingAssetBundle = new Dictionary>>();
public ResourceLoaderManager()
{
m_dicAssetInfo = new Dictionary>();
m_ListAssetBundleLoader = new LinkedList();
m_ListAssetLoader = new LinkedList();
}
//初始化
public override void Init()
{
//确保游戏刚开始运行的时候,分类字典已经初始化好了
IEnumerator iter = Enum.GetValues(typeof(AssetCategory)).GetEnumerator();
while (iter.MoveNext())
{
AssetCategory assetCategory = (AssetCategory)iter.Current;
m_dicAssetInfo[assetCategory] = new Dictionary();
}
}
#region 初始化资源信息
//初始化资源信息(这个才是真正的初始化函数)
private void InitAssetInfo(byte[] buffer)
{
buffer = ZlibHelper.DeCompressBytes(buffer);
MMO_MemoryStream ms = new MMO_MemoryStream(buffer);
int len = ms.ReadInt();
int depLen = 0;
for (int i = 0; i < len; ++i)
{
AssetEntity entity = new AssetEntity();
entity.Category = (AssetCategory)ms.ReadByte();
entity.AssetFullName = ms.ReadUTF8String();
entity.AssetBundleName = ms.ReadUTF8String();
depLen = ms.ReadInt();
//有依赖的资源包
if (depLen > 0)
{
entity.ListDependsAsset = new List();
//对依赖的资源包进行循环
for (int j = 0; j < depLen; ++j)
{
AssetDependsEntity assetDependsEntity = new AssetDependsEntity();
assetDependsEntity.Category = (AssetCategory)ms.ReadByte();
assetDependsEntity.AssetFullName = ms.ReadUTF8String();
entity.ListDependsAsset.Add(assetDependsEntity);
}
}
m_dicAssetInfo[entity.Category][entity.AssetFullName] = entity;
}
m_InitAssetInfoComplete?.Invoke();
}
//从CDN加载资源信息
private void OnLoadAssetInfoFromCDN(HttpCallBackArgs args)
{
if (!args.HasError)
{
InitAssetInfo(args.Data);
}
else
{
GameEntry.Log(LogCategory.Resource, args.Value);
}
}
#region 初始化资源信息
//初始化资源信息
public void InitAssetInfo(BaseAction initAssetInfoComplete)
{
m_InitAssetInfoComplete = initAssetInfoComplete;
//资源信息?
byte[] buffer = GameEntry.Resource.ResManager.LocalAssetsManager.GetFileBuffer(ConstDefine.AssetInfoName);
if (buffer == null)
{
//如果只读区没有,从CDN读
string url = string.Format("{0}{1}", GameEntry.Data.SysDataManager.CurrChannelConfig.RealSourceUrl, ConstDefine.AssetInfoName);
GameEntry.Http.SendData(url, OnLoadAssetInfoFromCDN, isGetData: true);
}
else
{
InitAssetInfo(buffer);
}
}
//根据资源分类和资源路径 获取资源信息
public AssetEntity GetAssetEntity(AssetCategory assetCategory, string assetFullName)
{
Dictionary dicCategory = null;
if (m_dicAssetInfo.TryGetValue(assetCategory, out dicCategory))
{
AssetEntity entity = null;
if (dicCategory.TryGetValue(assetFullName, out entity))
{
return entity;
}
}
return null;
}
#endregion
#endregion
#region 加载资源包 LoadAssetBundle
//加载中的资源包
//{资源包名:加载资源包完成的回调list}
///
/// 加载资源包
///
/// ab包路径
/// 加载中回调
/// 加载完成回调
public void LoadAssetBundle(string assetBundlePath, Action onUpdate = null, Action onComplete = null)
{
//1.判断资源包是否存在于AssetBundlePool中
ResourceEntity resourceEntity = GameEntry.Pool.AssetBundlePool.Spawn(assetBundlePath);
//资源在资源包池中 存在
if (resourceEntity != null)
{
AssetBundle assetBundle = resourceEntity.Target as AssetBundle;
onComplete?.Invoke(assetBundle);
return;
}
//资源在资源包池中 不存在
LinkedList> lst = null;
if (m_dicLoadingAssetBundle.TryGetValue(assetBundlePath, out lst))
{
//如果存在加载中的assetbundle,把加载完成的回调函数 加入这个资源加载的链表,然后返回
lst.AddLast(onComplete);
return;
}
else
{
lst = GameEntry.Pool.DequeueClassObject>>();
lst.AddLast(onComplete);
m_dicLoadingAssetBundle[assetBundlePath] = lst;
}
//资源包加载routine
AssetBundleLoaderRoutine routine = GameEntry.Pool.DequeueClassObject();
//这句话可以不加,Dequeue的时候如果没有一定会new一个
if (null == routine)
{
routine = new AssetBundleLoaderRoutine();
}
//加入链表还是循环加载
m_ListAssetBundleLoader.AddLast(routine);
//开始加载assetBundle
routine.LoadAssetBundle(assetBundlePath);
//注册更新回调
routine.OnAssetBundleCreateUpdate = (float progress) =>
{
onUpdate?.Invoke(progress);
};
routine.OnLoadAssetBundleComplete = (AssetBundle assetBundle) =>
{
//把资源包注册到资源池
resourceEntity = GameEntry.Pool.DequeueClassObject();
resourceEntity.ResourceName = assetBundlePath;
resourceEntity.IsAssetBundle = true;
resourceEntity.Target = assetBundle;
GameEntry.Pool.AssetBundlePool.Register(resourceEntity);
//加载完成后,执行所有回调函数
for (LinkedListNode> iter = lst.First; iter != null; iter = iter.Next)
{
iter.Value?.Invoke(assetBundle);
}
//一定要清空
lst.Clear();
GameEntry.Pool.EnqueueClassObject(lst);
//下载完成后,从下载中字段中清除这个字典
m_dicLoadingAssetBundle.Remove(assetBundlePath);
//结束循环 routine回池
m_ListAssetBundleLoader.Remove(routine);
GameEntry.Pool.EnqueueClassObject(routine);
};
}
#endregion
#region 从资源包中加载资源 LoadAsset
/// 资源名
/// assetBundle包
/// 加载中回调
/// 加载完成回调
public void LoadAsset(string assetName, AssetBundle assetBundle, Action onUpdate = null, Action onComplete = null)
{
LinkedList> lst = null;
//这个资源在加载中
if (m_dicLoadingAsset.TryGetValue(assetName, out lst))
{
//把加载完成回调函数(委托)加入到对应的链表中,然后直接返回
lst.AddLast(onComplete);
return;
}
else
{
//如果不在加载中
//从类对象池取一个对象,把链表保存到字典中
lst = GameEntry.Pool.DequeueClassObject>>();
lst.AddLast(onComplete);
m_dicLoadingAsset[assetName] = lst;
}
AssetLoaderRoutine routine = GameEntry.Pool.DequeueClassObject();
if (routine == null)
routine = new AssetLoaderRoutine();
m_ListAssetLoader.AddLast(routine);
//开始加载资源
routine.LoadAsset(assetName, assetBundle);
//下载中更新回调
routine.OnAssetUpdate = (float progress) =>
{
onUpdate?.Invoke(progress);
};
//下载完成回调
routine.OnLoadAssetComplete = (UnityEngine.Object obj) =>
{
for (LinkedListNode> iter = lst.First; iter != null; iter = iter.Next)
{
iter.Value?.Invoke(obj);
}
//一定要清空
lst.Clear();
//链表回池
GameEntry.Pool.EnqueueClassObject(lst);
//资源对应的链表从字典删除
m_dicLoadingAsset.Remove(assetName);
//结束循环
m_ListAssetLoader.Remove(routine);
//资源加载器回池
GameEntry.Pool.EnqueueClassObject(routine);
};
}
#endregion
///
/// 加载主资源
///
/// 资源分类
/// 资源完整名称
/// 加载完成回调
public void LoadMainAsset(AssetCategory assetCategory, string assetFullName, BaseAction onComplete = null)
{
MainAssetLoaderRoutine routine = GameEntry.Pool.DequeueClassObject();
//加载
routine.LoadAsset(assetCategory, assetFullName,(ResourceEntity resEntity)=>
{
onComplete?.Invoke(resEntity);
});
}
//释放资源
public void UnLoadGameObject(GameObject go)
{
GameEntry.Pool.ReleaseInstanceResource(go.GetInstanceID());
}
// 更新所有 AssetBundleLoaderRoutine
// 更新所有 AssetLoaderRoutine
public void OnUpdate()
{
for (LinkedListNode iter = m_ListAssetBundleLoader.First; iter!=null; iter= iter.Next)
{
iter.Value.OnUpdate();
}
for (LinkedListNode iter = m_ListAssetLoader.First; iter != null; iter = iter.Next)
{
iter.Value.OnUpdate();
}
}
public void Dispose()
{
m_dicAssetInfo.Clear();
m_ListAssetBundleLoader.Clear();
m_ListAssetLoader.Clear();
}
}
}