目录
正文
上一篇文章降到了开启加载任务,本篇文章先展示加载任务相关的所有代码
加载任务有3部分代码,
- LoadTaskManager维护所有加载任务
- 编辑器模式EditorLoadTask
- AssetBundle模式ABLoadTask
LoadTaskManager:
using System;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using System.Linq;
#endif
using UnityEngine;
public class LoadTaskManager:Singleton<LoadTaskManager>
{
#if UNITY_EDITOR
public Dictionary<string, EditorLoadTask> _allEditorLoadTask = new Dictionary<string, EditorLoadTask>();
#endif
public Dictionary<string, ABLoadTask> _allABLoadTask = new Dictionary<string, ABLoadTask>();
/// <summary>
/// 初始化接口
/// </summary>
/// <param name="root"></param>
public void Init()
{
}
public void CreateLoadTask(AssetLoaderBase loader, Action<UnityEngine.Object, bool> callback,Type t)
{
//只有编辑器才要考虑是否用AB
#if UNITY_EDITOR
//GameSetting.Instance == null说明配置文件还没加载
if (GameSetting.Instance == null || !GameSetting.Instance.AssetbundleMode)//不用AB,直接加载
{
EditorLoadTask task = new EditorLoadTask();
_allEditorLoadTask.Add(loader._resPath, task);
task.StartTask(loader._resPath, callback, t);
return;
}
#endif
{
//Editor模拟AB和正常的AB加载走这里
ABLoadTask task = GetABLoadTask(loader._resPath, out bool hasBundle);
if (hasBundle == false)
task.StartTask(loader._resPath, callback, t);
}
}
public ABLoadTask GetABLoadTask(string loadPath, out bool hasBundle, bool isDepend = false)
{
ABLoadTask task;
if (_allABLoadTask.TryGetValue(loadPath, out task))
{
//Debug.Log("GetABLoadTask,已存在path: " + loadPath);
if (isDepend)
task.Reference();
hasBundle = true;
}
else
{
//Debug.Log("GetABLoadTask,不存在,创建 path: " + loadPath);
task = new ABLoadTask();
task._bundleLoadPath = loadPath;
_allABLoadTask.Add(loadPath, task);
hasBundle = false;
}
return task;
}
public void Tick(float deltaTime)
{
#if UNITY_EDITOR
for (int i = 0; i < _allEditorLoadTask.Count; i++)
{
var item = _allEditorLoadTask.ElementAt(i);
item.Value.Tick();
}
#endif
foreach (var task in _allABLoadTask)
{
task.Value.Tick();
}
}
public void UnLoadNoUseBundle()
{
}
}
ABLoadTask
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class ABLoadTask:LoadTaskBase
{
//AB的所有依赖
private List<ABLoadTask> _depends = new List<ABLoadTask>(10);
//
public string _bundleLoadPath;
//
private AssetBundleCreateRequest _bundleRequest;
//
private AssetBundleRequest _assetRequest;
private AssetBundle _bundle;
//引用次数
private int RefCount;
//资源名
protected string _assetName;
public override void DoTask()
{
int lastPoint = _loadResPath.LastIndexOf(".");
int lastXieGang = _loadResPath.LastIndexOf("/");
string extension = _loadResPath.Substring(lastPoint);
//无扩展的路径
string notExtPath = _loadResPath.Substring(0, lastPoint);
//保存文件名,带类型
_assetName = _loadResPath.Substring(lastXieGang + 1, lastPoint - lastXieGang - 1) + extension;
//小写路径
_bundleLoadPath = "assets/works/res/" + notExtPath.ToLower() + ".unity3d";
StartLoadBundle(Application.streamingAssetsPath + "/" + _bundleLoadPath);
}
public void StartLoadBundle(string path)
{
if (GameSetting.Instance.LoadBundleAsync)
{
LogManager.LogProcedure("StartLoadBundle Async:" + path);
_bundleRequest = AssetBundle.LoadFromFileAsync(path);
_bundleRequest.completed += LoadBundleComplete;
_loadState = TaskLoadState.LoadingBundle;
}
else
{
LogManager.LogProcedure("StartLoadBundle:" + path);
_bundle = AssetBundle.LoadFromFile(path);
_loadState = TaskLoadState.LoadBundleSuccess;
}
SetDependencies();
}
private void LoadBundleComplete(AsyncOperation op)
{
if (op.isDone)
{
if (_loadState == TaskLoadState.UnLoadBundle)
{
_bundleRequest.assetBundle.Unload(false);
return;
}
//LogManager.LogInfo("LoadBundleComplete,path:" + _bundleLoadPath);
_bundle = _bundleRequest.assetBundle;
_loadState = TaskLoadState.LoadBundleSuccess;
}
}
//设置依赖Loader
public void SetDependencies()
{
string[] allDepends = AssetBundleManager.Instance.GetBundleDepends(_bundleLoadPath);
for (int i = 0; i < allDepends.Length; i++)
{
//LogManager.LogProcedure($"_bundleLoadPath:{_bundleLoadPath} 存在依赖: {allDepends[i]}");
//创建依赖并添加依赖
ABLoadTask task = LoadTaskManager.Instance.GetABLoadTask(allDepends[i], out bool hasBundle, true);
task._depends.Add(task);
task._bundleLoadPath = allDepends[i];
if (hasBundle == false)
task.StartLoadBundle(Application.streamingAssetsPath + "/" + allDepends[i]);
}
}
//递归检查依赖包是否全部完成
public bool IsDone()
{
if (_depends.Count == 0)//无依赖证明是最底层的Bundle
return _loadState == TaskLoadState.LoadBundleSuccess;
else
{
//检查本包的所有依赖,只要有一个未完成,则直接返回未完成
for (int i = 0; i < _depends.Count; i++)
{
if (_depends[i].IsDone() == false)
{
return false;
}
return true;
}
}
return false;
}
/// <summary>
/// 引用(引用计数递加)
/// </summary>
public virtual void Reference()
{
RefCount++;
}
/// <summary>
/// 释放(引用计数递减)
/// </summary>
public virtual void DeReference()
{
RefCount--;
}
//卸载此包,递归删除引用
public void UnLoadBundle()
{
for (int i = 0; i < _depends.Count; i++)
{
_depends[i].DeReference();
_depends[i].UnLoadBundle();
}
if (RefCount <= 0)
{
_loadState = TaskLoadState.UnLoadBundle;
_bundleRequest.assetBundle.Unload(false);
}
}
public override void Tick()
{
//_assetName不空表示是主包,非依赖包
if (_loadState == TaskLoadState.LoadBundleSuccess && !string.IsNullOrEmpty(_assetName))
{
if (IsDone() == true)//所有依赖全部加载完成
{
//Debug.LogError("AB包及依赖加载完成:" + _loadResPath);
if (_targetType == typeof(Scene))
{
_loadState = TaskLoadState.LoadAssetSuccess;
_callback?.Invoke(null, true);
}
else
{
_loadState = TaskLoadState.LoadingAsset;
if (GameSetting.Instance.LoadAssetAsync)
{
if (_targetType == null)
_assetRequest = _bundle.LoadAssetAsync(_assetName);
else
_assetRequest = _bundle.LoadAssetAsync(_assetName, _targetType);
_assetRequest.completed += LoadAssetCallback;
}
else
{
if (_targetType == null)
_target = _bundle.LoadAsset(_assetName);
else
_target = _bundle.LoadAsset(_assetName, _targetType);
CheckAsset();
}
}
}
}
}
/// <summary>
/// 所有依赖包加载完成后,加载Asset资源
/// </summary>
/// <param name="op"></param>
private void LoadAssetCallback(AsyncOperation op)
{
if (op.isDone)
{
//LogManager.LogProcedure("LoadAssetCallback,assetName:" + _assetName);
_target = _assetRequest.asset;
CheckAsset();
}
}
private void CheckAsset()
{
if (_target != null)
_loadState = TaskLoadState.LoadAssetSuccess;
else
_loadState = TaskLoadState.LoadAssetFailed;
// 通知Loader加载结果
_callback?.Invoke(_target, _target != null);
}
}
EditorLoadTask
#if UNITY_EDITOR
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
public class EditorLoadTask:LoadTaskBase
{
/*
* 使用方式:
* "Works/Res/Prefabs/UIPanel/Canvas.prefab"
* 要带着文件扩展名
*/
public override void DoTask()
{
string path = "Assets/Works/Res/" + _loadResPath;
if (_targetType != typeof(Scene))
_target = AssetDatabase.LoadAssetAtPath(path, _targetType);
//模拟异步下一帧加载
_loadState = TaskLoadState.LoadingAsset;
}
public override void Tick()
{
if (_loadState != TaskLoadState.LoadingAsset)
return;
if (_targetType == typeof(Scene))
{
LoadSceneParameters parameters = new LoadSceneParameters() { loadSceneMode = LoadSceneMode.Single, localPhysicsMode = LocalPhysicsMode.None };
AsyncOperation asyncOperation = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneAsyncInPlayMode("Assets/" + _loadResPath, parameters);
//Scene scene = UnityEditor.SceneManagement.EditorSceneManager.GetSceneByPath("Assets/" + _loadResPath, parameters);
Scene scene = UnityEditor.SceneManagement.EditorSceneManager.GetSceneByPath("Assets/" + _loadResPath);
if (scene == null) {
_loadState = TaskLoadState.LoadAssetFailed;
//通知ResourceLoader加载成功或失败
_callback?.Invoke(null, false);
}
else
{
_loadState = TaskLoadState.LoadAssetSuccess;
//通知ResourceLoader加载成功或失败
_callback?.Invoke(null, true);
}
}
else
{
_loadState = _target == null ? TaskLoadState.LoadAssetFailed : TaskLoadState.LoadAssetSuccess;
if (_loadState == TaskLoadState.LoadAssetFailed)
LogManager.LogError($"Failed to load asset object : path:{_loadResPath}, type:{_targetType.ToString()}");
通知Loader加载结果
_callback?.Invoke(_target, _target != null);
}
}
}
#endif
LoadTaskBase
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum TaskLoadState
{
None = 0,
LoadingBundle = 1,
LoadBundleSuccess = 2,
LoadingAsset = 3,//LoadingAsset状态 //AB模式代表AB及依赖已全部加载完成,Editor模式下一帧加载
LoadAssetSuccess = 4,
LoadAssetFailed = 5,
UnLoadBundle = 6,
}
public abstract class LoadTaskBase
{
protected string _loadResPath;
protected TaskLoadState _loadState;
protected Action<UnityEngine.Object, bool> _callback;
protected Type _targetType;
//目标类型
protected UnityEngine.Object _target;
public void StartTask(string loadResPath,Action<UnityEngine.Object, bool> callback,Type t)
{
_loadResPath = loadResPath;
_targetType = t;
_loadState = TaskLoadState.LoadingBundle;
_callback = callback;
DoTask();
}
/// <summary>
/// 交给子类去完成任务
/// </summary>
public abstract void DoTask();
public abstract void Tick();
}