Files
plugin-library/Assets/00.StaryEvo/Editor/BuildAsset/BuildAssetWindow.cs
2025-09-23 12:23:39 +08:00

548 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/****************************************************
文件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;
#if HotUpdate
using HybridCLR.Editor;
using HybridCLR.Editor.Commands;
#endif
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 BuildAssetWindow : OdinEditorWindow
{
public static OdinEditorWindow window;
[MenuItem("Evo/资源打包工具")]
static void ShowWindows()
{
#if NotUpdate
if (EditorUtility.DisplayDialog("提示", "当前为非热更模式,不支持热更打包功能,是否切换热更模式", "是", "否"))
{
ChangeHotUpdateSchema.SetHotUpdateMode(HotUpdateMode.HotUpdate);
}
#elif HotUpdate
if (CreatAssetWindow.GetCreatDomainAll().Count <= 0)
{
EditorUtility.DisplayDialog("提示", "不存在Domain元素无法打开此面板请先创建Domain元素", "确定");
return;
}
window = (BuildAssetWindow)EditorWindow.GetWindow(typeof(BuildAssetWindow));
window.Show();
#endif
}
protected override void OnDisable()
{
base.OnDisable();
EditorUtility.ClearProgressBar();
}
protected override async void Initialize()
{
base.Initialize();
GetBuildPackageNames();
UpdateMessage(false);
if (string.IsNullOrEmpty(ip))
{
buildAssetType = BuildAssetType.Login;
return;
}
bool isValidateToken = await WebRequestSystem.GetValidateToken(ip + "/Authentication/validateToken");
if (isValidateToken)
{
buildAssetType = BuildAssetType.Build;
return;
}
buildAssetType = BuildAssetType.Login;
}
public static void RemoveBuildAssetWindow()
{
if (window != null)
window.Close();
}
[EnumToggleButtons, HideLabel] public BuildAssetType buildAssetType;
#region BuildAssetLogin
[ShowIf("@ buildAssetType== BuildAssetType.Login")] [BoxGroup("Login", showLabel: false)]
public string ip, userName, password;
[ShowIf("@ buildAssetType== BuildAssetType.Login")]
[BoxGroup("Login", showLabel: false)]
[Button("登录", ButtonSizes.Large)]
[InfoBox("@ message", InfoMessageType.Info)]
public async void LoginButton()
{
string url = ip + "/Authentication/login";
EditorUtility.DisplayProgressBar("提示", $"登陆中~", 0f);
bool islogin = await WebRequestSystem.Login(url, userName, password);
float progress = 0f;
while (progress >= 1f)
{
progress += 0.1f;
EditorUtility.DisplayProgressBar("提示", $"登陆中~", progress);
await Task.Delay(TimeSpan.FromSeconds(0.2f));
}
EditorUtility.ClearProgressBar();
UpdateMessage(islogin);
}
private string message;
public async void UpdateMessage(bool islogin)
{
message = "当前登录状态为:" + islogin;
//初始化读取资源配置表
HotfixMainResDomain hotfixMainResDomain = Resources.Load<HotfixMainResDomain>("HotfixMainResDomain");
if (hotfixMainResDomain == null)
{
Debug.LogError($"UnityEvo:读取资源配置表失败【HotfixMainResDomain】...表不存在");
}
else
{
ip = hotfixMainResDomain.hotfixMainResDomainEntity.ipconfig;
userName = hotfixMainResDomain.hotfixMainResDomainEntity.username;
password = hotfixMainResDomain.hotfixMainResDomainEntity.password;
}
if (islogin)
{
buildAssetType = BuildAssetType.Build;
}
}
#endregion
protected void OnSelectionChange()
{
EditorUtility.SetDirty(BuildAssetDataSetting);
AssetDatabase.SaveAssets();
//AssetDatabase.Refresh();
}
[BoxGroup("Build", showLabel: false)]
[ShowIf("@ buildAssetType== BuildAssetType.Build")]
[Title("包裹列表", titleAlignment: TitleAlignments.Centered)]
[HorizontalGroup("Build/BuildPipeline"), HideLabel]
[ValueDropdown("GetBuildPackageNames")]
[OnValueChanged("SetBuildPackageNames")]
public string selectedPackageNames;
[BoxGroup("Build", showLabel: false)]
[ShowIf("@ buildAssetType== BuildAssetType.Build")]
[Title("当前打包平台", titleAlignment: TitleAlignments.Centered)]
[ReadOnly]
[HorizontalGroup("Build/BuildPipeline"), HideLabel]
public string buildTarget;
public static string packageName;
#region HyBridCLRBuild
[BoxGroup("Build", showLabel: false)]
[HideIf("@ buildAssetType!= BuildAssetType.Build")]
[Title("打包dll(子包仅打一次)", titleAlignment: TitleAlignments.Centered)]
[HorizontalGroup("Build/HyBridClrBuildEntity"), HideLabel]
public BuildAssetEntity hyBridClrBuildEntity =
new BuildAssetEntity("HyBridCLRBuild", "DllBuildTarget", () =>
{
#if HotUpdate
//PrebuildCommand.GenerateAll();
CompileDllCommand.CompileDllActiveBuildTarget();
#endif
});
#endregion
#region MarkAsset
[BoxGroup("Build", showLabel: false)]
[ShowIf("@ buildAssetType== BuildAssetType.Build")]
[Title("标记资源", titleAlignment: TitleAlignments.Centered)]
[HorizontalGroup("Build/HyBridClrBuildEntity"), HideLabel]
public BuildAssetEntity markAssetEntity =
new BuildAssetEntity("MarkAsset", "MarkAsset", MarkAdressable.AddMark);
#endregion
#region BuildAsset
[BoxGroup("Build", showLabel: false)]
[ShowIf("@ buildAssetType== BuildAssetType.Build")]
[InlineEditor(InlineEditorObjectFieldModes.CompletelyHidden)]
[HideLabel]
public BuildAssetDataSetting BuildAssetDataSetting;
/// <summary>
/// 检测当前所有包裹
/// </summary>
/// <returns></returns>
private List<string> GetBuildPackageNames()
{
List<string> result = new List<string>();
foreach (var name in CreatAssetWindow.GetCreatDomainAllName())
{
result.Add(name);
}
if (selectedPackageNames.IsNullOrEmpty())
{
// string buildPackageName = DataSetting.packageName;
// if (result.Exists(p => p == buildPackageName))
// {
// selectedPackageNames = buildPackageName;
// }
// else
// {
selectedPackageNames = result[0];
//}
}
SetBuildPackageNames();
return result;
}
/// <summary>
/// 设置当前包裹
/// </summary>
/// <returns></returns>
private void SetBuildPackageNames()
{
//PlayerPrefs.SetString("BuildPackageNames", selectedPackageNames);
// DataSetting.packageName = selectedPackageNames;
// DataSetting = Resources.Load<BuildAssetDataSetting>("BuildAssetDataSetting");
string buildAssetDataSettingPath =
$"Assets/Domain/{selectedPackageNames}/Conf/BuildAssetDataSetting.asset";
BuildAssetDataSetting buildAssetDataSetting =
AssetDatabase.LoadAssetAtPath<BuildAssetDataSetting>(buildAssetDataSettingPath);
if (buildAssetDataSetting != null)
{
BuildAssetDataSetting = buildAssetDataSetting;
Init();
}
else
{
Debug.LogError($"UnityEvo:BuildAssetDataSetting 不存在,请检查路径{buildAssetDataSettingPath}");
}
if (selectedPackageNames != packageName)
{
GetHostBuildPackageVersion(buildAssetDataSetting);
}
packageName = selectedPackageNames;
}
/// <summary>
/// 获取当前包裹
/// </summary>
/// <returns></returns>
public static string GetBuildPackageName()
{
return packageName;
}
#endregion
#region Update
[BoxGroup("Build", showLabel: false)]
[ShowIf("@ buildAssetType== BuildAssetType.Build")]
[Title("打包本地资源", titleAlignment: TitleAlignments.Centered)]
[HideLabel]
public BuildAssetEntity onBuildPipelineEntity;
[BoxGroup("Build", showLabel: false)]
[Title("上传资源", titleAlignment: TitleAlignments.Centered)]
[HideLabel]
[ShowIf(
"@ BuildAssetDataSetting.environmentType== EnvironmentType.Release && buildAssetType== BuildAssetType.Build")]
public BuildAssetEntity onUpdateBuildPipelineEntity;
private void OnBuildPipeline()
{
if (EditorUtility.DisplayDialog("提示", $"开始构建资源包[{selectedPackageNames}]", "Yes", "No"))
{
EditorTools.ClearUnityConsole();
EditorApplication.delayCall += BuildAssetDataSetting.viewer.ExecuteBuild;
}
else
{
Debug.LogWarning("[Build] 打包已经取消");
}
}
private async void OnUpdateBuildPipeline()
{
if (EditorUtility.DisplayDialog("提示", $"开始上传至服务器[{selectedPackageNames}]", "Yes", "No"))
{
// 新增打包为zip的逻辑
string zipFilePath = BuildZip(BuildAssetDataSetting);
await UpdateFileDataResDomain(BuildAssetDataSetting, zipFilePath);
await Task.Delay(1000);
EditorUtility.ClearProgressBar();
}
else
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("提示", "Update] 上传已经取消", "确定");
Debug.LogWarning("[Update] 上传已经取消");
}
}
public static string BuildZip(BuildAssetDataSetting setting)
{
EditorUtility.DisplayProgressBar("提示", $"开始上传{setting.packageName}(打包zip)", 0.0f);
// 新增打包为zip的逻辑
string zipFileName =
$"{setting.packageName}_{setting.packageVersion}.zip";
var outputPackageDirectory =
$"{AssetBundleBuilderHelper.GetDefaultBuildOutputRoot()}/{EditorUserBuildSettings.activeBuildTarget}/{setting.packageName}";
//拷贝目录
string outFilePath = $"{outputPackageDirectory}/{setting.packageVersion}";
//DefaultBuildinFileSystemBuild.CreateBuildinCatalogFile(setting.packageName, 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("提示", $"开始上传{setting.packageName}(打包zip)", 0.25f);
return zipFilePath;
}
catch (Exception ex)
{
Debug.LogError($"打包zip失败{ex.Message}");
EditorUtility.ClearProgressBar();
return default;
}
}
public static async Task UpdateFileDataResDomain(BuildAssetDataSetting setting, string zipFilePath)
{
//初始化读取资源配置表
HotfixMainResDomain hotfixMainResDomain = Resources.Load<HotfixMainResDomain>("HotfixMainResDomain");
if (hotfixMainResDomain == null)
{
Debug.LogError($"UnityEvo:读取资源配置表失败【HotfixMainResDomain】...表不存在");
return;
}
var ip = hotfixMainResDomain.hotfixMainResDomainEntity.ipconfig;
var messageEntity = await WebRequestSystem.PostFile(ip + "/FileLoad/UpLoadFile", new[] { zipFilePath });
EditorUtility.DisplayProgressBar("提示", $"开始上传{setting.packageName}(上传zip文件)", 0.5f);
if (messageEntity.code == 200)
{
List<ResultMessageEntity> resultMessageEntities =
JsonConvert.DeserializeObject<List<ResultMessageEntity>>(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 = setting.packageName,
Platform = EditorUserBuildSettings.activeBuildTarget.ToString(),
PackageVersion = setting.packageVersion,
DocumentFileId = fileId
};
var resResultMessage = await WebRequestSystem.Post(ip + "/ResDomain/AddResDomain",
JsonConvert.SerializeObject(resDmainAddRequst));
//如果低于服务器版本,更新版本号
if (resResultMessage.code == 1009)
{
ResDmainVersionResponse dmainVersionResponse =
JsonConvert.DeserializeObject<ResDmainVersionResponse>(resResultMessage.data
.ToString());
string[] versions = dmainVersionResponse.PackageVersion.Split('.');
setting.packageVersionX = int.Parse(versions[0]);
setting.packageVersionY = int.Parse(versions[1]);
setting.packageVersionZ = int.Parse(versions[2]);
EditorUtility.DisplayDialog("提示",
$"{resResultMessage.message + $"\n{resResultMessage.data.ToString()}"}", "确定");
}
setting.GetBuildPackageVersion(true);
}
EditorUtility.DisplayProgressBar("提示", $"开始上传{setting.packageName}(更新数据库)", 1f);
}
}
else
{
EditorUtility.DisplayProgressBar("提示", $"{messageEntity.message}", 1f);
}
await Task.Delay(1000);
EditorUtility.ClearProgressBar();
return;
}
/// <summary>
/// 获取服务器上版本号
/// </summary>
private async void GetHostBuildPackageVersion(BuildAssetDataSetting setting)
{
var resDmainAddRequst = new ResDmainRequst()
{
ProductName = Application.identifier,
DomainName = selectedPackageNames,
Platform = EditorUserBuildSettings.activeBuildTarget.ToString(),
};
var resResultMessage = await WebRequestSystem.Post(ip + "/ResDomain/GetResDomainByDomain",
JsonConvert.SerializeObject(resDmainAddRequst));
//如果低于服务器版本,更新版本号
if (resResultMessage.code != 1011)
{
if (resResultMessage.data != null)
{
ResDmainResponse domainResponse =
JsonConvert.DeserializeObject<ResDmainResponse>(resResultMessage.data
.ToString());
string[] versions = domainResponse.PackageVersion.Split('.');
setting.packageVersionX = int.Parse(versions[0]);
setting.packageVersionY = int.Parse(versions[1]);
setting.packageVersionZ = int.Parse(versions[2]);
setting.GetBuildPackageVersion(true);
}
else
{
Debug.LogError($"UnityEvo获取服务器版本失败,resResultMessage.data为空");
}
}
else
{
EditorUtility.DisplayDialog("提示",
$"{resResultMessage.message},默认1.0.0版本 ", "确定");
setting.packageVersionX = 1;
setting.packageVersionY = 0;
setting.packageVersionZ = 0;
setting.GetBuildPackageVersion(false);
}
}
#endregion
protected void Init()
{
//Update
buildTarget = EditorUserBuildSettings.activeBuildTarget.ToString();
onBuildPipelineEntity =
new BuildAssetEntity("打包", $"打包资源包【版本:{BuildAssetDataSetting.packageVersion}】", OnBuildPipeline);
onUpdateBuildPipelineEntity =
new BuildAssetEntity("更新", $"更新至服务器【版本:{BuildAssetDataSetting.packageVersion}】",
OnUpdateBuildPipeline);
}
private Vector2 scroll;
protected override void DrawEditor(int index)
{
scroll = GUILayout.BeginScrollView(scroll);
{
base.DrawEditor(index);
}
GUILayout.EndScrollView();
BuildServerPath();
UpdateBuildPipelineButtonName();
}
public void UpdateBuildPipelineButtonName()
{
onBuildPipelineEntity.SetButtonName($"打包资源包【版本:{BuildAssetDataSetting.packageVersion}】");
onUpdateBuildPipelineEntity.SetButtonName($"更新至服务器【版本:{BuildAssetDataSetting.packageVersion}】");
}
/// <summary>
/// 生成服务器路径
/// </summary>
private void BuildServerPath()
{
// if (!_isCheckDriveExist)
// {
// return;
// }
//
// updateServerPath =
// $"Z:/{Application.productName}/{BuildAssetDataSetting.packageName}/{EditorUserBuildSettings.activeBuildTarget}/{BuildAssetDataSetting.packageVersion}";
// if (!Directory.Exists(updateServerPath))
// Directory.CreateDirectory(updateServerPath);
//更新Button文字
onBuildPipelineEntity.SetButtonName($"打包资源包【版本:{BuildAssetDataSetting.packageVersion}】");
onUpdateBuildPipelineEntity.SetButtonName($"更新至服务器【版本:{BuildAssetDataSetting.packageVersion}】");
}
}
public enum BuildAssetType
{
Login,
Build,
}
}