/// <summary> /// 根据AppResConfig进行更新 /// </summary> public void UpdateByAppResConfig(ResConfigFile _appConfig) { if (_appConfig.ResVersion < ResVersion) { return; } for (Int32 i = 0; i < _appConfig.m_assets.Count; ++i) { ResInfo localResInfo; var appResInfo = _appConfig.m_assets[i]; if (ResDictionary.TryGetValue(appResInfo.Name, out localResInfo)) { if (appResInfo.Version > localResInfo.Version) { appResInfo.CopyTo(localResInfo); localResInfo.Location = AssetLocation.StreamingPath; } } else { localResInfo = appResInfo.Clone(); localResInfo.Location = AssetLocation.StreamingPath; m_assets.Add(localResInfo); ResDictionary.Add(localResInfo.Name, localResInfo); } } Save(); }
public Boolean BuilderMergeOld(ResConfigFile _old_file) { Boolean found = false; for (Int32 i = 0; i < m_assets.Count; ++i) { ResInfo old_res_info; if (!_old_file.TryGetAssetInfo(m_assets[i].Name, out old_res_info)) { found = true; Log.Info("[New]: {0}", m_assets[i].Name); continue; } if (m_assets[i].ResType == ResourceType.AssetBundle && m_assets[i].AssetBundleTypeTreeHash.Equals(old_res_info.AssetBundleTypeTreeHash)) { m_assets[i] = old_res_info; ResDictionary[old_res_info.Name] = old_res_info; continue; } if (!old_res_info.NeedUpdate(m_assets[i])) { m_assets[i] = old_res_info; ResDictionary[old_res_info.Name] = old_res_info; continue; } Log.Info("[Modify]: {0}", m_assets[i].Name); found = true; } return(found); }
public void UpdateRes(Action <Boolean> _onCompleted) { Log.Debug("开始资源更新准备工作"); mOnUpdateCompleted = _onCompleted; var appConfigAb = AssetBundle.LoadFromFile( ResInfo.GetSystemApiLoadPath("res_config.grt", AssetLocation.StreamingPath)); if (appConfigAb == null) { Log.Critical(eLogType.Resources, "加载 In App res config 失败!!!"); appConfigAb.Unload(true); return; } mInAppConfig = ResConfigFile.Create(appConfigAb.LoadAsset <TextAsset>("res_config").bytes); if (appConfigAb == null) { Log.Critical(eLogType.Resources, "解析 In App res config 失败!!!"); appConfigAb.Unload(true); return; } appConfigAb.Unload(true); mLocalConfig = ResConfigFile.Create(ResInfo.GetSystemApiLoadPath("res_config", AssetLocation.PersistentPath), true); if (mLocalConfig == null) { Log.Critical(eLogType.Resources, "创建 Local res config 失败!!!"); return; } StartCoroutine(checkUpdate()); }
private IEnumerator checkUpdate() { Log.Debug("开始检查资源更新"); using (UnityWebRequest uwr = UnityWebRequest.GetAssetBundle(ResUtility.ResConfigDownloadUrl)) { yield return(uwr.Send()); if (uwr.isError) { Debug.Log(uwr.error); showCheckUpdateFailTip(); yield break; } else { AssetBundle srvConfigAb = ((DownloadHandlerAssetBundle)uwr.downloadHandler).assetBundle; if (srvConfigAb == null) { showCheckUpdateFailTip(); yield break; } TextAsset asset = srvConfigAb.LoadAsset <TextAsset>("res_config"); if (asset == null) { showCheckUpdateFailTip(); srvConfigAb.Unload(true); yield break; } mServerConfig = ResConfigFile.Create(asset.bytes); srvConfigAb.Unload(true); if (mServerConfig == null) { showCheckUpdateFailTip(); yield break; } } } // 处理更新列表 Boolean localResConfigUpdated; mUpdateTotalSize = mLocalConfig.GetUpdateList(mInAppConfig, mServerConfig, out mUpdateList, out localResConfigUpdated); if (mUpdateTotalSize == 0) { mOnUpdateCompleted(localResConfigUpdated); } else { showUpdateTip(); } }
/// <summary> /// 获取更新列表 /// </summary> /// <param name="_appConfig"></param> /// <param name="_serverConfig"></param> /// <param name="_updateList"></param> /// <returns>更新文件大小(字节)</returns> public Int64 GetUpdateList(ResConfigFile _appConfig, ResConfigFile _serverConfig, out LinkedList <ResInfo> _updateList, out Boolean _localConfigUpdated) { _localConfigUpdated = false; Int64 updateSize = 0; _updateList = new LinkedList <ResInfo>(); for (Int32 i = 0; i < _serverConfig.m_assets.Count; ++i) { var srvResInfo = _serverConfig.m_assets[i]; ResInfo localResInfo; ResDictionary.TryGetValue(srvResInfo.Name, out localResInfo); ResInfo appResInfo; _appConfig.ResDictionary.TryGetValue(srvResInfo.Name, out appResInfo); // 无需更新 if (localResInfo != null && !localResInfo.NeedUpdate(srvResInfo)) { continue; } if (appResInfo != null && !appResInfo.NeedUpdate(srvResInfo)) { localResInfo = appResInfo.Clone(); localResInfo.Location = AssetLocation.StreamingPath; AddOrUpdateResInfo(localResInfo); Save(); _localConfigUpdated = true; } else { localResInfo = srvResInfo.Clone(); localResInfo.Location = AssetLocation.PersistentPath; _updateList.AddLast(localResInfo); updateSize += localResInfo.Size; } } return(updateSize); }
/// <summary> /// 加载一个最新的package /// </summary> /// <returns></returns> public static ResUpdatePkg LoadLastPkg() { var resConfigPath = String.Concat(OUTPUT_ROOT, "/res_config.grt"); ResUpdatePkg pkg = new ResUpdatePkg(); if (!File.Exists(resConfigPath)) { Log.Info("没有更新包!"); return(null); } else { // 直接读取txt pkg.m_res_config = ResConfigFile.Create(String.Concat(OUTPUT_ROOT, "/res_config.txt"), false); pkg.Version = pkg.m_res_config.ResVersion; if (pkg.m_res_config == null) { Log.Error("读取最新更新包失败!"); return(null); } } return(pkg); }
/// <summary> /// 从AssetsConfig中删除资源 /// </summary> /// <param name="_srv_config"></param> /// <returns>是否有删除到东西</returns> public Boolean DeleteRes(ResConfigFile _srv_config) { Boolean found = false; for (int i = 0; i < m_assets.Count; i++) { if (!_srv_config.ContainAsset(m_assets[i].Name)) { m_assets[i] = null; if (m_asset_dictionary != null) // 直接重建好了 { m_asset_dictionary = null; } found = true; } } if (!found) { return(false); } m_assets.RemoveNull(); return(true); }
/// <summary> /// 初始化ResourceManager, 加载包内和包外的res_config /// </summary> /// <param name="_action_initialized"></param> /// <returns></returns> private IEnumerator _asyncInitialize(Action <Boolean> _action_initialized) { String app_res_config_path = ResInfo.GetWWWLoadPath("res_config", AssetLocation.StreamingPath); Log.Debug(eLogType.Resources, app_res_config_path); using (WWW www = new WWW(app_res_config_path)) { yield return(www); if (!String.IsNullOrEmpty(www.error)) // 加载错误 { Log.Error(eLogType.Resources, "[ResourceManager]: In App res_config assetbundle 加载失败!: {0}", www.error); _action_initialized(false); yield break; } ResConfigFile app_res_config = ResConfigFile.Create(www.bytes); if (app_res_config == null) // 解析错误 { Log.Error(eLogType.Resources, "[ResourceManager]: In App res_config 解析错误!"); _action_initialized(false); yield break; } mLoadResConfig = ResConfigFile.Create(ResUtility.LocalResConfigPath, true); if (mLoadResConfig == null) // 保存用assetsconfig 创建或读取错误 { app_res_config = null; Log.Error(eLogType.Resources, "[ResouceManager]: Saved res_config file 创建或解析错误!"); _action_initialized(false); yield break; } _action_initialized(true); } }
/// <summary> /// 初始化资源管理器 /// </summary> /// <param name="_updateByAppConfig">是否使用app内config更新列表,在更新完成之后重新初始化时不需要更新</param> /// <returns></returns> public Boolean Initialize(Boolean _updateByAppConfig) { String appResConfigPath = String.Concat(Application.streamingAssetsPath, "/res/res_config.grt"); var assetbundleAppResConfig = AssetBundle.LoadFromFile(appResConfigPath); if (assetbundleAppResConfig == null) { Log.Critical("[ResourceManager.Initialize]:读取inapp res config 失败! assetbundle 加载失败!"); return(false); } var appResConfigBytes = assetbundleAppResConfig.LoadAsset <TextAsset>("res_config"); if (appResConfigBytes == null) { Log.Critical("[ResourceManager.Initialize]:读取inapp res config 失败! TextAsset加载失败"); assetbundleAppResConfig.Unload(true); return(false); } var appResConfig = ResConfigFile.Create(appResConfigBytes.bytes); if (appResConfig == null) { Log.Critical(eLogType.Resources, "[ResourceManager.Initialize]: 读取inapp res config 失败! 解析失败!"); assetbundleAppResConfig.Unload(true); return(false); } assetbundleAppResConfig.Unload(true); mLoadResConfig = ResConfigFile.Create(ResUtility.LocalResConfigPath, true); if (mLoadResConfig == null) { Log.Error(eLogType.Resources, "[ResouceManager]: Local res config file 创建失败!"); return(false); } // 首次初始化时执行 if (_updateByAppConfig) { mLoadResConfig.UpdateByAppResConfig(appResConfig); } mLoadResConfig.TraverseAssets(_info => { m_res_dictionary.Add(_info.Name, _createResourceData(_info)); }); // 读取依赖 var assetbundleManifest = AssetBundle.LoadFromFile(GetResource("res.grt").ResouceInfo.SystemApiLoadingPath); AssetBundleManifest manifest = assetbundleManifest.LoadAsset <AssetBundleManifest>("AssetBundleManifest"); foreach (Resource_Base res in m_res_dictionary.Values) { if (res.ResouceInfo.ResType != ResourceType.AssetBundle) { continue; } Resource_Assetbundle resAssetbundle = res as Resource_Assetbundle; var dependenciesName = manifest.GetDirectDependencies(res.Name); for (int i = 0; i < dependenciesName.Length; i++) { Resource_Assetbundle dependency = GetResource <Resource_Assetbundle>(dependenciesName[i]); if (dependency == null) { Log.Critical(eLogType.Resources, "[ResourceManager.Initialize]: {0}的依赖资源: {1}没有在ResourceConfig中找到! 请尝试重新打包!", res.Name, dependenciesName[i]); return(false); } resAssetbundle.AddDependencies(dependency); } } assetbundleManifest.Unload(true); Log.Debug(eLogType.Resources, "ResourceManager Initialized Done!"); return(true); }
public static void BuildNew(ResUpdatePkg _old_pkg) { //AssetBundle bundle = AssetBundle.LoadFromFile( String.Concat( OUTPUT_TMP, "/data/global_configtest" ) ); //TextAsset g = bundle.LoadAsset<TextAsset>( "global_configtest" ); ////TextAsset r = bundle.LoadAsset<TextAsset>( "rookie_config" ); //bundle.Unload( true ); ////AssetBundle bundle = AssetBundle.LoadFromFile( String.Concat( OUTPUT_TMP, "/ui/ui_main.ui" ) ); //return; FileHelper.DeleteDirectory(OUTPUT_TMP, true); FileHelper.CreateDirectory(OUTPUT_TMP); // 打包Assetbundle BuildPipeline.BuildAssetBundles(OUTPUT_TMP, BUILD_OPTIONS, BUILD_TARGET); AssetBundle assetbundleManifest = null; assetbundleManifest = AssetBundle.LoadFromFile(String.Concat(OUTPUT_TMP, "/res")); AssetBundleManifest manifest = assetbundleManifest.LoadAsset <AssetBundleManifest>("AssetBundleManifest"); String[] allAssetBundles = manifest.GetAllAssetBundles(); // 添加Assetbundle到config var newPkg = new ResUpdatePkg { Version = _old_pkg == null ? 1 : _old_pkg.Version + 1, m_pre_version = _old_pkg }; newPkg.m_res_config = ResConfigFile.Create(String.Concat(OUTPUT_TMP, "/res_config.txt"), true); foreach (String assetBundle in allAssetBundles) { newPkg.m_res_config.BuidlerAndResInfo(OUTPUT_TMP, assetBundle, newPkg.Version); } assetbundleManifest.Unload(true); File.Move(String.Concat(OUTPUT_TMP, "/res"), String.Concat(OUTPUT_TMP, "/res.grt")); newPkg.m_res_config.BuidlerAndResInfo(OUTPUT_TMP, "res.grt", newPkg.Version); // 打包lua文件 GrtFileEditor.Pack("Assets/res/lua", OUTPUT_TMP, "scripts/ui.grt"); newPkg.m_res_config.BuidlerAndResInfo(OUTPUT_TMP, "scripts/ui.grt", newPkg.Version); Boolean hasNewRes = true; // 处理res_config if (newPkg.m_pre_version != null) { hasNewRes = newPkg.m_res_config.BuilderMergeOld(_old_pkg.m_res_config); } if (!hasNewRes) { EditorUtility.DisplayDialog("", "资源无更新!", "确定"); return; } // 保存到版本目录 String version_root = String.Concat(OUTPUT_ROOT, "/", newPkg.Version.ToString()); FileHelper.CreateDirectory(version_root); // 临时保存到Assets下以便打包 newPkg.m_res_config.SaveAs("Assets/res_config.txt", true); File.Copy("Assets/res_config.txt", String.Concat(version_root, "/res_config.txt"), true); File.Copy("Assets/res_config.txt", String.Concat(OUTPUT_ROOT, "/res_config.txt"), true); AssetDatabase.Refresh(); BuildPipeline.BuildAssetBundles( OUTPUT_ROOT, new AssetBundleBuild[] { new AssetBundleBuild() { assetBundleName = "res_config.grt", assetNames = new[] { "Assets/res_config.txt" } } }, BUILD_OPTIONS, BUILD_TARGET ); AssetDatabase.Refresh(); File.Copy(String.Concat(OUTPUT_ROOT, "/res_config.grt"), String.Concat(version_root, "/res_config.grt"), true); // 保存的根目录 //new_pkg.m_res_config.SaveAs( String.Concat( OUTPUT_ROOT, "/res_config" ), true ); FileHelper.CreateDirectory(version_root); // copy main assetbundle manifest //File.Copy( String.Concat( OUTPUT_TMP, "/res" ), String.Concat( version_root, "/res" ), true ); newPkg.m_res_config.TraverseAssets( _info => { if (_info.Version != newPkg.Version) { return; } String dest = String.Concat(version_root, "/", _info.Name); FileHelper.CreateDirectoryByFilePath(dest); File.Copy(String.Concat(OUTPUT_TMP, "/", _info.Name), dest, true); }); // 删除指定Assetbundle打包后生成的信息文件(没用) File.Delete(String.Concat(OUTPUT_ROOT, "/update_pkg")); File.Delete(String.Concat(OUTPUT_ROOT, "/update_pkg.manifest")); File.Delete("Assets/res_config.txt"); File.Delete("Assets/res_config.grt"); AssetDatabase.Refresh(); EditorUtility.DisplayDialog("成功", "打包完成!", "确定"); }
/// <summary> /// 反序列化ResouceConfigFile /// </summary> /// <param name="_file_path"></param> /// <param name="_bytes"></param> /// <param name="_create_if_err"></param> /// <returns></returns> private static ResConfigFile _deserialize(String _file_path, Byte[] _bytes, Boolean _create_if_err) { ResConfigFile res_config = new ResConfigFile() { m_file_path = _file_path }; try { using (MemoryStream memory_stream = new MemoryStream(_bytes)) { using (StreamReader reader = new StreamReader(memory_stream, Encoding.UTF8)) { if (!Equals(Encoding.UTF8, reader.CurrentEncoding)) { throw new ConfigFileNotUTF8("AssetsConfig file with {0} encoding not UTF-8!", reader.CurrentEncoding.EncodingName); } if (reader.EndOfStream) { return(res_config); } Int32 line_count = 0; while (!reader.EndOfStream) { String line = reader.ReadLine(); if (String.IsNullOrEmpty(line)) { continue; } line_count++; String[] parts = line.Split('\t'); //#if UNITY_EDITOR // if( parts.Length != 8 && parts.Length != 9 ) //#else // if( parts.Length != 8 ) //#endif // throw new Exception( "Assetsinfo size error" ); String name = parts[0]; Int64 size = Int64.Parse(parts[1], NumberStyles.None); Int32 version = Int32.Parse(parts[2]); AssetLocation location = Configuration.ParseEnum <AssetLocation>(parts[3]); String sha1 = parts[4]; String md5 = parts[5]; UInt32 crc32 = UInt32.Parse(parts[6], NumberStyles.None); ResourceType resource_type = Configuration.ParseEnum <ResourceType>(parts[7]); ResInfo res = new ResInfo(name, size, version, sha1, md5, crc32, location, resource_type); #if UNITY_EDITOR if (parts.Length == 9) { res.AssetBundleTypeTreeHash = parts[8]; } #endif // 处理版本号 if (version > res_config.ResVersion) { res_config.ResVersion = version; } res_config.m_assets.Add(res); } } } } catch (Exception e) { if (_create_if_err) { Log.Error("解析 AssetsConfig 文件失败! 创建新文件"); return(new ResConfigFile() { m_file_path = _file_path }); } Log.Error("解析 AssetsConfig 文件失败!\tMessage: {0}\nStackTrace: {1} {2}", e.Message, e.StackTrace, e.ToString()); res_config = null; } return(res_config); }