/// <summary> /// 生成sqlite /// 默认导出到当前平台目录下 /// </summary> /// <param name="ouptputPath">自定义路径</param> public static void AllExcel2SQLite(string ouptputPath, RuntimePlatform platform, DBType dbType = DBType.Local) { //触发bd环境周期 BDFrameworkPipelineHelper.OnBeginBuildSqlite(); var xlslFiles = ExcelEditorTools.GetAllExcelFiles(); switch (dbType) { case DBType.Local: SqliteLoder.LoadLocalDBOnEditor(ouptputPath, platform); break; case DBType.Server: SqliteLoder.LoadServerDBOnEditor(ouptputPath, platform); break; } { foreach (var f in xlslFiles) { try { Excel2SQLite(f, dbType); } catch (Exception e) { Debug.LogError("导表失败:" + f); EditorUtility.ClearProgressBar(); } } } SqliteLoder.Close(); // EditorUtility.ClearProgressBar(); //触发bd环境周期 BDFrameworkPipelineHelper.OnEndBuildSqlite(ouptputPath); BasePackageAssetsHelper.GenBasePackageAssetBuildInfo(ouptputPath, platform); Debug.Log("导出Sqlite完成!"); }
/// <summary> #region 启动热更逻辑 /// <summary> /// 初始化 /// 修改版本,让这个启动逻辑由使用者自行处理 /// </summary> /// <param name="mainProjectTypes">Editor模式下,UPM隔离了DLL需要手动传入</param> /// <param name="GameId">单游戏更新启动不需要id,多游戏更新需要id号</param> public void Launch(Type[] mainProjectTypes, Action <bool> clrBindingAction, string gameId = "default") { BDebug.Log("【Launch】Persistent:" + Application.persistentDataPath); BDebug.Log("【Launch】StreamingAsset:" + Application.streamingAssetsPath); //主工程启动 IGameStart mainStart; foreach (var type in mainProjectTypes) { //TODO 这里有可能先访问到 IGamestart的Adaptor if (type.IsClass && type.GetInterface(nameof(IGameStart)) != null) { BDebug.Log("【Launch】主工程Start! " + type.FullName); mainStart = Activator.CreateInstance(type) as IGameStart; if (mainStart != null) { //注册 mainStart.Start(); OnUpdate += mainStart.Update; OnLateUpdate += mainStart.LateUpdate; break; } } } BDebug.Log("【Launch】框架资源版本验证!"); //开始资源检测 BasePackageAssetsHelper.CheckBasePackageVersion(BApplication.RuntimePlatform, () => { //1.美术目录 BResources.Init(GameConfig.ArtRoot); //2.sql SqliteLoder.Init(GameConfig.SQLRoot); //3.脚本,这个启动会开启所有的逻辑 ScriptLoder.Init(GameConfig.CodeRoot, GameConfig.CodeRunMode, mainProjectTypes, clrBindingAction); }); }
/// <summary> /// 资源转hash /// </summary> /// <param name="path"></param> /// <param name="uploadHttpApi"></param> static public void PublishAssetsToServer(string path) { foreach (var platform in BApplication.SupportPlatform) { //资源路径 var sourcePath = IPath.Combine(path, BApplication.GetPlatformPath(platform)); //输出路径 var outputPath = IPath.Combine(IPath.ReplaceBackSlash(path), UPLOAD_FOLDER_SUFFIX, BApplication.GetPlatformPath(platform)); if (Directory.Exists(sourcePath)) { //对比Assets.info 是否一致 var sourceAssetsInfoPath = IPath.Combine(sourcePath, BResources.ASSETS_INFO_PATH); var outputAssetsInfoPath = IPath.Combine(outputPath, BResources.ASSETS_INFO_PATH); if (File.Exists(sourceAssetsInfoPath) && File.Exists(outputAssetsInfoPath)) { var sourceHash = FileHelper.GetMurmurHash3(sourceAssetsInfoPath); var outputHash = FileHelper.GetMurmurHash3(outputAssetsInfoPath); if (sourceHash == outputHash) { Debug.Log("【PublishPipeline】资源无改动,无需重新生成服务器文件. -" + BApplication.GetPlatformPath(platform)); continue; } } //获取资源版本号 var basePckInfo = BasePackageAssetsHelper.GetPacakgeBuildInfo(path, platform); var versionNum = basePckInfo.Version; //发布资源处理前,处理前回调 BDFrameworkPipelineHelper.OnBeginPublishAssets(platform, sourcePath, versionNum); //处理资源 var outdir = GenServerHashAssets(path, platform, versionNum); //发布资源处理后,通知回调 BDFrameworkPipelineHelper.OnEndPublishAssets(platform, outdir, versionNum); Debug.Log("发布资源处理完成! 请继承PublishPipeline生命周期,完成后续自动化部署到自己的文件服务器!"); } } }
/// <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> /// 编译DLL /// </summary> static public void BuildDll(string outPath, RuntimePlatform platform, BuildMode mode, bool isShowTips = true) { IsShowTips = isShowTips; if (IsShowTips) { EditorUtility.DisplayProgressBar("编译服务", "准备编译环境...", 0.1f); } try { //生成CSProj EditorApplication.ExecuteMenuItem("Assets/Open C# Project"); } catch { } //准备输出环境 var _outPath = Path.Combine(outPath, BApplication.GetPlatformPath(platform)); try { var path = _outPath + "/Hotfix"; if (Directory.Exists(path)) { Directory.Delete(path, true); } Directory.CreateDirectory(path); } catch (Exception e) { Debug.LogError(e.Message); if (IsShowTips) { EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("提示", "请手动删除hotfix文件后重试!", "OK"); } return; } if (IsShowTips) { EditorUtility.DisplayProgressBar("编译服务", "开始处理脚本", 0.2f); } #region CS DLL引用搜集处理 List <string> dllFileList = new List <string>(); List <string> csFileList = new List <string>(); //所有宏 defineList = new List <string>(); string[] parseCsprojList = new string[] { "Assembly-CSharp.csproj", "BDFramework.Core.csproj" }; foreach (var csproj in parseCsprojList) { var path = Path.Combine(BApplication.ProjectRoot, csproj); if (!File.Exists(path)) { EditorUtility.DisplayDialog("警告", $"请保证csproj存在:\n {csproj}.\n 请在Preferces/ExternalTools 选择 Generate.csproj文件", "OK"); return; } ParseCsprojFile(path, new List <string>() { }, ref csFileList, ref dllFileList); } //去重 dllFileList = dllFileList.Distinct().ToList(); csFileList = csFileList.Distinct().ToList(); defineList = defineList.Distinct().ToList(); //移除参与分析csproj的dll,因为已经解析 包含在cs foreach (var csproj in parseCsprojList) { var dll = csproj.Replace(".csproj", ".dll"); var idx = dllFileList.FindIndex((d) => d.EndsWith(dll, StringComparison.OrdinalIgnoreCase)); if (idx >= 0) { dllFileList.RemoveAt(idx); //Debug.Log("[Build DLL]剔除:" + dll); } } //宏解析 //移除editor相关宏 for (int i = defineList.Count - 1; i >= 0; i--) { var symbol = defineList[i]; if (symbol.Contains("UNITY_EDITOR")) { defineList.RemoveAt(i); } } //剔除不存的dll //TODO 这里是File 接口mac下有bug 会判断文件不存在 if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.OSXEditor) { for (int i = dllFileList.Count - 1; i >= 0; i--) { var dll = dllFileList[i]; if (!File.Exists(dll)) { dllFileList.RemoveAt(i); Debug.Log("剔除:" + dll); } } } #endregion // 热更代码 = 框架部分@hotfix + 游戏逻辑部分@hotfix var baseCs = csFileList.FindAll(f => !f.Contains(STR_HOTFIX) && f.EndsWith(".cs")); //筛选cs //不用ILR binding进行编译base.dll,因为binding本身会因为@hotfix调整容易报错 baseCs = baseCs.Where((cs) => (!cs.Contains("\\ILRuntime\\Binding\\Analysis\\") && !cs.Contains("/ILRuntime/Binding/Analysis/")) || cs.EndsWith("CLRBindings.cs")).ToList(); // var hotfixCs = csFileList.FindAll(f => (f.Contains(STR_HOTFIX) || f.Contains(STR_HALF_HOTFIX)) && f.EndsWith(".cs")); var outHotfixPath = Path.Combine(_outPath, DLLPATH); if (mode == BuildMode.Release) { Build(baseCs, hotfixCs, dllFileList, outHotfixPath); } else if (mode == BuildMode.Debug) { Build(baseCs, hotfixCs, dllFileList, outHotfixPath, true); } BasePackageAssetsHelper.GenBasePackageAssetBuildInfo(outPath, platform); }
/// <summary> /// 构建所有资源 /// </summary> /// <param name="platform">平台</param> /// <param name="outputPath">输出目录</param> /// <param name="setNewVersionNum">新版本号</param> static public void BuildAllAssets(RuntimePlatform platform, string outputPath, string setNewVersionNum = null) { var newVersionNum = ""; //触发事件 var lastPackageBuildInfo = BasePackageAssetsHelper.GetPacakgeBuildInfo(outputPath, platform); var lastVersionNum = lastPackageBuildInfo.Version; //没有指定版本号,则需要触发版本号的实现逻辑 if (string.IsNullOrEmpty(setNewVersionNum)) { BDFrameworkPipelineHelper.OnBeginBuildAllAssets(platform, outputPath, lastVersionNum, out newVersionNum); } //项目没有实现提供新的版本号,则内部提供一个版本号 if (string.IsNullOrEmpty(newVersionNum) || lastVersionNum == newVersionNum) { //没指定版本号 if (string.IsNullOrEmpty(setNewVersionNum)) { newVersionNum = VersionNumHelper.AddVersionNum(lastVersionNum, add: 1); } //指定版本号 else { newVersionNum = VersionNumHelper.AddVersionNum(lastVersionNum, setNewVersionNum); } } //开始构建资源 var _outputPath = Path.Combine(outputPath, BApplication.GetPlatformPath(platform)); if (!Directory.Exists(_outputPath)) { Directory.CreateDirectory(_outputPath); } //1.编译脚本 try { EditorWindow_ScriptBuildDll.RoslynBuild(outputPath, platform, ScriptBuildTools.BuildMode.Release); } catch (Exception e) { Debug.LogError(e.Message); } //2.打包表格 try { Excel2SQLiteTools.AllExcel2SQLite(outputPath, platform); } catch (Exception e) { Debug.LogError(e.Message); } //3.打包资源 try { //var config = BDEditorApplication.BDFrameWorkFrameEditorSetting.BuildAssetBundle; AssetBundleEditorToolsV2.GenAssetBundle(outputPath, platform); } catch (Exception e) { Debug.LogError(e.Message); } //4.生成母包资源信息 BasePackageAssetsHelper.GenBasePackageAssetBuildInfo(outputPath, platform, version: newVersionNum); //5.生成本地Assets.info配置 //这个必须最后生成!!!! //这个必须最后生成!!!! //这个必须最后生成!!!! var allServerAssetItemList = PublishPipelineTools.GetAssetItemList(outputPath, platform); var csv = CsvSerializer.SerializeToString(allServerAssetItemList); var assetsInfoPath = BResources.GetAssetsInfoPath(outputPath, platform); FileHelper.WriteAllText(assetsInfoPath, csv); // Debug.Log($"<color=yellow>{ BApplication.GetPlatformPath(platform)} - 旧版本:{lastPackageBuildInfo.Version} 新版本号:{newVersionNum} </color> "); //完成回调通知 BDFrameworkPipelineHelper.OnEndBuildAllAssets(platform, outputPath, newVersionNum); }
/// <summary> /// 打包Asset Bundle /// </summary> /// <param name="buildAssetsInfo"></param> /// <param name="buildParams"></param> /// <param name="platform"></param> private void BuildAssetBundle(List <AssetBundleItem> assetBundleItemList, BuildAssetsInfo buildAssetsInfo, BuildAssetBundleParams buildParams, RuntimePlatform platform) { //----------------------------开始设置build ab name------------------------------- //根据传进来的资源,设置AB name foreach (var buildInfoItem in buildAssetsInfo.AssetDataMaps) { var assetPath = buildInfoItem.Key; var assetData = buildInfoItem.Value; //设置ab name var ai = GetAssetImporter(assetPath); if (ai) { ai.SetAssetBundleNameAndVariant(assetData.ABName, null); } } //----------------------------生成AssetBundle------------------------------- var platformOutputPath = Path.Combine(buildParams.OutputPath, BApplication.GetPlatformPath(platform)); string abOutputPath = IPath.Combine(platformOutputPath, BResources.ART_ASSET_ROOT_PATH); if (!Directory.Exists(abOutputPath)) { Directory.CreateDirectory(abOutputPath); } //配置 var buildTarget = BApplication.GetBuildTarget(platform); BuildAssetBundleOptions buildOpa = BuildAssetBundleOptions.ChunkBasedCompression | //压缩 BuildAssetBundleOptions.DeterministicAssetBundle | //保证一致 //BuildAssetBundleOptions.DisableWriteTypeTree| //关闭TypeTree BuildAssetBundleOptions.DisableLoadAssetByFileName | BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension; //关闭使用filename加载 //关闭TypeTree var buildAssetConf = BDEditorApplication.BDFrameWorkFrameEditorSetting?.BuildAssetBundle; if (buildAssetConf.IsDisableTypeTree) { buildOpa |= BuildAssetBundleOptions.DisableWriteTypeTree; //关闭TypeTree } UnityEditor.BuildPipeline.BuildAssetBundles(abOutputPath, buildOpa, buildTarget); Debug.LogFormat("【编译AssetBundle】 output:{0} ,buildTarget:{1}", abOutputPath, buildTarget.ToString()); //----------------------------清理------------------------------------- //1.移除所有的ab RemoveAllAssetbundleName(); //2.删除本地没有的资源 var allABList = Directory.GetFiles(abOutputPath, "*", SearchOption.AllDirectories).Where((p) => string.IsNullOrEmpty(Path.GetExtension(p))); foreach (var abpath in allABList) { var abname = Path.GetFileName(abpath); var ret = assetBundleItemList.FirstOrDefault((abdata) => abdata.AssetBundlePath == abname); if (ret == null) { // File.Delete(abpath); File.Delete(abpath + ".manifest"); // var path = AssetDatabase.GUIDToAssetPath(abname); Debug.Log("【删除旧ab:】" + abname + " - " + path); } } //3.检测本地Assetbundle // allAbList = Directory.GetFiles(abOutputPath, "*", SearchOption.AllDirectories); // foreach (var abpath in allAbList) // { // if (abpath.Contains(".")) // { // continue; // } // // var depend = AssetDatabase.GetAssetBundleDependencies(abpath,true); // } BasePackageAssetsHelper.GenBasePackageAssetBuildInfo(buildParams.OutputPath, platform); }