1.AssetLoader
/****************************************************
文件:AssetLoader.cs
作者:赵深圳
邮箱: 1329346609@qq.com
日期:2022/5/9 10:39:33
功能:资源加载器
*****************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// 资源加载器
/// </summary>
public class AssetLoader : Singleton<AssetLoader>
{
/// <summary>
/// 平台对应的只读路径下的资源
/// key 模块名字
/// value 模块下所有的资源
/// </summary>
public Dictionary<string, Hashtable> base2Assets;
public AssetLoader()
{
base2Assets = new Dictionary<string, Hashtable>();
}
/// <summary>
/// 加载模块对应的全局AssetBundle资源管理文件
/// </summary>
/// <param name="moduleConfig">模块名字</param>
/// <param name="onCompelte">加载完成后的回调</param>
public async Task<ModuleABConfig> LoadAssetBundleConfig(string moduleName)
{
#if UNITY_EDITOR
if (GlobalConfig.BundleMode == false)
{
return null;
}
else
{
return await LoadAssetBundleConfig_Runtime(moduleName);
}
#else
return await LoadAssetBundleConfig_Runtime(moduleName);
#endif
}
/// <summary>
/// 加载本地的模块的AB配置文件
/// </summary>
/// <param name="moudleName">模块的名字</param>
/// <returns></returns>
public async Task<ModuleABConfig> LoadAssetBundleConfig_Runtime(string moudleName)
{
string url = Application.streamingAssetsPath + "/" + moudleName + "/" + moudleName.ToLower() + ".json";
UnityWebRequest request = UnityWebRequest.Get(url);
await request.SendWebRequest();
if (string.IsNullOrEmpty(request.error))
{
return LitJson.JsonMapper.ToObject<ModuleABConfig>(request.downloadHandler.text);
}
return null;
}
/// <summary>
/// 根据模块的json文件创角内存中资源管理器
/// </summary>
/// <param name="moduleABConfig"></param>
/// <returns></returns>
public Hashtable ConfigAssembly(ModuleABConfig moduleABConfig)
{
//根据ab配置文件,得到所有的bundleinfo,并转换成bundlRef
Dictionary<string, BundleRef> name2BundleRef = new Dictionary<string, BundleRef>();
foreach (KeyValuePair<string,BundleInfo> keyValue in moduleABConfig.BundleInfoDic)
{
string bundleName = keyValue.Key;
BundleInfo bundleInfo = keyValue.Value;
name2BundleRef[bundleName] = new BundleRef(bundleInfo);
}
Hashtable path2AssetRef = new Hashtable();
//获取所有Asset资源信息
for (int i = 0; i < moduleABConfig.AssetInfoArr.Length; i++)
{
AssetInfo assetInfo = moduleABConfig.AssetInfoArr[i];
AssetRef assetRef = new AssetRef(assetInfo);
assetRef.bundleRef = name2BundleRef[assetInfo.bundle_name];
int count = assetInfo.dependenciesLst.Count;
assetRef.dependencies = new BundleRef[count];
for (int index = 0; index < count; index++)
{
string bundleName = assetInfo.dependenciesLst[index];
assetRef.dependencies[index] = name2BundleRef[bundleName];
}
path2AssetRef.Add(assetInfo.asset_path,assetRef);
}
return path2AssetRef;
}
/// <summary>
/// 加载游戏对象
/// </summary>
/// <param name="moduleName">模块名字</param>
/// <param name="path">游戏对象的相对路径</param>
/// <returns></returns>
public GameObject Clone(string moduleName,string path)
{
//获取当前路径资源所在内存中信息
AssetRef assetRef= LoadAssetRef<GameObject>(moduleName,path);
if (assetRef==null||assetRef.asset==null)
{
return null;
}
//实例化资源
GameObject gameObject = UnityEngine.Object.Instantiate(assetRef.asset) as GameObject;
if (assetRef.children==null)
{
assetRef.children = new List<GameObject>();
}
//把当前实例化资源加入到加入到Asset的被依赖列表中
assetRef.children.Add(gameObject);
return gameObject;
}
/// <summary>
/// 加载AssetRef对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="moduleName">模块名字</param>
/// <param name="assetPath">资源的相对路径</param>
/// <returns></returns>
private AssetRef LoadAssetRef<T>(string moduleName, string assetPath) where T : UnityEngine.Object
{
#if UNITY_EDITOR
if (GlobalConfig.BundleMode == false)
{
return LoadAssetRef_Editor<T>(moduleName, assetPath);
}
else
{
return LoadAssetRef_Runtime<T>(moduleName,assetPath);
}
#else
return LoadAssetRef_Runtime<T>(moduleName,assetPath);
#endif
}
/// <summary>
/// 编译器模式下加载AssetRef对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="moduleName">模块名字</param>
/// <param name="assetPath">资源的相对路径</param>
/// <returns></returns>
private AssetRef LoadAssetRef_Editor<T>(string moduleName, string assetPath) where T : UnityEngine.Object
{
#if UNITY_EDITOR
if (string.IsNullOrEmpty(assetPath))
{
return null;
}
AssetRef assetRef = new AssetRef(null);
assetRef.asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);
return assetRef;
#else
return null;
#endif
}
/// <summary>
/// AB包模式下加载的AssetRef对象
/// </summary>
/// <typeparam name="T">要加载的资源类型</typeparam>
/// <param name="moduleName">模块名字</param>
/// <param name="assetPath">资源的相对路径</param>
/// <returns></returns>
private AssetRef LoadAssetRef_Runtime<T>(string moduleName, string assetPath) where T : UnityEngine.Object
{
if (string.IsNullOrEmpty(assetPath))
{
return null;
}
Hashtable module2AssetRef;
//得到这个模块的所有资源集合
bool moduleExsit = base2Assets.TryGetValue(moduleName,out module2AssetRef);
if (moduleExsit==false)
{
Debug.LogError("未找到资源对应模块:moduleName="+moduleName+"assetPath="+assetPath);
return null;
}
//得到资源中内存对象
AssetRef assetRef = (AssetRef)module2AssetRef[assetPath];
if (assetPath==null)
{
Debug.LogError("未找到资源:moduleName=" + moduleName + "assetPath=" + assetPath);
return null;
}
//如果已经加载直接返回
if (assetRef.asset!=null)
{
return assetRef;
}
//处理AssetRef依赖的BundleRef列表
foreach (BundleRef oneBundleRef in assetRef.dependencies)
{
if (oneBundleRef.bundle==null)//判断当前依赖项的bundle有没有被加载
{
string bundlePath = BundlePath(moduleName,oneBundleRef.bundleInfo.bundle_name);
//加载当前依赖项的bundle
oneBundleRef.bundle = AssetBundle.LoadFromFile(bundlePath);
}
if (oneBundleRef.chilren==null)
{
oneBundleRef.chilren = new List<AssetRef>();
}
//设置依赖项的被依赖资源列表,把自己加入到依赖项的被依赖的资源列表中
oneBundleRef.chilren.Add(assetRef);
}
//处理assetRef属于哪个BundleRef对象
//判断自己所属的Bundle有没有被加载
BundleRef bundleRef = assetRef.bundleRef;
if (bundleRef.bundle==null)
{
//加载自身所在的AB包
bundleRef.bundle = AssetBundle.LoadFromFile(BundlePath(moduleName,bundleRef.bundleInfo.bundle_name));
}
//把自己加到自己所属的Bundle的被依赖资源列表中
if (bundleRef.chilren==null)
{
bundleRef.chilren = new List<AssetRef>();
}
bundleRef.chilren.Add(assetRef);
//从bundle中提取asset
assetRef.asset = assetRef.bundleRef.bundle.LoadAsset<T>(assetRef.assetInfo.asset_path);
if (typeof(T) == typeof(GameObject) && assetRef.assetInfo.asset_path.EndsWith(".prefab"))
{
assetRef.isGameObject = true;
}
else {
assetRef.isGameObject = false;
}
return assetRef;
}
/// <summary>
/// 创建资源对象
/// </summary>
/// <typeparam name="T">资源类型</typeparam>
/// <param name="moduleName">模块名字</param>
/// <param name="assetPath">资源路径</param>
/// <param name="gameObject">资源加载后,所挂载到的游戏对象</param>
/// <returns></returns>
public T CreateAsset<T>(string moduleName, string assetPath, GameObject gameObject) where T : UnityEngine.Object
{
if (typeof(T)==typeof(GameObject)||(!string.IsNullOrEmpty(assetPath)&&assetPath.EndsWith(".prefab")))
{
Debug.LogError("不可以加载GameObject类型,请直接使用AssetLoader.Instance.Clone接口,path:"+assetPath);
return null;
}
if (gameObject==null)
{
Debug.LogError("CreateAsset必须传递一个gameObject其将要被挂载的GameObject对象!");
return null;
}
AssetRef assetRef = LoadAssetRef<T>(moduleName,assetPath);
if (assetRef==null||assetRef.asset==null)
{
return null;
}
if (assetRef.children==null)
{
assetRef.children = new List<GameObject>();
}
assetRef.children.Add(gameObject);
return assetRef.asset as T;
}
public void Unload(Dictionary<string,Hashtable> module2Assets)
{
foreach (string moduleName in module2Assets.Keys)
{
Hashtable path2AssetRef = module2Assets[moduleName];
if (path2AssetRef==null)
{
continue;
}
foreach (AssetRef assetRef in path2AssetRef.Values)
{
if (assetRef.children==null||assetRef.children.Count==0)
{
continue;
}
for (int i = assetRef.children.Count - 1; i >= 0; i--)
{
GameObject go = assetRef.children[i];
if (go==null)
{
assetRef.children.RemoveAt(i);
}
}
//如果当前资源没有被任何GameObject所依赖,那么就可以卸载了
if (assetRef.children.Count==0)
{
assetRef.asset = null;
Resources.UnloadUnusedAssets();
//对于assetRef所属的bundle 解除关系
assetRef.bundleRef.chilren.Remove(assetRef);
if (assetRef.bundleRef.chilren.Count==0)
{
assetRef.bundleRef.bundle.Unload(true);
}
//对于assetRef所依赖的那些bundle列表,解除关系
foreach (BundleRef bundleRef in assetRef.dependencies)
{
bundleRef.chilren.Remove(assetRef);
if (bundleRef.chilren.Count==0)
{
bundleRef.bundle.Unload(true);
}
}
}
}
}
}
/// <summary>
/// 工具函数,根据模块名字和bundle名字,返回其实际资源路径
/// </summary>
/// <param name="moduleName">模块名字</param>
/// <param name="bundleName">bundle名字</param>
/// <returns></returns>
private string BundlePath(string moduleName,string bundleName)
{
return Application.streamingAssetsPath + "/" + moduleName + "/" + bundleName;
}
}
2.GameEntry
/****************************************************
文件:GameEntry.cs
作者:赵深圳
邮箱: 1329346609@qq.com
日期:2022/5/9 10:43:14
功能:游戏启动入口
*****************************************************/
using UnityEngine;
public class GameEntry : MonoBehaviour
{
public static GameEntry Instance;
private async void Awake()
{
InitGlobal();
//启动模块
ModuleConfig launchModule = new ModuleConfig
{
moduleName="launch",
moduleVersion="202205091051",
moduleUrl="127.0.0.1"
};
bool result= await ModuleManager.Instance.Load(launchModule);
if (result)
{
Log.ZSZLog(LogCategory.Resource,"Lua 代码开始");
}
}
private void InitGlobal()
{
Instance = this;
GlobalConfig.HotUpdate = false;
GlobalConfig.BundleMode = false;
DontDestroyOnLoad(this.gameObject);
}
private void Update()
{
AssetLoader.Instance.Unload(AssetLoader.Instance.base2Assets);
}
}