/**************************************************** 文件:BuildAssetWindow.cs 作者:xosmo_ 邮箱: 日期:2025/3/10 10:43:20 功能: *****************************************************/ using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Sirenix.OdinInspector; using Sirenix.OdinInspector.Editor; using UnityEditor; using UnityEngine; using YooAsset; using YooAsset.Editor; namespace Stary.Evo.Editor { public class BuildArtAssetWindow : OdinEditorWindow { public static OdinEditorWindow window; private HotfixMainResDomain hotfixMainResDomain; [MenuItem("Evo/Art/Art资源打包工具", false, 1)] static void ShowWindows() { window = (BuildArtAssetWindow)EditorWindow.GetWindow(typeof(BuildArtAssetWindow)); window.Show(); } protected override void OnDisable() { base.OnDisable(); EditorUtility.ClearProgressBar(); packageName = ""; } protected override async void Initialize() { base.Initialize(); GetBuildPackageNames(); //初始化打包管线 _buildPipelineViewer = new ScriptableBuildPipelineViewer(packageName, EBuildPipeline.ScriptableBuildPipeline.ToString(), _packageVersion); _buildPipelineViewer.clearBuildCacheToggle = true; _buildPipelineViewer.useAssetDependencyDBToggle = false; _buildPipelineViewer.SetBuildCacheToggle(); _buildPipelineViewer.SetUseAssetDependencyDB(); } public static void RemoveBuildAssetWindow() { if (window != null) window.Close(); } [BoxGroup("Build", showLabel: false)] [Title("包裹列表", titleAlignment: TitleAlignments.Centered)] [HorizontalGroup("Build/BuildPipeline"), HideLabel] [ValueDropdown("GetBuildPackageNames")] [OnValueChanged("SetBuildPackageNames")] public string selectedPackageNames; [BoxGroup("Build", showLabel: false)] [Title("当前打包平台", titleAlignment: TitleAlignments.Centered)] [ReadOnly] [HorizontalGroup("Build/BuildPipeline"), HideLabel] public string buildTarget; private static string packageName; [Title("版本号", titleAlignment: TitleAlignments.Centered)] [HorizontalGroup("Build/PackageVersion"), HideLabel] [OnValueChanged("OnPackageValueChanged")] public string _packageVersion; private string PackageVersion { get { return _packageVersion; } set { _packageVersion = value; if (_buildPipelineViewer != null) _buildPipelineViewer.SetBuildPackagePackageVersion(_packageVersion); } } private AbstractBuildPipelineViewer _buildPipelineViewer; #region BuildAsset public void OnPackageValueChanged() { if (_buildPipelineViewer != null) _buildPipelineViewer.SetBuildPackageData(packageName, EBuildPipeline.ScriptableBuildPipeline.ToString(), _packageVersion); } /// /// 检测当前所有包裹 /// /// private List GetBuildPackageNames() { List result = new List(); foreach (var name in ArtLoadAssetLocal.GetLocalDomainAllName()) { result.Add(name); } if (selectedPackageNames.IsNullOrEmpty()) { if (result.Count > 0) { selectedPackageNames = result[0]; } else { selectedPackageNames = ""; } } SetBuildPackageNames(); return result; } /// /// 获取当前包裹 /// /// public static string GetBuildPackageName() { return packageName; } /// /// 设置当前包裹 /// /// private void SetBuildPackageNames() { if (selectedPackageNames != packageName) { GetHostBuildPackageVersion(); Init(); } packageName = selectedPackageNames; OnPackageValueChanged(); } #endregion #region Update [BoxGroup("Build", showLabel: false)] [Title("打包本地资源", titleAlignment: TitleAlignments.Centered)] [HideLabel] public BuildAssetEntity onBuildPipelineEntity; [BoxGroup("Build", showLabel: false)] [Title("上传资源", titleAlignment: TitleAlignments.Centered)] [HideLabel] public BuildAssetEntity onUpdateBuildPipelineEntity; private void OnBuildPipeline() { if (EditorUtility.DisplayDialog("提示", $"开始构建资源包[{selectedPackageNames}],版本号为[{_buildPipelineViewer.packageVersion}]!", "Yes", "No")) { EditorTools.ClearUnityConsole(); MarkAdressable.AddArtMark(() => { EditorApplication.delayCall += _buildPipelineViewer.ExecuteBuild; }); } else { Debug.LogWarning("[Build] 打包已经取消"); } } private async void OnUpdateBuildPipeline() { if (EditorUtility.DisplayDialog("提示", $"开始上传至服务器[{selectedPackageNames}],,版本号为[{_buildPipelineViewer.packageVersion}", "Yes", "No")) { // 新增:打包为zip的逻辑 string zipFilePath = BuildZip(); await UpdateFileDataResDomain(zipFilePath); await Task.Delay(1000); EditorUtility.ClearProgressBar(); } else { EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("提示", "Update] 上传已经取消", "确定"); Debug.LogWarning("[Update] 上传已经取消"); } } public string BuildZip() { EditorUtility.DisplayProgressBar("提示", $"开始上传{packageName}(打包zip)", 0.0f); // 新增:打包为zip的逻辑 string zipFileName = $"{packageName}_{_packageVersion}.zip"; //原yooAsset目录 var outputPackageDirectory = $"{AssetBundleBuilderHelper.GetDefaultBuildOutputRoot()}/{EditorUserBuildSettings.activeBuildTarget}/{packageName}"; //拷贝目录 string outFilePath = $"{outputPackageDirectory}/{_packageVersion}"; var copyPackageDirectory = $"{Application.streamingAssetsPath}/{YooAssetSettingsData.GetDefaultYooFolderName()}/{packageName}"; //拷贝BuildinCatalog文件 CreateBuildinCatalogFile("BuildinCatalog.json", copyPackageDirectory, outFilePath); CreateBuildinCatalogFile("BuildinCatalog.bytes", copyPackageDirectory, outFilePath); //输出目录 string zipFilePath = Path.Combine(outputPackageDirectory, zipFileName); try { using (FileStream zipStream = new FileStream(zipFilePath, FileMode.Create)) using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)) { // 指定需要压缩的后缀(例如:只压缩.json和.dll文件) //string[] targetExtensions = { ".bundle" }; // 遍历目录下所有文件 // foreach (string filePath in Directory.GetFiles(outFilePath, "*.*", SearchOption.AllDirectories) // .Where(f => targetExtensions.Contains(Path.GetExtension(f), // StringComparer.OrdinalIgnoreCase))) foreach (string filePath in Directory.GetFiles(outFilePath, "*.*", SearchOption.AllDirectories)) { // 获取文件在压缩包中的相对路径 string entryName = Path.GetRelativePath(outFilePath, filePath); // 创建zip条目 ZipArchiveEntry entry = archive.CreateEntry(entryName, System.IO.Compression.CompressionLevel.Optimal); // 写入文件内容 using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (Stream entryStream = entry.Open()) { fileStream.CopyTo(entryStream); } } } Debug.Log($"成功打包为zip:{zipFilePath}"); EditorUtility.DisplayProgressBar("提示", $"开始上传{packageName}(打包zip)", 0.25f); return zipFilePath; } catch (Exception ex) { Debug.LogError($"打包zip失败:{ex.Message}"); EditorUtility.ClearProgressBar(); return default; } } private static void CreateBuildinCatalogFile(string fileName, string copyPackageDirectory, string outFilePath) { // 假设 BuildinCatalog 文件名为 BuildinCatalog.json string sourcePath = Path.Combine(copyPackageDirectory, fileName); // 源文件路径 string destinationPath = Path.Combine(outFilePath, fileName); // 目标文件路径 // 如果目标文件已存在,则覆盖 if (File.Exists(destinationPath)) { File.Delete(destinationPath); } // 执行拷贝操作 File.Copy(sourcePath, destinationPath); } public async Task UpdateFileDataResDomain(string zipFilePath) { string ip = EditorPrefs.GetString("ip"); var messageEntity = await WebRequestSystem.PostFile(ip + "/FileLoad/UpLoadFile", new[] { zipFilePath }); EditorUtility.DisplayProgressBar("提示", $"开始上传{packageName}(上传zip文件)", 0.5f); if (messageEntity.code == 200) { List resultMessageEntities = JsonConvert.DeserializeObject>(messageEntity.data.ToString()); if (resultMessageEntities.Count > 0) { EditorUtility.DisplayProgressBar("提示", "开始上传(更新数据库)", 0.75f); foreach (var resultMessageEntity in resultMessageEntities) { var data = JsonConvert.DeserializeObject(resultMessageEntity.data.ToString()) as JObject; string fileId = data["id"].ToString(); ResDmainAddRequst resDmainAddRequst = new ResDmainAddRequst() { ProductName = Application.identifier, DomainName = packageName, Platform = EditorUserBuildSettings.activeBuildTarget.ToString(), PackageVersion = _packageVersion, DocumentFileId = fileId }; var resResultMessage = await WebRequestSystem.Post(ip + "/ResDomain/AddResDomain", JsonConvert.SerializeObject(resDmainAddRequst)); //如果低于服务器版本,更新版本号 if (resResultMessage.code == 4100) { ResDmainVersionResponse dmainVersionResponse = JsonConvert.DeserializeObject(resResultMessage.data .ToString()); if (dmainVersionResponse.PackageVersion == _packageVersion) { EditorUtility.DisplayDialog("提示", $"上传失败,版本号{_packageVersion}跟服务器版本重复,请修改版本号后,重新打包上传", "确定"); EditorUtility.ClearProgressBar(); return; } } else if (resResultMessage.code == 200) { EditorUtility.DisplayDialog("提示", $"上传成功,已更新为{_packageVersion}", "确定"); } } EditorUtility.DisplayProgressBar("提示", $"开始上传{packageName}(更新数据库)", 1f); } } else { EditorUtility.DisplayProgressBar("提示", $"{messageEntity.message}", 1f); } await Task.Delay(1000); EditorUtility.ClearProgressBar(); return; } /// /// 获取服务器上版本号 /// private async void GetHostBuildPackageVersion() { var resDmainAddRequst = new ResDmainRequst() { ProductName = Application.identifier, DomainName = selectedPackageNames, Platform = EditorUserBuildSettings.activeBuildTarget.ToString(), }; string ip = EditorPrefs.GetString("ip"); var resResultMessage = await WebRequestSystem.Post(ip + "/ResDomain/GetResDomainByDomain", JsonConvert.SerializeObject(resDmainAddRequst)); //如果低于服务器版本,更新版本号 if (resResultMessage.code != 1011) { if (resResultMessage.data != null) { ResDmainResponse domainResponse = JsonConvert.DeserializeObject(resResultMessage.data .ToString()); PackageVersion = domainResponse.PackageVersion; } else { Debug.LogError($"UnityEvo:获取服务器版本失败,resResultMessage.data为空"); } } else { EditorUtility.DisplayDialog("提示", $"{resResultMessage.message},默认test_1.0版本 ", "确定"); PackageVersion = "test_1.0"; } } #endregion protected void Init() { //Update buildTarget = EditorUserBuildSettings.activeBuildTarget.ToString(); onBuildPipelineEntity = new BuildAssetEntity("打包", $"打包资源包【版本:{_packageVersion}】", OnBuildPipeline); onUpdateBuildPipelineEntity = new BuildAssetEntity("更新", $"更新至服务器【版本:{_packageVersion}】", OnUpdateBuildPipeline); } private Vector2 scroll; protected override void DrawEditor(int index) { scroll = GUILayout.BeginScrollView(scroll); { base.DrawEditor(index); } GUILayout.EndScrollView(); UpdateBuildPipelineButtonName(); } public void UpdateBuildPipelineButtonName() { onBuildPipelineEntity.SetButtonName($"打包资源包【版本:{_packageVersion}】"); onUpdateBuildPipelineEntity.SetButtonName($"更新至服务器【版本:{_packageVersion}】"); } } }