/// <summary> /// 从cache中加载bundle /// </summary> private bool load_bundle_from_cache(string _bundle_path, List <BundleObject> _all_bundles) { if (bundleobj_cache_.is_in_cache(_bundle_path)) { BundleObject bundle_object = bundleobj_cache_.get_bundle_object_from_cache(_bundle_path); if (!_all_bundles.Contains(bundle_object)) { _all_bundles.Add(bundle_object); bundle_object.add_ref();//增加引用,防止在加载过程中被gc销毁 //bundle_object.load_fbx_inf();//set the mesh info if this is a fbx info } return(true); } return(false); }
/// <summary> /// 加载DefaultRes /// </summary> private IEnumerator load_first_bundle() { // 使用LoadFromFileAsync进行加载(ios包内外均可使用,android必须拷贝到包外) bool is_from_package = false; uint file_offset = 0; string bundle_url = get_bundle_url(FIRST_INIT_BUNDLE, ref is_from_package, ref file_offset); bundle_url = CommonTool.WipeFileSprit(bundle_url); AssetBundle bundle = null; if (AuditManager.Instance.Open) { var request = AssetBundle.LoadFromFileAsync(bundle_url, 0, file_offset); yield return(request); bundle = request.assetBundle; } else { var request = AssetBundle.LoadFromFileAsync(bundle_url); yield return(request); bundle = request.assetBundle; } BundleObject bundle_object = new BundleObject(FIRST_INIT_BUNDLE, bundle); bundle_object.add_ref(); put_bundle_object_to_cache(FIRST_INIT_BUNDLE, bundle_object); #if UNITY_IPHONE // 在ios提审/内存小于1G时,不进行Shader的预加载 if (AuditManager.Instance.Open || SystemInfo.systemMemorySize <= 1024) { yield break; } #endif // 加载ShaderVariantCollection var load_request = bundle.LoadAllAssetsAsync(typeof(UnityEngine.ShaderVariantCollection)); yield return(load_request); var load_asset = load_request.asset; if (load_asset != null) { Debug.Log("load shadervariantvollection succ."); // warmup var shader_varient = load_asset as UnityEngine.ShaderVariantCollection; if (!shader_varient.isWarmedUp) { shader_varient.WarmUp(); } // Shader变体存为静态变量 var variant_info = MainGame.GetGlobalMono().gameObject.AddComponent <ShaderVariantInfo>(); if (variant_info != null) { variant_info.ShaderVariantUsed = shader_varient; } } else { Debug.Log("load shadervariantvollection failed !!!"); } }
public void put_bundle_object_to_cache(string _path, BundleObject _bundle_object) { bundles_cache_.Add(_path, _bundle_object); }
private IEnumerator gc_coroutine() { float start_time = Time.unscaledTime; if (!bundleobj_cache_.is_first_resource_loaded() || is_gcing_) { yield break; } is_gcing_ = true; // GameObject被销毁时,要减少对应AssetObject的引用 foreach (xc.Tuple <GameObject, AssetObject> item in dic_gameobj_asset_) { if (item.get_item1_ == null) { item.get_item2_.decrence_ref(); } } dic_gameobj_asset_.RemoveAll(item => item.get_item1_ == null); // 销毁场景相关引用计数已为0的AssetObject List <string> assets = assetobj_cache_.get_cache_asset_for_gc_names(true); foreach (string path in assets) { if (!asset_lock_.try_lock(path)) { yield return(StartCoroutine(asset_lock_.try_lock_croutine(path))); } assetobj_cache_.try_clean_noused_asset(path); asset_lock_.unlock(path); } // 销毁其他引用计数已为0的AssetObject assets = assetobj_cache_.get_cache_asset_for_gc_names(false); foreach (string path in assets) { if (!asset_lock_.try_lock(path)) { yield return(StartCoroutine(asset_lock_.try_lock_croutine(path))); } assetobj_cache_.try_clean_noused_asset(path); asset_lock_.unlock(path); } ResourceUtilEx.Instance.gc(0); // ResourceUtilEx调用gc后需要再次检查引用计数已为0的AssetObject assets = assetobj_cache_.get_cache_asset_for_gc_names(false); foreach (string path in assets) { if (!asset_lock_.try_lock(path)) { yield return(StartCoroutine(asset_lock_.try_lock_croutine(path))); } assetobj_cache_.try_clean_noused_asset(path); asset_lock_.unlock(path); } // 卸载引用计数为0的assetbundle List <string> destroyed = new List <string>(); List <string> bundles_set = bundleobj_cache_.get_bundles_for_gc(); foreach (string path in bundles_set) { if (!bundleobj_cache_.is_in_cache(path)) { continue; } if (!bundle_lock_.try_lock(path)) { yield return(StartCoroutine(bundle_lock_.try_lock_croutine(path))); } BundleObject bundle_object = bundleobj_cache_.get_bundle_object_from_cache(path); if (bundle_object.get_ref_count_ < 1) { bundle_object.destroy(); bundleobj_cache_.remove_bundle_object_from_cache(path); } bundle_lock_.unlock(path); } SGameEngine.Pool <string> .List.Free(bundles_set); #if UNITY_IPHONE // 1G内存的iphone设备开启gc if (SystemInfo.systemMemorySize <= 1024) { System.GC.Collect(0); } #endif float mark_time = Time.unscaledTime; is_gcing_ = false; GameDebug.Log(string.Format("[ResourceLoader](gc_process)use time: {0}, mark time: {1}", Time.unscaledTime - start_time, Time.unscaledTime - mark_time)); }
/// <summary> /// <para>加载UnityEngine.Object资源,资源不再使用后要调用AssetResource.Destroy()来销毁</para> /// <para>_asset_path:资源路径,eg: "Assets/Res/DefaultRes.prefab"</para> /// <para>_type:加载资源的类型</para> /// <para>_result:协程结束后返回加载资源的结果</para> /// <para>_lock_asset:为避免其他协程加载资源,是否进行锁定操作</para> /// <para>_scene_asset:是否是场景资源</para> /// <para>_scene_name:场景资源的名字</para> /// </summary> public IEnumerator load_asset(string _asset_path, Type _type, AssetResource _result, bool _lock_asset = true, bool _scene_asset = false, string _scene_name = "") { if (is_destroyed_) { yield break; } bool is_ui_asset = _asset_path.Contains("Assets/Res/UI"); if (Const.Language != LanguageType.SIMPLE_CHINESE) { LocalizeManager.Instance.LocalizePath(ref _asset_path); } #if UNITY_EDITOR // 在编辑器下检查资源是否添加到打包配置中(因为lightmap的bug,.unity3d场景暂时不进行资源检查) if (!CheckAssetCfged(_asset_path)) { Debug.LogError(string.Format("asset {0} is not configured for bundle, load failed!", _asset_path)); yield break; } #endif if (_result.get_obj() != null) { Debug.LogError("resused an old assetresoure! you should create a new!"); yield break; } //1. 等待first res加载完毕,其中包含bundleinfo while (!bundleobj_cache_.is_first_resource_loaded()) { yield return(new WaitForEndOfFrame()); } loading_ = true; // 检查资源对应的分包是否已经下载完毕 int patch_id; if (!xpatch.XPatchManager.Instance.IsAssetDownloaded(_asset_path, out patch_id)) { Debug.Log(string.Format("asset {0} is not download for bundle!", _asset_path)); yield break; } //2. 锁定资源,避免加载同一份asset IEnumerator ielock = null; if (_lock_asset) { if (!asset_lock_.try_lock(_asset_path)) { ielock = asset_lock_.try_lock_croutine(_asset_path); coroutine_locked_assets_.Add(ielock, _asset_path); yield return(StartCoroutine(ielock)); } } //3. 检查Cache中是否已经有对应的bundle,否则需要进行加载 AssetObject found_obj = assetobj_cache_.get_from_cache(_asset_path); if (found_obj != null) { _result.set_obj(found_obj); if (_scene_asset) { //load level sceneLoadAsyncOp = SceneManager.LoadSceneAsync(_scene_name); yield return(sceneLoadAsyncOp); } } else { #if UNITY_EDITOR if (!EnableBundleInEditor) { //editor enviroment yield return(StartCoroutine(load_asset_from_assetdatabase(_asset_path, _type, _result, _lock_asset, _scene_asset, _scene_name))); } else #endif { //bundle enviroment //4.从bundleinfo中获取asset的依赖项 AssetBundleInfoItem bundle_info = bundleobj_cache_.get_asset_bundle_info(_asset_path); if (bundle_info == null) { Debug.LogError("Dynamic bundle not find!Editor path is " + _asset_path); goto EXIT_LOAD_ASSET; } UnityEngine.Object loaded_asset = null; List <BundleObject> all_bundles = new List <BundleObject>(); List <List <string> > sort_depends_list = bundleobj_cache_.get_asset_all_dependence(_asset_path); foreach (List <string> sub_list in sort_depends_list) { // 先判断是否在Cache中 if (bundleobj_cache_.is_all_in_cache(sub_list)) { foreach (string path in sub_list) { load_bundle_from_cache(path, all_bundles); } } else { List <string> fail_list = new List <string>(); yield return(StartCoroutine(try_load_bundle_list_coroutine(sub_list, all_bundles, fail_list, is_ui_asset))); //被其他协程锁定的bundle等待解锁后再进行加载 foreach (string depend_bundle_path in fail_list) { //lock if (!bundle_lock_.try_lock(depend_bundle_path)) { yield return(StartCoroutine(bundle_lock_.try_lock_croutine(depend_bundle_path))); } //load bundle and add ref if (!load_bundle_from_cache(depend_bundle_path, all_bundles)) { yield return(StartCoroutine(load_bundle_from_disk_coroutine(depend_bundle_path, all_bundles, is_ui_asset))); } //unlock bundle_lock_.unlock(depend_bundle_path); } } } //5.锁定asset并进行加载 if (!bundle_lock_.try_lock(_asset_path)) { yield return(StartCoroutine(bundle_lock_.try_lock_croutine(_asset_path))); } //load bundle and add ref if (!load_bundle_from_cache(_asset_path, all_bundles)) { yield return(StartCoroutine(load_bundle_from_disk_coroutine(_asset_path, all_bundles, is_ui_asset))); } //unlock bundle_lock_.unlock(_asset_path); if (all_bundles.Count < 1) { goto EXIT_LOAD_ASSET; } //6.从bundle中加载mainasset // 在调用Bundle.Load()之前,需要将缓存所有的依赖bundle if (!_scene_asset) { BundleObject root = all_bundles[all_bundles.Count - 1]; // 获取在bundle中的资源名字 /*string asset_name = root.get_asset_path_; * int last_path_idx = asset_name.LastIndexOf('/'); * if(last_path_idx != -1) * asset_name = asset_name.Substring(last_path_idx + 1); * last_path_idx = asset_name.LastIndexOf('.'); * if (last_path_idx != -1) * asset_name = asset_name.Substring(0, last_path_idx);*/ //loaded_asset = bundleobj_cache_.load_main_asset(root.get_asset_bundle_, _type, BundleNameDef.MAIN); var loadReq = root.get_asset_bundle_.LoadAssetAsync(BundleNameDef.MAIN, _type); yield return(loadReq); loaded_asset = loadReq.asset; if (loaded_asset == null) { Debug.LogError(string.Format("asset counld not be loaded {0} ,check xls or your project", _asset_path)); // 加载失败后要将依赖的bundle的引用计数减少 foreach (BundleObject bo in all_bundles) { bo.decrease_ref();// 因为load bundle的时候增加了引用计数,所以此处需要减少 } goto EXIT_LOAD_ASSET; } } // 场景资源在缓存bundle之后就可以使用 else { sceneLoadAsyncOp = SceneManager.LoadSceneAsync(_scene_name); yield return(sceneLoadAsyncOp); } //7. 创建assetobject并添加到Cache中 AssetObject ao = _scene_asset ? new SceneAssetObject(_asset_path) : new AssetObject(_asset_path, loaded_asset); foreach (BundleObject bo in all_bundles) { AssetBundleInfoItem bundle_item_depend = bundleobj_cache_.get_asset_bundle_info(bo.get_asset_path_); bool shared = bundle_item_depend.shared; // 当assetbundle不被多个资源引用时,可以立即将assetbundle的文件镜像卸载,并从Cache中清除 // Atlas经过特殊处理,虽然被多个资源引用,但是也会立即卸载 /// FIXME /// 在2017版本中,此时unload assetbundle会报错 /*if(!shared) * { * bo.destroy(false); * bundleobj_cache_.remove_bundle_object_from_cache(bo.get_asset_path_); * } * else*/ { ao.add_depend_bundle(bo); } bo.decrease_ref();//decrease the ref added by load bundle } all_bundles.Clear(); assetobj_cache_.put_to_cache(_asset_path, ao); _result.set_obj(ao); } } //9.unlock asset EXIT_LOAD_ASSET: //unlock if (_lock_asset) { if (ielock != null) { coroutine_locked_assets_.Remove(ielock); } asset_lock_.unlock(_asset_path); } loading_ = false; }
/// <summary> /// 从磁盘上加载bundle文件 /// </summary> private IEnumerator load_bundle_from_disk_coroutine(string _bundle_path, List <BundleObject> _all_bundles, bool is_ui_asset) { // 获取实际的文件路径 bool from_install_package = false; uint file_offset = 0; string bundle_url = bundleobj_cache_.get_bundle_url(_bundle_path, ref from_install_package, ref file_offset); if (bundle_url == null) { Debug.LogError(string.Format("[ResourceLoader](load_bundle_from_disk_coroutine)bundle url null. bundle path: {0}", _bundle_path)); yield break; } AssetBundle bundle = null; if (from_install_package == false)// 在包外通过LoadFromFileAsync来加载会更快 { bundle_url = CommonTool.WipeFileSprit(bundle_url); if (!is_ui_asset) { if (AuditManager.Instance.Open) // 提审状态开启的时候,资源需要从bin文件读取 { var requeset = AssetBundle.LoadFromFileAsync(bundle_url, 0, file_offset); yield return(requeset); bundle = requeset.assetBundle; } else { var requeset = AssetBundle.LoadFromFileAsync(bundle_url); yield return(requeset); bundle = requeset.assetBundle; } } else { if (AuditManager.Instance.Open) // 提审状态开启的时候,资源需要从bin文件读取 { bundle = AssetBundle.LoadFromFile(bundle_url, 0, file_offset); } else { bundle = AssetBundle.LoadFromFile(bundle_url); } } } else // 在包内时,因为程序修改了x.data的路径,所以必须通过www来进行加载*/ { #if UNITY_IPHONE if (AuditManager.Instance.Open) // 提审状态开启的时候,资源需要从bin文件读取 { // ios streamingasset目录下的文件也可以通过LoadFromFileAsync来读取 bundle_url = CommonTool.WipeFileSprit(bundle_url); var requeset = AssetBundle.LoadFromFileAsync(bundle_url, 0, file_offset); yield return(requeset); bundle = requeset.assetBundle; } else { // ios streamingasset目录下的文件也可以通过LoadFromFileAsync来读取 bundle_url = CommonTool.WipeFileSprit(bundle_url); var requeset = AssetBundle.LoadFromFileAsync(bundle_url); yield return(requeset); bundle = requeset.assetBundle; } #else // 通过www来加载bundle WWW www = new WWW(bundle_url); yield return(www); while (!www.isDone) { Debug.LogError(string.Format("[ResourceLoader](load_bundle_from_disk_coroutine) this is harmless, bundle ids not donw after yield: {0}", _bundle_path)); yield return(new WaitForEndOfFrame()); } // 加载完毕后获取assetbundle bundle = www.assetBundle; www.Dispose(); #endif } if (bundle == null) { string msg = string.Format("[ResourceLoader](load_bundle_from_disk_coroutine)load bundle from www failed, unity3d file is in valid, bundle path is {0} device is {1}", _bundle_path, SystemInfo.deviceModel); Debug.LogError(msg); ControlServerLogHelper.Instance.PostPlayerFollowRecord(PlayerFollowRecordSceneId.ResLoadFail, msg, false); // Post The File Msg To DownloadRepairer Manager //ClientEventMgr.GetInstance().FireEvent((int)ClientEvent.CE_BUNDLE_RES_LOAD_FAILED, new CEventBaseArgs(_bundle_path)); var patch_mgr = xpatch.XPatchManager.Instance; if (patch_mgr.IsAutoFix) { patch_mgr.DownloadBundle(_bundle_path); } BuglyAgent.ReportException(new IOException(), msg); yield break; } // 加载的bundle使用BundleObject进行包装并放入到Cache中 BundleObject bundle_object = new BundleObject(_bundle_path, bundle); if (_bundle_path.EndsWith(CACHE_STR_CS)) { bundle_object.add_ref(); } bundleobj_cache_.put_bundle_object_to_cache(_bundle_path, bundle_object); _all_bundles.Add(bundle_object); bundle_object.add_ref(); //增加引用,防止在加载过程中被gc销毁 //bundle_object.load_fbx_inf();//set the mesh info if this is a fbx info }
public void add_depend_bundle(BundleObject _bundle_object) { _bundle_object.add_ref(); dependence_bundles_.Add(_bundle_object); }