/// <summary> /// Check Bundles/[Platform]/xxxx.kk exists? /// </summary> /// <param name="url"></param> /// <returns></returns> public static bool IsBundleResourceExist(string url) { if (KResourceModule.IsEditorLoadAsset) { var editorPath = "Assets/" + KEngineDef.ResourcesBuildDir + "/" + url; var hasEditorUrl = File.Exists(editorPath); if (hasEditorUrl) { return(true); } } return(KResourceModule.IsResourceExist(KResourceModule.BundlesPathRelative + url.ToLower() + AppEngine.GetConfig(KEngineDefaultConfigs.AssetBundleExt))); }
private IEnumerator CoLoad(string url) { if (_loaderMode == LoaderMode.Sync) { Bytes = KResourceModule.LoadAssetsSync(url); } else { string _fullUrl; var getResPathType = KResourceModule.GetResourceFullPath(url, _loaderMode == LoaderMode.Async, out _fullUrl); if (getResPathType == KResourceModule.GetResourceFullPathType.Invalid) { Log.Error("[HotBytesLoader]Error Path: {0}", url); OnFinish(null); yield break; } _wwwLoader = KWWWLoader.Load(_fullUrl); while (!_wwwLoader.IsCompleted) { Progress = _wwwLoader.Progress; yield return(null); } if (!_wwwLoader.IsSuccess) { //if (AssetBundlerLoaderErrorEvent != null) //{ // AssetBundlerLoaderErrorEvent(this); //} Log.Error("[HotBytesLoader]Error Load WWW: {0}", url); OnFinish(null); yield break; } #if UNITY_2018_1_OR_NEWER //TODO 换成WebRequst //Bytes = _wwwLoader.Www.downloadHandler.data; Bytes = _wwwLoader.Www.bytes; #else Bytes = _wwwLoader.Www.bytes; #endif } OnFinish(Bytes); }
protected override void Init(string url, params object[] args) { #if UNITY_5 || UNITY_2017_1_OR_NEWER PreLoadManifest(); #endif base.Init(url); _loaderMode = (LoaderMode)args[0]; if (NewAssetBundleLoaderEvent != null) { NewAssetBundleLoaderEvent(url); } RelativeResourceUrl = url; KResourceModule.LogRequest("AssetBundle", RelativeResourceUrl); KResourceModule.Instance.StartCoroutine(LoadAssetBundle(url)); }
private IEnumerator CoLoad(string url) { if (_loaderMode == LoaderMode.Sync) { Bytes = LoadSync(url); } else { var getResPathType = KResourceModule.GetResourceFullPath(url, _loaderMode == LoaderMode.Async, out _fullUrl); if (getResPathType == KResourceModule.GetResourceFullPathType.Invalid) { if (Debug.isDebugBuild) { Log.Error("[HotBytesLoader]Error Path: {0}", url); } OnFinish(null); yield break; } _wwwLoader = KWWWLoader.Load(_fullUrl); while (!_wwwLoader.IsCompleted) { Progress = _wwwLoader.Progress; yield return(null); } if (!_wwwLoader.IsSuccess) { //if (AssetBundlerLoaderErrorEvent != null) //{ // AssetBundlerLoaderErrorEvent(this); //} Log.Error("[HotBytesLoader]Error Load WWW: {0}", url); OnFinish(null); yield break; } Bytes = _wwwLoader.Www.bytes; } OnFinish(Bytes); }
/// <summary> /// Unity5下,使用manifest进行AssetBundle的加载 /// bool isForce,在热更新后,可能需要强制刷新AssetBundleManifest。 /// </summary> public static void PreLoadManifest(bool isForce = false) { if (_hasPreloadAssetBundleManifest && isForce == false) { return; } _hasPreloadAssetBundleManifest = true; //此方法不能加载到manifest文件 //var manifestPath = string.Format("{0}/{1}/{1}.manifest", KResourceModule.BundlesPathRelative,KResourceModule.BuildPlatformName); // _mainAssetBundle = AssetBundle.LoadFromFile(manifestPath); // _assetBundleManifest = _mainAssetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); var manifestPath = KResourceModule.BundlesPathRelative + KResourceModule.GetBuildPlatformName(); KBytesLoader bytesLoader = KBytesLoader.Load(manifestPath, LoaderMode.Sync); Debuger.Assert(bytesLoader != null, $"load manifest byte error path:{manifestPath}"); _mainAssetBundle = AssetBundle.LoadFromMemory(bytesLoader.Bytes); Debuger.Assert(_mainAssetBundle != null, "load manifest ab error"); _assetBundleManifest = _mainAssetBundle.LoadAsset("AssetBundleManifest") as AssetBundleManifest; }
private IEnumerator _Init(string path, LoaderMode loaderMode) { IsLoadAssetBundle = AppEngine.GetConfig("KEngine", "IsLoadAssetBundle").ToInt32() != 0; Object getAsset = null; if (IsEditorLoadAsset) { #if UNITY_EDITOR if (path.EndsWith(".unity")) { // scene getAsset = KResourceModule.Instance; Log.LogWarning("Load scene from Build Settings: {0}", path); } else { getAsset = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/" + KEngineDef.ResourcesBuildDir + "/" + path, typeof(UnityEngine.Object)); if (getAsset == null) { Log.Error("Asset is NULL(from {0} Folder): {1}", KEngineDef.ResourcesBuildDir, path); } } #else Log.Error("`IsEditorLoadAsset` is Unity Editor only"); #endif OnFinish(getAsset); } else if (!IsLoadAssetBundle) { string extension = Path.GetExtension(path); path = path.Substring(0, path.Length - extension.Length); // remove extensions getAsset = Resources.Load <Object>(path); if (getAsset == null) { Log.Error("Asset is NULL(from Resources Folder): {0}", path); } OnFinish(getAsset); } else { _bundleLoader = AssetBundleLoader.Load(path, null, loaderMode); while (!_bundleLoader.IsCompleted) { if (IsReadyDisposed) // 中途释放 { _bundleLoader.Release(); OnFinish(null); yield break; } yield return(null); } if (!_bundleLoader.IsSuccess) { Log.Error("[AssetFileLoader]Load BundleLoader Failed(Error) when Finished: {0}", path); _bundleLoader.Release(); OnFinish(null); yield break; } var assetBundle = _bundleLoader.Bundle; DateTime beginTime = DateTime.Now; #if UNITY_5 || UNITY_2017_1_OR_NEWER // Unity 5 下,不能用mainAsset, 要取对象名 var abAssetName = Path.GetFileNameWithoutExtension(Url).ToLower(); if (!assetBundle.isStreamedSceneAssetBundle) { if (loaderMode == LoaderMode.Sync) { getAsset = assetBundle.LoadAsset(abAssetName); Debuger.Assert(getAsset); _bundleLoader.PushLoadedAsset(getAsset); } else { var request = assetBundle.LoadAssetAsync(abAssetName); while (!request.isDone) { yield return(null); } Debuger.Assert(getAsset = request.asset); _bundleLoader.PushLoadedAsset(getAsset); } } else { // if it's a scene in asset bundle, did nothing // but set a fault Object the result getAsset = KResourceModule.Instance; } #else // 经过AddWatch调试,.mainAsset这个getter第一次执行时特别久,要做序列化 //AssetBundleRequest request = assetBundle.LoadAsync("", typeof(Object));// mainAsset //while (!request.isDone) //{ // yield return null; //} try { Debuger.Assert(getAsset = assetBundle.mainAsset); } catch { Log.Error("[OnAssetBundleLoaded:mainAsset]{0}", path); } #endif KResourceModule.LogLoadTime("AssetFileBridge", path, beginTime); if (getAsset == null) { Log.Error("Asset is NULL: {0}", path); } } if (Application.isEditor) { if (getAsset != null) { KResoourceLoadedAssetDebugger.Create(getAsset.GetType().Name, Url, getAsset as Object); } // 编辑器环境下,如果遇到GameObject,对Shader进行Fix if (getAsset is GameObject) { var go = getAsset as GameObject; foreach (var r in go.GetComponentsInChildren <Renderer>(true)) { RefreshMaterialsShaders(r); } } } if (getAsset != null) { // 更名~ 注明来源asset bundle 带有类型 getAsset.name = String.Format("{0}~{1}", getAsset, Url); } OnFinish(getAsset); }
/// <summary> /// 协和加载Assetbundle,加载完后执行callback /// </summary> /// <param name="url">资源的url</param> /// <param name="callback"></param> /// <param name="callbackArgs"></param> /// <returns></returns> private IEnumerator CoLoad(string url) { #if UNITY_2017_1_OR_NEWER //在Unity2017.1.1下,路径中包含两种分隔符(/和\),仅限windows平台 //比如:C:\Code\KSFramework\Product/Bundles/Windows/ui/login.prefab.k)会报: UriFormatException: Invalid URI: Invalid port number //此处对路径处理成Unity标准路径格式:C:/Code/KSFramework/Product/Bundles/Windows/ui/login.prefab.k #if UNITY_EDITOR || UNITY_STANDALONE_WIN url = KTool.FormatToAssetUrl(url); #endif #endif KResourceModule.LogRequest("WWW", url); System.DateTime beginTime = System.DateTime.Now; // 潜规则:不用LoadFromCache~它只能用在.assetBundle Www = new WWW(url); BeginLoadTime = Time.time; WWWLoadingCount++; //设置AssetBundle解压缩线程的优先级 Www.threadPriority = Application.backgroundLoadingPriority; // 取用全局的加载优先速度 while (!Www.isDone) { Progress = Www.progress; yield return(null); } yield return(Www); WWWLoadingCount--; Progress = 1; if (IsReadyDisposed) { Log.Error("[KWWWLoader]Too early release: {0}", url); OnFinish(null); yield break; } if (!string.IsNullOrEmpty(Www.error)) { if (Application.platform == RuntimePlatform.Android) { // TODO: Android下的错误可能是因为文件不存在! } string fileProtocol = KResourceModule.GetFileProtocol(); if (url.StartsWith(fileProtocol)) { string fileRealPath = url.Replace(fileProtocol, ""); Log.Error("File {0} Exist State: {1}", fileRealPath, System.IO.File.Exists(fileRealPath)); } Log.Error("[KWWWLoader:Error]{0} {1}", Www.error, url); OnFinish(null); yield break; } else { KResourceModule.LogLoadTime("WWW", url, beginTime); if (WWWFinishCallback != null) { WWWFinishCallback(url); } Desc = string.Format("{0}K", Www.bytes.Length / 1024f); OnFinish(Www); } // 预防WWW加载器永不反初始化, 造成内存泄露~ if (Application.isEditor) { while (GetCount <KWWWLoader>() > 0) { yield return(null); } yield return(new WaitForSeconds(5f)); while (Debug.isDebugBuild && !IsReadyDisposed) { Log.Error("[KWWWLoader]Not Disposed Yet! : {0}", this.Url); yield return(null); } } }
/// <summary> /// Initialize the path of AssetBundles store place ( Maybe in PersitentDataPath or StreamingAssetsPath ) /// </summary> /// <returns></returns> static void InitResourcePath() { GameObject resMgr = GameObject.Find("_ResourceModule_"); if (resMgr == null) { resMgr = new GameObject("_ResourceModule_"); GameObject.DontDestroyOnLoad(resMgr); } _Instance = resMgr.AddComponent <KResourceModule>(); string editorProductPath = EditorProductFullPath; BundlesPathRelative = string.Format("{0}/{1}/", BundlesDirName, GetBuildPlatformName()); DocumentResourcesPath = FileProtocol + DocumentResourcesPathWithoutFileProtocol; switch (Application.platform) { case RuntimePlatform.WindowsEditor: case RuntimePlatform.OSXEditor: { ApplicationPath = string.Format("{0}{1}", GetFileProtocol(), editorProductPath); ProductPathWithProtocol = GetFileProtocol() + EditorProductFullPath + "/"; ProductPathWithoutFileProtocol = EditorProductFullPath + "/"; // Resources folder } break; case RuntimePlatform.WindowsPlayer: case RuntimePlatform.OSXPlayer: { string path = Application.streamingAssetsPath.Replace('\\', '/'); //Application.dataPath.Replace('\\', '/'); // path = path.Substring(0, path.LastIndexOf('/') + 1); ApplicationPath = string.Format("{0}{1}", GetFileProtocol(), Application.dataPath); ProductPathWithProtocol = string.Format("{0}{1}/", GetFileProtocol(), path); ProductPathWithoutFileProtocol = string.Format("{0}/", path); // Resources folder } break; case RuntimePlatform.Android: { ApplicationPath = string.Concat("jar:", GetFileProtocol(), Application.dataPath, "!/assets"); ProductPathWithProtocol = string.Concat(ApplicationPath, "/"); ProductPathWithoutFileProtocol = string.Concat(Application.dataPath, "!/assets/"); // 注意,StramingAsset在Android平台中,是在壓縮的apk里,不做文件檢查 // Resources folder } break; case RuntimePlatform.IPhonePlayer: { ApplicationPath = System.Uri.EscapeUriString(GetFileProtocol() + Application.streamingAssetsPath); // MacOSX下,带空格的文件夹,空格字符需要转义成%20 ProductPathWithProtocol = string.Format("{0}/", ApplicationPath); // only iPhone need to Escape the f*****g Url!!! other platform works without it!!! Keng Die! ProductPathWithoutFileProtocol = Application.streamingAssetsPath + "/"; // Resources folder } break; default: { Debuger.Assert(false); } break; } }
/// <summary> /// Initialize the path of AssetBundles store place ( Maybe in PersitentDataPath or StreamingAssetsPath ) /// </summary> /// <returns></returns> static void InitResourcePath() { GameObject resMgr = GameObject.Find("_ResourceModule_"); if (resMgr == null) { resMgr = new GameObject("_ResourceModule_"); GameObject.DontDestroyOnLoad(resMgr); } _Instance = resMgr.AddComponent<KResourceModule>(); string editorProductPath = EditorProductFullPath; BundlesPathRelative = string.Format("{0}/{1}/", BundlesDirName, GetBuildPlatformName()); DocumentResourcesPath = FileProtocol + DocumentResourcesPathWithoutFileProtocol; switch (Application.platform) { case RuntimePlatform.WindowsEditor: case RuntimePlatform.OSXEditor: { ApplicationPath = string.Format("{0}{1}/", GetFileProtocol(), editorProductPath); BundlesPathWithProtocol = GetFileProtocol() + EditorAssetBundleFullPath + "/" + BuildPlatformName + "/"; BundlesPathWithoutFileProtocol = EditorAssetBundleFullPath + "/" + BuildPlatformName + "/"; // Resources folder } break; case RuntimePlatform.WindowsPlayer: case RuntimePlatform.OSXPlayer: { string path = Application.streamingAssetsPath.Replace('\\', '/');//Application.dataPath.Replace('\\', '/'); // path = path.Substring(0, path.LastIndexOf('/') + 1); ApplicationPath = string.Format("{0}{1}/", GetFileProtocol(), Application.dataPath); BundlesPathWithProtocol = string.Format("{0}{1}/{2}/{3}/", GetFileProtocol(), path, BundlesDirName, GetBuildPlatformName()); BundlesPathWithoutFileProtocol = string.Format("{0}/{1}/{2}/", path, BundlesDirName, GetBuildPlatformName()); // Resources folder } break; case RuntimePlatform.Android: { ApplicationPath = string.Concat("jar:", GetFileProtocol(), Application.dataPath, string.Format("!/assets/{0}/", BundlesDirName)); BundlesPathWithProtocol = string.Concat(ApplicationPath, GetBuildPlatformName(), "/"); BundlesPathWithoutFileProtocol = string.Concat(Application.dataPath, "!/assets/" + BundlesDirName + "/", GetBuildPlatformName() + "/"); // 注意,StramingAsset在Android平台中,是在壓縮的apk里,不做文件檢查 // Resources folder } break; case RuntimePlatform.IPhonePlayer: { ApplicationPath = System.Uri.EscapeUriString(GetFileProtocol() + Application.streamingAssetsPath + "/" + BundlesDirName + "/"); // MacOSX下,带空格的文件夹,空格字符需要转义成%20 BundlesPathWithProtocol = string.Format("{0}{1}/", ApplicationPath, GetBuildPlatformName()); // only iPhone need to Escape the f*****g Url!!! other platform works without it!!! Keng Die! BundlesPathWithoutFileProtocol = Application.streamingAssetsPath + "/" + BundlesDirName + "/" + GetBuildPlatformName() + "/"; // Resources folder } break; default: { Debuger.Assert(false); } break; } }
private IEnumerator LoadAssetBundle(string relativeUrl) { #if UNITY_5 || UNITY_2017_1_OR_NEWER // Unity 5 Manifest中管理了依赖 var abPath = relativeUrl.ToLower(); var deps = _assetBundleManifest.GetAllDependencies(abPath); _depLoaders = new AssetBundleLoader[deps.Length]; for (var d = 0; d < deps.Length; d++) { var dep = deps[d]; _depLoaders[d] = AssetBundleLoader.Load(dep, null, _loaderMode); if (_depLoaders[d].dependFrom == string.Empty) { _depLoaders[d].dependFrom = relativeUrl; } } for (var l = 0; l < _depLoaders.Length; l++) { var loader = _depLoaders[l]; while (!loader.IsCompleted) { yield return(null); } } #endif #if UNITY_5 || UNITY_2017_1_OR_NEWER // Unity 5 AssetBundle自动转小写 relativeUrl = relativeUrl.ToLower(); #endif if (AppConfig.IsLogAbLoadCost) { beginTime = Time.realtimeSinceStartup; } string _fullUrl = KResourceModule.GetAbFullPath(relativeUrl); if (string.IsNullOrEmpty(_fullUrl)) { OnFinish(null); yield break; } AssetBundle assetBundle = null; if (_loaderMode == LoaderMode.Sync) { assetBundle = AssetBundle.LoadFromFile(_fullUrl); } else { var request = AssetBundle.LoadFromFileAsync(_fullUrl); while (!request.isDone) { if (IsReadyDisposed) // 中途释放 { OnFinish(null); yield break; } Progress = request.progress; yield return(null); } assetBundle = request.assetBundle; } if (assetBundle == null) { Log.Error("assetBundle is NULL: {0}", RelativeResourceUrl); } if (AppConfig.IsLogAbLoadCost) { Log.Info("[Finish] Load AssetBundle {0}, CostTime {1}s {2}", relativeUrl, Time.realtimeSinceStartup - beginTime, dependFrom); } if (AppConfig.IsSaveCostToFile && !relativeUrl.StartsWith("ui/")) { LogFileManager.WriteLoadAbLog(relativeUrl, Time.realtimeSinceStartup - beginTime); } OnFinish(assetBundle); }
/// <summary> /// 协和加载Assetbundle,加载完后执行callback /// </summary> /// <param name="url">资源的url</param> /// <param name="callback"></param> /// <param name="callbackArgs"></param> /// <returns></returns> private IEnumerator CoLoad(string url) { KResourceModule.LogRequest("WWW", url); System.DateTime beginTime = System.DateTime.Now; // 潜规则:不用LoadFromCache~它只能用在.assetBundle Www = new WWW(url); BeginLoadTime = Time.time; WWWLoadingCount++; //设置AssetBundle解压缩线程的优先级 Www.threadPriority = Application.backgroundLoadingPriority; // 取用全局的加载优先速度 while (!Www.isDone) { Progress = Www.progress; yield return(null); } yield return(Www); WWWLoadingCount--; Progress = 1; if (IsReadyDisposed) { Log.Error("[KWWWLoader]Too early release: {0}", url); OnFinish(null); yield break; } if (!string.IsNullOrEmpty(Www.error)) { if (Application.platform == RuntimePlatform.Android) { // TODO: Android下的错误可能是因为文件不存在! } string fileProtocol = KResourceModule.GetFileProtocol(); if (url.StartsWith(fileProtocol)) { string fileRealPath = url.Replace(fileProtocol, ""); Log.Error("File {0} Exist State: {1}", fileRealPath, System.IO.File.Exists(fileRealPath)); } Log.Error("[KWWWLoader:Error]{0} {1}", Www.error, url); OnFinish(null); yield break; } else { KResourceModule.LogLoadTime("WWW", url, beginTime); if (WWWFinishCallback != null) { WWWFinishCallback(url); } Desc = string.Format("{0}K", Www.bytes.Length / 1024f); OnFinish(Www); } // 预防WWW加载器永不反初始化, 造成内存泄露~ if (Application.isEditor) { while (GetCount <KWWWLoader>() > 0) { yield return(null); } yield return(new WaitForSeconds(5f)); while (Debug.isDebugBuild && !IsReadyDisposed) { Log.Error("[KWWWLoader]Not Disposed Yet! : {0}", this.Url); yield return(null); } } }
private IEnumerator _Init(string path, LoaderMode loaderMode) { IsLoadAssetBundle = KEngine.AppEngine.GetConfig("KEngine", "IsLoadAssetBundle").ToInt32() != 0; UnityEngine.Object getAsset = null; if (!IsLoadAssetBundle) { string extension = System.IO.Path.GetExtension(path); path = path.Substring(0, path.Length - extension.Length); // remove extensions getAsset = Resources.Load <UnityEngine.Object>(path); if (getAsset == null) { Log.Error("Asset is NULL(from Resources Folder): {0}", path); } OnFinish(getAsset); } else { _bundleLoader = KAssetBundleLoader.Load(path, null, loaderMode); while (!_bundleLoader.IsCompleted) { if (IsReadyDisposed) // 中途释放 { _bundleLoader.Release(); OnFinish(null); yield break; } yield return(null); } if (!_bundleLoader.IsSuccess) { Log.Error("[KAssetFileLoader]Load BundleLoader Failed(Error) when Finished: {0}", path); _bundleLoader.Release(); OnFinish(null); yield break; } var assetBundle = _bundleLoader.Bundle; System.DateTime beginTime = System.DateTime.Now; #if UNITY_5 // Unity 5 下,不能用mainAsset, 要取对象名 var abAssetName = Path.GetFileNameWithoutExtension(Url).ToLower(); if (loaderMode == LoaderMode.Sync) { getAsset = assetBundle.LoadAsset(abAssetName); Debuger.Assert(getAsset); } else { var request = assetBundle.LoadAssetAsync(abAssetName); while (!request.isDone) { yield return(null); } Debuger.Assert(getAsset = request.asset); } #else // 经过AddWatch调试,.mainAsset这个getter第一次执行时特别久,要做序列化 //AssetBundleRequest request = assetBundle.LoadAsync("", typeof(Object));// mainAsset //while (!request.isDone) //{ // yield return null; //} try { Debuger.Assert(getAsset = assetBundle.mainAsset); } catch { Log.Error("[OnAssetBundleLoaded:mainAsset]{0}", path); } #endif KResourceModule.LogLoadTime("AssetFileBridge", path, beginTime); if (getAsset == null) { Log.Error("Asset is NULL: {0}", path); } } if (Application.isEditor) { if (getAsset != null) { KResoourceLoadedAssetDebugger.Create(getAsset.GetType().Name, Url, getAsset as UnityEngine.Object); } } if (getAsset != null) { // 更名~ 注明来源asset bundle 带有类型 getAsset.name = string.Format("{0}~{1}", getAsset, Url); } OnFinish(getAsset); }
/// <summary> /// Unity5下,使用manifest进行AssetBundle的加载 /// bool isForce,在热更新后,可能需要强制刷新AssetBundleManifest。 /// </summary> public static void PreLoadManifest(bool isForce = false) { if (_hasPreloadAssetBundleManifest && isForce == false) { return; } _hasPreloadAssetBundleManifest = true; //此方法不能加载到manifest文件 //var manifestPath = string.Format("{0}/{1}/{1}.manifest", KResourceModule.BundlesPathRelative,KResourceModule.BuildPlatformName); // _mainAssetBundle = AssetBundle.LoadFromFile(manifestPath); // _assetBundleManifest = _mainAssetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); KBytesLoader bytesLoader = KBytesLoader.Load(KResourceModule.BundlesPathRelative + KResourceModule.GetBuildPlatformName(), LoaderMode.Sync); _mainAssetBundle = AssetBundle.LoadFromMemory(bytesLoader.Bytes);//KResourceModule.LoadSyncFromStreamingAssets(mainAssetBundlePath)); _assetBundleManifest = _mainAssetBundle.LoadAsset("AssetBundleManifest") as AssetBundleManifest; Debuger.Assert(_mainAssetBundle); Debuger.Assert(_assetBundleManifest); }