using UnityEngine; using System.Collections; using System.Collections.Generic; using System.IO; using System; using UnityEngine.Networking; public enum E_AssetBundleLoadType { /// /// www方式异步加载 /// WWW = 0, /// /// LoadFromFile方式异步加载 /// LoadFromFileAsync = 1, /// /// LoadFromFile方式同步加载 /// LoadFromFileSynchro = 2, /// /// 网络加载 /// NetUrlMode = 3, /// /// 新版资源包加载方式 /// NewAssetBundle = 4, } /// /// 资源管理器 /// By WJ 2019-12-12 09:03:30 /// public class ResourceHelper : MonoSingleton { /// /// 正在加载的相同AssetBundle列表 /// private Dictionary>> mSameAssetBundleAcList = new Dictionary>>(); /// /// 已加载的AssetBundle /// private Dictionary mAssetBundleList = new Dictionary(); /// /// 正在加载的资源名称列表 /// private List mLoadingAssetList = new List(); /// /// 加载进度 /// private float mLoadProgress = 0; /// /// 超时时间 /// private float mTimeOutTime = 0; #region 新版加载方式 /// /// 主文件 /// private AssetBundleManifest abManifest = null; /// /// 主文件请求 /// private AssetBundle manifesAssetBundle = null; /// /// 资源包的请求 /// private Dictionary loadNewAssetBundles = new Dictionary(); /// /// 资源包后缀 /// private static string AssetBundleSuffix = ".unity3d"; #endregion ///// ///// 加载资源 ///// ///// 名称 ///// 加载完成后的回调 ///// 同一文件是否支持多重加载,false时同一时间只会加载一份 ///// 加载的类型,默认LoadFromFile异步加载 //public void LoadAssetBundle(string _name, Action ac, bool multiLoad = true, E_AssetBundleLoadType type = E_AssetBundleLoadType.LoadFromFileAsync) //{ // switch (type) // { // case E_AssetBundleLoadType.WWW: // LoadAssetBundleWWW(_name, ac, multiLoad); // break; // case E_AssetBundleLoadType.LoadFromFileAsync: // LoadAssetBundleAsync(_name, ac, multiLoad); // break; // case E_AssetBundleLoadType.LoadFromFileSynchro: // LoadAssetBundleSynchro(_name, ac); // break; // //case E_AssetBundleLoadType.NetUrlMode: // // LoadAssetBundleUrl(_name, ac); // // break; // //case E_AssetBundleLoadType.NewAssetBundle: // // LoadAssetBundleNew(_name, ac); // // break; // } //} /// /// 新版加载资源包 /// /// 所属类型名称 /// 加载的资源名称 /// 加载完成的回调 public void LoadAssetBundle(string resName, Action ac = null) { if (string.IsNullOrEmpty(resName)) { return; } string assetBundleName = resName.ToLower() + AssetBundleSuffix; string mainPath = GetNewPath("", ""); if (manifesAssetBundle == null) { manifesAssetBundle = AssetBundle.LoadFromFile(mainPath + "NewRes"); } // 加载主文件 if (abManifest == null) { abManifest = manifesAssetBundle.LoadAsset("assetbundlemanifest"); } var hash = abManifest.GetAssetBundleHash(assetBundleName); // 新版资源,查找依赖 if (hash.isValid) { Debug.Log(resName+"存在依赖关系,使用新版加载方式"); // 再查找依赖资源包加载并创建 string[] strs = abManifest.GetAllDependencies(assetBundleName); foreach (var itemName in strs) { if (loadNewAssetBundles.ContainsKey(itemName) == false) { try { AssetBundle ylAssetBundle = AssetBundle.LoadFromFile(mainPath + itemName); loadNewAssetBundles.Add(itemName, ylAssetBundle); } catch (Exception e) { UI_CueDialog.Instance().Open("加载异常:" + e.Message); } } } } // 旧版资源包,用正常名称 else { Debug.Log(resName + "不存在依赖关系,使用旧版加载方式"); assetBundleName = resName + AssetBundleSuffix; } if (loadNewAssetBundles.ContainsKey(assetBundleName) == false) { // 最后再加载并创建自身资源包 AssetBundle ab = AssetBundle.LoadFromFile(mainPath + assetBundleName); loadNewAssetBundles.Add(assetBundleName, ab); if (ac == null) { GameObject go = ab.LoadAsset(resName); if (go != null) { Instantiate(go); } } else { ac(ab); } } else { AssetBundle ab = loadNewAssetBundles[assetBundleName]; if (ac == null) { GameObject go = ab.LoadAsset(resName); if (go != null) { Instantiate(go); } } else { ac(ab); } } } /// /// 获取加载进度 /// /// public float GetLoadProgress() { return mLoadProgress; } ///// ///// 加载网络资源 ///// ///// ///// ///// //private void LoadAssetBundleUrl(string _name, Action ac) //{ // if (_name == string.Empty) // { // ac(null); // return; // } // if (mAssetBundleList.ContainsKey(_name)) // { // ac(mAssetBundleList[_name]); // } // else // { // if (mLoadingAssetList.Contains(_name) == false) // { // mLoadingAssetList.Add(_name); // StartCoroutine(IELoadAssetBundleUrl(_name, ac)); // } // else // { // if (mSameAssetBundleAcList.ContainsKey(_name)) // { // if (mSameAssetBundleAcList[_name].Contains(ac) == false) // { // mSameAssetBundleAcList[_name].Add(ac); // } // } // else // { // List> acList = new List>(); // acList.Add(ac); // mSameAssetBundleAcList.Add(_name, acList); // } // } // } //} ///// ///// 协同加载网络资源 ///// ///// ///// ///// ///// //IEnumerator IELoadAssetBundleUrl(string _name, Action ac, string fileSuffix = ".unity3d") //{ // // 重新加载 // bool reLoad = true; // while (reLoad) // { // string url = ""; // uint version = 0; // string streamingAssetsPath = Application.streamingAssetsPath + "/Res/" + _name + fileSuffix; // if (Launcher.netUpdateFileInfo != null) // { // if (Application.isEditor && File.Exists(streamingAssetsPath)) // { // url = "file://" + streamingAssetsPath; // } // else // { // if (RuntimePlatform.IPhonePlayer == Application.platform) // { // url = Launcher.netUrl + "UpdateAndroid/" + _name + fileSuffix; // } // else // { // url = Launcher.netUrl + "UpdateAndroid/" + _name + fileSuffix; // } // } // foreach (FileMD5Info info in Launcher.netUpdateFileInfo.Infos) // { // if (info.Name == _name + fileSuffix) // { // if(info.PackSizeM >= 1) // { // UI_LoadingWindow.Instance().Show(1); // } // version = (uint)info.PackVersion; // break; // } // } // } // else // { // version = Launcher.netVersion; // } // UnityWebRequest request = null; // // 编辑器下,有工程资源,不走缓存机制 // if (Application.isEditor && File.Exists(streamingAssetsPath)) // { // request = UnityWebRequestAssetBundle.GetAssetBundle(url); // } // else // { // request = UnityWebRequestAssetBundle.GetAssetBundle(url, version, 0); // } // yield return request.SendWebRequest(); // // 加载完成,移除正在加载的资源 // mLoadingAssetList.Remove(_name); // // 等待加载完成 // while (request.isDone == false) // { // yield return new WaitForSeconds(0.05f); // } // // 没有错误 // if (request.error == null) // { // AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; // mAssetBundleList.Add(_name, ab); // if (ac != null) // { // ac(ab); // } // reLoad = false; // // 关闭Loading // if (mLoadingAssetList.Count == 0) // { // UI_LoadingWindow.Instance().Hide(1); // } // // 返回相同AC // if (mSameAssetBundleAcList.ContainsKey(_name)) // { // for (int i = 0; i < mSameAssetBundleAcList[_name].Count; i++) // { // mSameAssetBundleAcList[_name][i](ab); // } // mSameAssetBundleAcList[_name].Clear(); // } // } // else // { // bool waiting = false; // if (request.isNetworkError) // { // // 不可写入 // if (request.error == "Unable to write data") // { // reLoad = false; // } // else // { // reLoad = true; // waiting = true; // UI_CueDialog.Instance().Open("加载" + _name + " 失败,是否重试?", "", E_DialogType.TwoBntton, () => // { // // 同意的回调 // waiting = false; // }, () => // { // // 取消的回调 // Application.Quit(); // }); // } // } // else if (request.isHttpError) // { // reLoad = true; // waiting = true; // UI_CueDialog.Instance().Open("加载" + _name + " 失败,是否重试?", "", E_DialogType.TwoBntton, () => // { // // 同意的回调 // waiting = false; // }, () => // { // // 取消的回调 // Application.Quit(); // }); // } // Debug.LogError(_name + " 加载错误: " + request.error); // while (waiting) // { // yield return new WaitForSeconds(0.1f); // } // // 不重新加载,则返回回调 // if (reLoad == false) // { // if (ac != null) // { // ac(null); // } // // 关闭Loading // UI_LoadingWindow.Instance().Hide(1); // } // } // } //} /// /// WWW加载AssetBundle /// /// 名称,不包含后缀 /// Lambda返回值 private void LoadAssetBundleWWW(string _name, Action ac, bool multiLoad = true) { if (_name == string.Empty) { ac(null); return; } if (mAssetBundleList.ContainsKey(_name)) { ac(mAssetBundleList[_name]); } else { if (mLoadingAssetList.Contains(_name) == false) { mLoadingAssetList.Add(_name); StartCoroutine(IELoadAssetBundleWWW(_name, ac, multiLoad)); } else { if (mSameAssetBundleAcList.ContainsKey(_name)) { if (mSameAssetBundleAcList[_name].Contains(ac) == false) { mSameAssetBundleAcList[_name].Add(ac); } } else { List> acList = new List>(); acList.Add(ac); mSameAssetBundleAcList.Add(_name, acList); } } } } /// /// 协同加载AssetBundle /// /// 名称,不包含后缀 /// Lambda返回值 /// 返回资源AssetBundle private IEnumerator IELoadAssetBundleWWW(string _name, Action ac, bool multiLoad = true) { WWW www = new WWW(GetPath(_name)); yield return www; // 加载完成 mLoadingAssetList.Remove(_name); if (www != null && www.assetBundle != null) { mAssetBundleList.Add(_name, www.assetBundle); ac(www.assetBundle); // 返回相同AC if (mSameAssetBundleAcList.ContainsKey(_name)) { for (int i = 0; i < mSameAssetBundleAcList[_name].Count; i++) { if (multiLoad) { mSameAssetBundleAcList[_name][i](www.assetBundle); } } mSameAssetBundleAcList[_name].Clear(); } } else { ac(null); // 返回相同AC if (mSameAssetBundleAcList.ContainsKey(_name)) { for (int i = 0; i < mSameAssetBundleAcList[_name].Count; i++) { if (multiLoad) { mSameAssetBundleAcList[_name][i](null); } } mSameAssetBundleAcList[_name].Clear(); } Debug.LogWarning("没有找到资源__" + _name); } } /// /// 同步读取资源 /// /// 资源名称(不带后缀) /// Object private void LoadAssetBundleSynchro(string _name, Action ac) { if (string.IsNullOrEmpty(_name)) { ac(null); return; } String path = GetPath2(_name); if (mAssetBundleList.ContainsKey(_name)) { ac(mAssetBundleList[_name]); } else { AssetBundle ab = AssetBundle.LoadFromFile(path); if (ab != null) { mAssetBundleList.Add(_name, ab); ac(ab); } else { ac(null); } } } /// /// 异步读取资源 /// /// 名称,不包含后缀 /// Lambda返回值(必须经过实例化才可用) private void LoadAssetBundleAsync(string _name, Action ac, bool multiLoad = true) { if (string.IsNullOrEmpty(_name)) { ac(null); return; } if (mAssetBundleList.ContainsKey(_name)) { ac(mAssetBundleList[_name]); } else { if (mLoadingAssetList.Contains(_name) == false) { mLoadingAssetList.Add(_name); StartCoroutine(IELoadAssetBundleAsync(_name, ac, multiLoad)); } else { if (mSameAssetBundleAcList.ContainsKey(_name)) { if (mSameAssetBundleAcList[_name].Contains(ac) == false) { mSameAssetBundleAcList[_name].Add(ac); } } else { List> acList = new List>(); acList.Add(ac); mSameAssetBundleAcList.Add(_name, acList); } } } } /// /// 协同加载AssetBundle /// /// 名称,不包含后缀 /// Lambda返回值 /// 返回资源AssetBundle private IEnumerator IELoadAssetBundleAsync(string _name, Action ac, bool multiLoad = true) { String path = GetPath2(_name); AssetBundleCreateRequest abcRequest = AssetBundle.LoadFromFileAsync(path); // 等待加载完成 while (abcRequest != null && abcRequest.isDone == false) { mLoadProgress = abcRequest.progress; yield return new WaitForSeconds(0.015f); } mLoadProgress = 1.0f; // 加载完成 mLoadingAssetList.Remove(_name); if (abcRequest != null && abcRequest.assetBundle != null) { mAssetBundleList.Add(_name, abcRequest.assetBundle); ac(abcRequest.assetBundle); // 返回相同AC if (mSameAssetBundleAcList.ContainsKey(_name)) { for (int i = 0; i < mSameAssetBundleAcList[_name].Count; i++) { if (multiLoad) { mSameAssetBundleAcList[_name][i](abcRequest.assetBundle); } } mSameAssetBundleAcList[_name].Clear(); } } else { ac(null); // 返回相同AC if (mSameAssetBundleAcList.ContainsKey(_name)) { for (int i = 0; i < mSameAssetBundleAcList[_name].Count; i++) { mSameAssetBundleAcList[_name][i](null); } mSameAssetBundleAcList[_name].Clear(); } Debug.LogWarning("没有找到资源__" + _name); } } /// /// 加载外部纯文本 by:jgao /// /// url路径 /// 回调 /// 数据 public void LoadText(string strName, Action ac, Dictionary postData = null) { if (strName == string.Empty) { return; } StartCoroutine(IELoadText(strName, ac, postData)); } /// /// 加载外部纯文本 by:jgao /// /// 名称 /// 回调 /// 数据 /// 返回资源AssetBundle private IEnumerator IELoadText(string name, Action ac, Dictionary postData) { WWW www; if (postData == null) { www = new WWW(name); } else { WWWForm form = new WWWForm(); foreach (KeyValuePair kv in postData) { form.AddField(kv.Key, kv.Value); } www = new WWW(name, form); } DateTime timer = DateTime.MinValue; float lastProgress = 0.0f; // 超时检测(苹果支付时不考虑超时问题) while (false == www.isDone && postData == null) { if (www.error != null) { Debug.LogWarning("网络超时,请检查网络后重试!"); yield break; } if (www.progress.Equals(0)) { if (lastProgress.Equals(0) && timer == DateTime.MinValue) { lastProgress = www.progress; timer = DateTime.Now; } else { double diff = (DateTime.Now - timer).TotalMilliseconds; if (diff > Const.NetDefaultTimeOut) { Debug.LogWarning("网络超时,请检查网络后重试!"); yield break; } } } else { // 进度值一直不动,超过10s认为断网 if (www.progress.Equals(lastProgress)) { double diff = (DateTime.Now - timer).TotalMilliseconds; if (diff > Const.NetDefaultTimeOut) { Debug.LogWarning("网络超时,请检查网络后重试!"); yield break; } } else { // 正常下载,重置状态 lastProgress = www.progress; timer = DateTime.Now; } } yield return null; } yield return www; if (www.error == null) { ac(www.text); www.Dispose(); } else { Debug.LogWarning(www.error); } } /// /// 卸载AssetBundle /// /// 名称,不包含后缀 /// 强力卸载,为真时即便是常驻内存也将被卸载 /// 是否卸载成功 public bool UnloadAssetBundle(string _name) { if (mAssetBundleList.ContainsKey(_name)) { mAssetBundleList[_name].Unload(true); mAssetBundleList.Remove(_name); return true; } return false; } /// /// 清除所有AssetBundle /// /// 强力卸载,为真时即便是常驻内存也将被卸载 public void ClearAllAssetBundle() { List KeyList = new List(mAssetBundleList.Keys); for (int i = 0; i < KeyList.Count; i++) { UnloadAssetBundle(KeyList[i]); } } /// /// 获取异步加载资源路径(用于 www 加载) /// /// 资源名称 /// 文件后缀 /// 返回实际路径 public static string GetPath(string strName, string fileSuffix = ".unity3d") { string strPath = string.Empty; string persistentDataPath = Application.persistentDataPath + "/Res/" + strName + fileSuffix; string streamingAssetsPath = Application.streamingAssetsPath + "/Res/" + strName + fileSuffix; if (Application.isEditor) { if (File.Exists(streamingAssetsPath)) { strPath = "file://" + streamingAssetsPath; } else { strPath = "file:///" + persistentDataPath; } } else { if (File.Exists(persistentDataPath)) { strPath = "file://" + persistentDataPath; } else { if (RuntimePlatform.Android == Application.platform) { strPath = streamingAssetsPath; } else { strPath = "file://" + streamingAssetsPath; } } } return strPath; } /// /// 获取加载资源路径(用于 LoadFromFile 的同步和异步加载) /// /// 资源名称 /// 文件后缀 /// 返回实际路径 public static string GetPath2(string strName, string fileSuffix = ".unity3d") { string path = ""; string persistentDataPath = Application.persistentDataPath + "/Res/" + strName + fileSuffix;// 沙盒路径 string streamingAssetsPath = Application.streamingAssetsPath + "/Res/" + strName + fileSuffix; if (Application.isEditor) { if (File.Exists(streamingAssetsPath)) { path = streamingAssetsPath; } else { path = persistentDataPath; } } else { if (File.Exists(persistentDataPath)) { path = persistentDataPath; } else { if (RuntimePlatform.Android == Application.platform) { path = Application.dataPath + "!assets" + "/Res/" + strName + fileSuffix; } else { path = streamingAssetsPath; } } } return path; } /// /// 获取加载资源路径(用于 LoadFromFile 的同步和异步加载) /// /// 资源名称 /// 文件后缀 /// 返回实际路径 public static string GetNewPath(string strName, string fileSuffix = ".unity3d") { string path = ""; //string persistentDataPath = Application.persistentDataPath + "/NewRes/" + strName + fileSuffix;// 沙盒路径 string streamingAssetsPath = Application.streamingAssetsPath + "/NewRes/" + strName + fileSuffix; if (Application.isEditor) { //if (File.Exists(streamingAssetsPath)) { path = streamingAssetsPath; } //else //{ // path = persistentDataPath; //} } else { //if (File.Exists(persistentDataPath)) //{ // path = persistentDataPath; //} //else { if (RuntimePlatform.Android == Application.platform) { path = Application.dataPath + "!assets" + "/NewRes/" + strName + fileSuffix; } else { path = streamingAssetsPath; } } } return path; } }