/// <summary> /// 脚本加载入口 /// </summary> /// <param name="loadPathTypeType"></param> /// <param name="runMode"></param> /// <param name="mainProjectTypes">UPM隔离了dll,需要手动传入</param> static public void Init(AssetLoadPathType loadPathTypeType, HotfixCodeRunMode runMode, Type[] mainProjectTypes, Action <bool> clrBindingAction) { CLRBindAction = clrBindingAction; if (loadPathTypeType == AssetLoadPathType.Editor) { BDebug.Log("【ScriptLaunch】Editor(非热更)模式!"); //反射调用,防止编译报错 var assembly = Assembly.GetExecutingAssembly(); var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); //添加框架部分的type,热更下不需要,打包会把框架的部分打进去 var list = new List <Type>(); list.AddRange(mainProjectTypes); list.AddRange(typeof(BDLauncher).Assembly.GetTypes()); method.Invoke(null, new object[] { list.ToArray(), null }); } else { BDebug.Log("【ScriptLaunch】热更模式!"); var path = GameConfig.GetLoadPath(loadPathTypeType); path = Path.Combine(path, BApplication.GetRuntimePlatformPath()); //加载dll var dllPath = Path.Combine(path, DLL_PATH); LoadHotfixDLL(dllPath, runMode, mainProjectTypes); } }
/// <summary> /// 初始化 /// </summary> /// <param name="rootPath"></param> public void Init(string rootPath) { //多热更切换,需要卸载 if (this.AssetConfigLoder != null) { this.UnloadAllAsset(); } var platformPath = BApplication.GetRuntimePlatformPath(); //1.设置加载路径 if (Application.isEditor) { firstArtDirectory = IPath.Combine(rootPath, platformPath, BResources.ART_ASSET_ROOT_PATH); secArtDirectory = IPath.Combine(Application.streamingAssetsPath, platformPath, BResources.ART_ASSET_ROOT_PATH); // } else { firstArtDirectory = IPath.Combine(Application.persistentDataPath, platformPath, BResources.ART_ASSET_ROOT_PATH); secArtDirectory = IPath.Combine(Application.streamingAssetsPath, platformPath, BResources.ART_ASSET_ROOT_PATH); // } //2.路径替换 firstArtDirectory = IPath.ReplaceBackSlash(firstArtDirectory); secArtDirectory = IPath.ReplaceBackSlash(secArtDirectory); //3.加载ArtConfig this.AssetConfigLoder = new AssetbundleConfigLoder(); var assetconfigPath = ""; var assetTypePath = ""; if (Application.isEditor) { assetconfigPath = IPath.Combine(rootPath, platformPath, BResources.ART_ASSET_CONFIG_PATH); assetTypePath = IPath.Combine(rootPath, platformPath, BResources.ART_ASSET_TYPES_PATH); } else { //真机环境config在persistent,跟dll和db保持一致 assetconfigPath = IPath.Combine(Application.persistentDataPath, platformPath, BResources.ART_ASSET_CONFIG_PATH); assetTypePath = IPath.Combine(Application.persistentDataPath, platformPath, BResources.ART_ASSET_TYPES_PATH); } this.AssetConfigLoder.Load(assetconfigPath, assetTypePath); //开始异步任务刷新 IEnumeratorTool.StartCoroutine(this.IE_AsyncTaskListUpdte()); BDebug.Log($"【AssetBundleV2】 firstDir:{firstArtDirectory}", "red"); BDebug.Log($"【AssetBundleV2】 secDir:{secArtDirectory}", "red"); }
/// <summary> /// 打包ShaderOnly /// </summary> public static void BuildShadersAssetBundle() { AssetDatabase.StartAssetEditing(); { CollectShaderVariant(); var guid = AssetDatabase.AssetPathToGUID(BResources.ALL_SHADER_VARAINT_ASSET_PATH); List <AssetImporter> list = new List <AssetImporter>(); //依赖信息 var dependice = AssetDatabase.GetDependencies(BResources.ALL_SHADER_VARAINT_ASSET_PATH); foreach (var depend in dependice) { var type = AssetDatabase.GetMainAssetTypeAtPath(depend); if (type == typeof(Material) || type == typeof(ShaderVariantCollection)) { var ai = AssetImporter.GetAtPath(depend); ai.SetAssetBundleNameAndVariant(guid, null); Debug.Log("打包:" + depend); list.Add(ai); } } //开始编译 var outpath = IPath.Combine(BApplication.Library, "BDBuildTest", BApplication.GetRuntimePlatformPath()); if (Directory.Exists(outpath)) { Directory.Delete(outpath, true); } Directory.CreateDirectory(outpath); // var buildtarget = BApplication.GetBuildTarget(BApplication.RuntimePlatform); UnityEditor.BuildPipeline.BuildAssetBundles(outpath, BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.ChunkBasedCompression, buildtarget); // foreach (var ai in list) { ai.SetAssetBundleNameAndVariant(null, null); } Debug.Log("测试AB已经输出:" + outpath); } AssetDatabase.StopAssetEditing(); }
/// <summary> /// 初始化 /// </summary> /// <param name="rootPath"></param> public void Init(string rootPath, RuntimePlatform platform = RuntimePlatform.Android) { //多热更切换,需要卸载 if (this.AssetConfigLoder != null) { this.UnloadAllAsset(); } //平台 string platformPath = ""; //1.设置加载路径 if (Application.isEditor) { //editor下可以自行输入 platformPath = BApplication.GetPlatformPath(platform); firstArtDirectory = IPath.Combine(rootPath, platformPath, BResources.ART_ASSET_ROOT_PATH); secArtDirectory = IPath.Combine(Application.streamingAssetsPath, platformPath, BResources.ART_ASSET_ROOT_PATH); // } else { //runtime只能使用当前平台 platformPath = BApplication.GetRuntimePlatformPath(); firstArtDirectory = IPath.Combine(Application.persistentDataPath, platformPath, BResources.ART_ASSET_ROOT_PATH); secArtDirectory = IPath.Combine(Application.streamingAssetsPath, platformPath, BResources.ART_ASSET_ROOT_PATH); // rootPath = Application.persistentDataPath; } //2.寻址路径格式化 firstArtDirectory = IPath.FormatPathOnRuntime(firstArtDirectory); secArtDirectory = IPath.FormatPathOnRuntime(secArtDirectory); //3.加载ArtConfig this.AssetConfigLoder = GetAssetbundleConfigLoder(rootPath, platformPath); //开始异步任务刷新 IEnumeratorTool.StartCoroutine(this.IE_LoadTaskUpdate()); IEnumeratorTool.StartCoroutine(this.IE_UnLoadTaskUpdate()); BDebug.Log($"【AssetBundleV2】 firstDir:{firstArtDirectory}", "red"); BDebug.Log($"【AssetBundleV2】 secDir:{secArtDirectory}", "red"); }
/// <summary> /// 一键导出 /// </summary> public void OnGUI_OneKeyExprot() { GUILayout.BeginVertical(GUILayout.Width(this.maxSize.x / 2), GUILayout.Height(350)); { GUILayout.Label("资源发布:", EditorGUIHelper.GetFontStyle(Color.red, 15)); EditorGUILayout.HelpBox("版本号采用三段式:0.0.1,前两位可以自定义,最后一位默认自增!\n默认导出地址:Devops/PublishAssets", MessageType.Info); GUILayout.Space(5); // foreach (var sp in BApplication.SupportPlatform) { GUILayout.BeginHorizontal(); { var isHas = selectPlatforms.Contains(sp); //选择 var isSelcet = GUILayout.Toggle(isHas, $"生成{BApplication.GetPlatformPath(sp)}资产", GUILayout.Width(150)); // if (isHas != isSelcet) { if (isSelcet) { selectPlatforms.Add(sp); } else { selectPlatforms.Remove(sp); } } var basePackageBuildInfo = BasePackageAssetsHelper.GetPacakgeBuildInfo(EXPORT_PATH, sp); string setVersionNum = ""; var ret = platformVersionMap.TryGetValue(sp, out setVersionNum); if (!ret) { platformVersionMap[sp] = basePackageBuildInfo.Version; } //根据即将设置信息开始解析 var vs = platformVersionMap[sp].Split('.'); int bigNum = 0; int smallNum = 0; int additiveNum = 0; bigNum = int.Parse(vs[0]); smallNum = int.Parse(vs[1]); additiveNum = int.Parse(vs[2]); //version.info信息 渲染 GUILayout.Label("Ver:", GUILayout.Width(30)); bigNum = EditorGUILayout.IntField(bigNum, GUILayout.Width(20)); GUILayout.Label(".", GUILayout.Width(5)); smallNum = EditorGUILayout.IntField(smallNum, GUILayout.Width(20)); GUILayout.Label(".", GUILayout.Width(5)); GUILayout.Label(additiveNum.ToString(), GUILayout.Width(40)); //保存 设置信息 setVersionNum = string.Format("{0}.{1}.{2}", bigNum, smallNum, additiveNum); //渲染预览信息 GUILayout.Space(10); var newVersion = VersionNumHelper.AddVersionNum(basePackageBuildInfo.Version, setVersionNum); GUILayout.Label($"预览: {basePackageBuildInfo.Version} => {newVersion}"); platformVersionMap[sp] = setVersionNum; } GUILayout.EndHorizontal(); GUILayout.Space(2); } // GUILayout.Space(5); if (GUILayout.Button("一键导出所选平台资产(脚本、美术、表格)", GUILayout.Width(350), GUILayout.Height(30))) { if (isBuilding) { return; } isBuilding = true; //开始 生成资源 foreach (var sp in selectPlatforms) { BuildAssetsTools.BuildAllAssets(sp, EXPORT_PATH, platformVersionMap[sp]); platformVersionMap.Remove(sp); } isBuilding = false; } // if (GUILayout.Button("热更资源转hash(生成服务器配置)", GUILayout.Width(350), GUILayout.Height(30))) { //自动转hash PublishPipelineTools.PublishAssetsToServer(EXPORT_PATH); } GUILayout.Space(20); GUILayout.Label("调试功能:", EditorGUIHelper.LabelH4); GUILayout.BeginHorizontal(); { if (GUILayout.Button("拷贝资源到Streaming", GUILayout.Width(175), GUILayout.Height(30))) { //路径 var source = IPath.Combine(EXPORT_PATH, BApplication.GetRuntimePlatformPath()); var target = IPath.Combine(Application.streamingAssetsPath, BApplication.GetRuntimePlatformPath()); if (Directory.Exists(target)) { Directory.Delete(target, true); } //拷贝 FileHelper.CopyFolderTo(source, target); AssetDatabase.Refresh(); } if (GUILayout.Button("删除Streaming资源", GUILayout.Width(175), GUILayout.Height(30))) { var target = IPath.Combine(Application.streamingAssetsPath, BApplication.GetRuntimePlatformPath()); Directory.Delete(target, true); } } } GUILayout.EndHorizontal(); GUILayout.EndVertical(); }
/// <summary> /// 开始版本控制逻辑 /// </summary> /// <param name="serverUrl">服务器配置根目录</param> /// <param name="localSaveAssetsPath">本地根目录</param> /// <param name="onDownloadProccess">任务进度通知(下载完不等于任务完成!)</param> /// <param name="onTaskEndCallback">任务成功\失败通知!</param> /// 返回码: -1:error 0:success async private Task StartVersionControl(UpdateMode updateMode, string serverUrl, string localSaveAssetsPath, string subPackageName, Action <AssetItem, List <AssetItem> > onDownloadProccess, Action <RetStatus, string> onTaskEndCallback) { var platform = BApplication.RuntimePlatform; //目录准备 var platformStr = BApplication.GetRuntimePlatformPath(); var localSavePlatformPath = IPath.Combine(localSaveAssetsPath, platformStr); if (!Directory.Exists(localSavePlatformPath)) { Directory.CreateDirectory(localSavePlatformPath); } //子包模式判断 bool isDownloadSubPackageMode = !string.IsNullOrEmpty(subPackageName); //1.下载服务器version config var serverVersionInfo = new AssetsVersionInfo(); var localVersionInfo = new AssetsVersionInfo(); #region AssetVersion.info下载 BDebug.Log("【版本控制】1.获取版本信息~", "red"); { var ret = await DownloadAssetVersionInfo(serverUrl, localSaveAssetsPath); if (ret.Item1 != null) { await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Error, ret.Item1); return; } serverVersionInfo = ret.Item2; localVersionInfo = ret.Item3; } #endregion //2.对比版本、获取对应数据 BDebug.Log("【版本控制】2.对比版本信息~", "red"); string err = null; string suc = null; var serverAssetsInfoList = new List <AssetItem>(); var localAssetsInfoList = new List <AssetItem>(); var serverAssetsContent = ""; // switch (updateMode) { case UpdateMode.Compare: case UpdateMode.CompareWithRepair: //CP模式对比版本与Compare一致 { if (isDownloadSubPackageMode) { //分包模式 (err, suc, serverAssetsInfoList, localAssetsInfoList, serverAssetsContent) = GetDownloadSubPackageData(serverUrl, subPackageName, platform, serverVersionInfo, localVersionInfo); } else { //全量下载 (err, suc, serverAssetsInfoList, localAssetsInfoList, serverAssetsContent) = GetDownloadAssetsData(serverUrl, platform, serverVersionInfo, localVersionInfo); } } break; case UpdateMode.Repair: { //服务器路径 var serverAssetInfosUrl = BResources.GetAssetsInfoPath(serverUrl, platform); //下载服务器Assets.info (err, serverAssetsInfoList, serverAssetsContent) = LoadServerAssetInfo(serverAssetInfosUrl); } break; } //返回返回结果,是否继续下载 if (err != null) { BDebug.LogError(err); await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Error, err); return; } if (suc != null) { BDebug.Log(suc); await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Success, suc); return; } //3.生成差异列表 BDebug.Log("【版本控制】3.获取差异列表~", "red"); Queue <AssetItem> diffDownloadQueue = null; #region 生成差异文件 switch (updateMode) { case UpdateMode.Compare: { diffDownloadQueue = Compare(localAssetsInfoList, serverAssetsInfoList, platform); } break; case UpdateMode.Repair: case UpdateMode.CompareWithRepair: //CP 获取差异模式与Repair一致 { diffDownloadQueue = Repair(serverAssetsInfoList, platform); } break; } BDebug.Log($"【版本控制】 配置数量:{serverAssetsInfoList.Count} ,本地存在{serverAssetsInfoList.Count - diffDownloadQueue.Count},下载文件数量{diffDownloadQueue.Count}", "yellow"); #endregion //4.开始下载 #region 根据差异文件下载 BDebug.Log("【版本控制】4.下载资源~", "red"); { var failDownloadList = await DownloadAssets(serverUrl, localSaveAssetsPath, diffDownloadQueue, onDownloadProccess); if (failDownloadList.Count > 0) { onTaskEndCallback(RetStatus.Error, "部分资源未下载完毕!"); return; } } #endregion //5.写入配置到本地 #region 存储配置到本地 BDebug.Log("【版本控制】5.写入配置~", "red"); string localAssetInfoPath = ""; if (isDownloadSubPackageMode) { localAssetInfoPath = BResources.GetAssetsSubPackageInfoPath(BApplication.persistentDataPath, platform, subPackageName); } else { localAssetInfoPath = BResources.GetAssetsInfoPath(BApplication.persistentDataPath, platform); } //写入Asset.Info File.WriteAllText(localAssetInfoPath, serverAssetsContent); BDebug.Log($"【版本控制】写入{Path.GetFileName(localAssetInfoPath)} \n {serverAssetsContent}"); //写入Version.Info if (isDownloadSubPackageMode) { localVersionInfo.Platfrom = serverVersionInfo.Platfrom; //子包版本信息 localVersionInfo.SubPckMap[subPackageName] = serverVersionInfo.SubPckMap[subPackageName]; } else { localVersionInfo.Platfrom = serverVersionInfo.Platfrom; //全量包信息 localVersionInfo.Version = serverVersionInfo.Version; } var localAssetsVersionInfoPath = BResources.GetServerAssetsVersionInfoPath(localSaveAssetsPath, platform); File.WriteAllText(localAssetsVersionInfoPath, JsonMapper.ToJson(localVersionInfo)); BDebug.Log($"【版本控制】写入{Path.GetFileName(localAssetsVersionInfoPath)}"); #endregion // 6.删除过期资源 BDebug.Log("【版本控制】6.冗余资源检查~", "red"); if (!isDownloadSubPackageMode) { var artAssetsPath = IPath.Combine(localSavePlatformPath, BResources.ART_ASSET_ROOT_PATH); var persistentArtAssets = Directory.GetFiles(artAssetsPath, "*", SearchOption.AllDirectories); var replacePath = localSavePlatformPath + "/"; foreach (var assetPath in persistentArtAssets) { var localPath = assetPath.Replace(replacePath, "").Replace("\\", "/"); var ret = serverAssetsInfoList.FirstOrDefault((info) => info.LocalPath.Equals(localPath)); if (ret == null) { BDebug.Log("【版本控制】删除过期资源:" + localPath); File.Delete(assetPath); } } } // 7.资源校验文件 BDebug.Log("【版本控制】7.整包资源校验~", "red"); err = null; foreach (var serverAssetItem in serverAssetsInfoList) { var ret = BResources.IsExsitAssetWithCheckHash(platform, serverAssetItem.LocalPath, serverAssetItem.HashName); if (!ret) { if (string.IsNullOrEmpty(err)) { err = "资源不存在:"; } err += $"\n {serverAssetItem.LocalPath}"; } } //the end. BDebug.Log("【版本控制】end.完成~", "red"); await UniTask.SwitchToMainThread(); if (err == null) { onTaskEndCallback?.Invoke(RetStatus.Success, null); } else { onTaskEndCallback?.Invoke(RetStatus.Error, err); } }