AlicizaX/Client/Assets/Editor/Build/BuildWindow/AdvancedBuildWindow.cs
2025-02-06 17:59:35 +08:00

381 lines
12 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.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AlicizaX.Resource.Runtime;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;
using YooAsset;
using YooAsset.Editor;
public class AdvancedBuildWindow : EditorWindow
{
[MenuItem("开发工具/打包工具")]
public static void ShowWindow()
{
GetWindow<AdvancedBuildWindow>("Build Window", true);
}
private int _selectedTab;
private readonly string[] _tabLabels = { "AB包构建", "整包构建" };
// AB包构建配置
private BuildTarget _abBuildTarget = BuildTarget.StandaloneWindows64;
private string _outputPath = "Builds/AB";
private string _packageVersion;
private bool _copyAfterBuild;
private string _copyDestination;
private ECompressOption _compressOption = ECompressOption.LZ4;
private EFileNameStyle _fileNameStyle = EFileNameStyle.BundleName_HashName;
private EBuildinFileCopyOption _copyOption = EBuildinFileCopyOption.ClearAndCopyByTags;
private string _copyParams = "Launch";
private bool _enableSharePack = true;
private string _selectedEncryption;
private string _selectedPackage;
// 整包构建配置
private BuildTarget _appBuildTarget = BuildTarget.StandaloneWindows64;
private string _appOutputPath = "Builds/App";
private List<SceneAsset> _scenes = new List<SceneAsset>();
private bool _developmentBuild;
private Vector2 _scrollPosition;
private List<string> _encryptionClasses;
private List<string> _buildPackageNames;
private void OnEnable()
{
LoadEncryptionClasses();
LoadBuildPackageNames();
GeneratePackageVersion();
}
private void GeneratePackageVersion()
{
int totalMinutes = DateTime.Now.Hour * 60 + DateTime.Now.Minute;
_packageVersion = DateTime.Now.ToString("yyyy-MM-dd") + "-" + totalMinutes;
}
private void LoadEncryptionClasses()
{
_encryptionClasses = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(t => typeof(IEncryptionServices).IsAssignableFrom(t) && !t.IsAbstract)
.Select(t => t.FullName)
.ToList();
}
private void LoadBuildPackageNames()
{
_buildPackageNames = new List<string>();
foreach (var package in AssetBundleCollectorSettingData.Setting.Packages)
{
_buildPackageNames.Add(package.PackageName);
}
}
private void OnGUI()
{
_selectedTab = GUILayout.Toolbar(_selectedTab, _tabLabels);
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
{
switch (_selectedTab)
{
case 0:
DrawABBuildTab();
break;
case 1:
DrawAppBuildTab();
break;
}
}
EditorGUILayout.EndScrollView();
}
private void DrawABBuildTab()
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("AB包构建配置", EditorStyles.boldLabel);
// 基本配置
DrawBuildTarget(ref _abBuildTarget);
DrawPathSelection("输出路径:", ref _outputPath);
DrawPackageVersion();
// 高级配置
EditorGUILayout.Space();
EditorGUILayout.LabelField("高级选项", EditorStyles.boldLabel);
_compressOption = (ECompressOption)EditorGUILayout.EnumPopup("压缩方式:", _compressOption);
_fileNameStyle = (EFileNameStyle)EditorGUILayout.EnumPopup("文件命名风格:", _fileNameStyle);
_copyOption = (EBuildinFileCopyOption)EditorGUILayout.EnumPopup("内置文件拷贝选项:", _copyOption);
_copyParams = EditorGUILayout.TextField("拷贝参数:", _copyParams);
_enableSharePack = EditorGUILayout.Toggle("启用共享打包:", _enableSharePack);
DrawEncryptionSelection();
DrawPackageSelection();
// 拷贝配置
EditorGUILayout.Space();
_copyAfterBuild = EditorGUILayout.BeginToggleGroup("构建后拷贝", _copyAfterBuild);
DrawPathSelection("拷贝目标:", ref _copyDestination);
EditorGUILayout.EndToggleGroup();
// 操作按钮
EditorGUILayout.Space();
if (GUILayout.Button("构建AB包", GUILayout.Height(30)))
{
BuildABPackage();
}
if (GUILayout.Button("构建热更程序集", GUILayout.Height(30)))
{
BuildDLLCommand.BuildAndCopyDlls();
}
}
private void DrawAppBuildTab()
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("整包构建配置", EditorStyles.boldLabel);
DrawBuildTarget(ref _appBuildTarget);
DrawPathSelection("输出路径:", ref _appOutputPath);
_developmentBuild = EditorGUILayout.Toggle("开发模式:", _developmentBuild);
EditorGUILayout.Space();
EditorGUILayout.LabelField("包含场景:", EditorStyles.boldLabel);
DrawSceneList();
EditorGUILayout.Space();
if (GUILayout.Button("构建应用程序", GUILayout.Height(30)))
{
BuildApplication();
}
}
private void DrawBuildTarget(ref BuildTarget target)
{
target = (BuildTarget)EditorGUILayout.EnumPopup("目标平台:", target);
}
private void DrawPathSelection(string label, ref string path)
{
EditorGUILayout.BeginHorizontal();
{
path = EditorGUILayout.TextField(label, path);
if (GUILayout.Button("浏览...", GUILayout.Width(60)))
{
string newPath = EditorUtility.SaveFolderPanel("选择输出目录", path, "");
if (!string.IsNullOrEmpty(newPath))
{
path = newPath;
}
}
}
EditorGUILayout.EndHorizontal();
}
private void DrawPackageVersion()
{
EditorGUILayout.BeginHorizontal();
{
_packageVersion = EditorGUILayout.TextField("版本号:", _packageVersion);
if (GUILayout.Button("生成新版本", GUILayout.Width(100)))
{
GeneratePackageVersion();
}
}
EditorGUILayout.EndHorizontal();
}
private void DrawEncryptionSelection()
{
if (_encryptionClasses == null || _encryptionClasses.Count == 0)
{
EditorGUILayout.HelpBox("未找到加密类实现", MessageType.Info);
return;
}
int selectedIndex = Mathf.Max(0, _encryptionClasses.IndexOf(_selectedEncryption));
selectedIndex = EditorGUILayout.Popup("加密方式:", selectedIndex, _encryptionClasses.ToArray());
_selectedEncryption = _encryptionClasses[selectedIndex];
}
private void DrawPackageSelection()
{
if (_buildPackageNames == null || _buildPackageNames.Count == 0)
{
EditorGUILayout.HelpBox("未找到包", MessageType.Info);
return;
}
int selectedIndex = Mathf.Max(0, _buildPackageNames.IndexOf(_selectedPackage));
selectedIndex = EditorGUILayout.Popup("Package:", selectedIndex, _buildPackageNames.ToArray());
_selectedPackage = _buildPackageNames[selectedIndex];
}
private void DrawSceneList()
{
for (int i = 0; i < _scenes.Count; i++)
{
_scenes[i] = (SceneAsset)EditorGUILayout.ObjectField($"场景 {i + 1}:", _scenes[i], typeof(SceneAsset), false);
}
EditorGUILayout.BeginHorizontal();
{
if (GUILayout.Button("添加场景"))
{
_scenes.Add(null);
}
if (GUILayout.Button("移除最后一个") && _scenes.Count > 0)
{
_scenes.RemoveAt(_scenes.Count - 1);
}
}
EditorGUILayout.EndHorizontal();
}
private void BuildABPackage()
{
try
{
var parameters = new ScriptableBuildParameters
{
BuildOutputRoot = _outputPath,
BuildTarget = _abBuildTarget,
PackageName = _selectedPackage,
BuildBundleType = (int)EBuildBundleType.AssetBundle,
BuildPipeline = EBuildPipeline.ScriptableBuildPipeline.ToString(),
BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot(),
PackageVersion = _packageVersion,
CompressOption = _compressOption,
FileNameStyle = _fileNameStyle,
VerifyBuildingResult = true,
ClearBuildCacheFiles = false,
BuildinFileCopyOption = _copyOption,
BuildinFileCopyParams = _copyParams,
EnableSharePackRule = _enableSharePack,
EncryptionServices = CreateEncryptionInstance()
};
ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline();
var report = pipeline.Run(parameters, true);
if (report.Success)
{
BuildUpdateData(_packageVersion, _copyDestination);
if (_copyAfterBuild && !string.IsNullOrEmpty(_copyDestination))
{
CopyFiles(report.OutputPackageDirectory, _copyDestination);
}
EditorUtility.DisplayDialog("构建成功", $"AB包构建完成\n输出目录: {report.OutputPackageDirectory}", "确定");
}
else
{
EditorUtility.DisplayDialog("构建失败", $"错误信息: {report.ErrorInfo}", "确定");
}
}
catch (Exception e)
{
Debug.LogException(e);
}
}
private void BuildUpdateData(string version, string outPath)
{
ResourcePatchData updateData = new ResourcePatchData()
{
Version = Application.version,
BundleUrl = $"http://127.0.0.1:8081/res/{version}/",
Notice = "Test Notice",
};
File.WriteAllText(Path.Combine(outPath, "UpdateData.json"), Newtonsoft.Json.JsonConvert.SerializeObject(updateData));
}
private void BuildApplication()
{
try
{
var options = new BuildPlayerOptions
{
scenes = _scenes.Where(s => s != null).Select(s => AssetDatabase.GetAssetPath(s)).ToArray(),
locationPathName = Path.Combine(_appOutputPath, GetExecutableName()),
target = _appBuildTarget,
options = _developmentBuild ? BuildOptions.Development : BuildOptions.None
};
var report = BuildPipeline.BuildPlayer(options);
HandleBuildReport(report);
}
catch (Exception e)
{
EditorUtility.DisplayDialog("错误", $"构建过程中发生异常: {e.Message}", "确定");
}
}
private IEncryptionServices CreateEncryptionInstance()
{
if (string.IsNullOrEmpty(_selectedEncryption)) return null;
var type = Type.GetType(_selectedEncryption);
if (type != null)
{
return (IEncryptionServices)Activator.CreateInstance(type);
}
return null;
}
private void CopyFiles(string source, string destination)
{
try
{
if (!Directory.Exists(destination))
{
Directory.CreateDirectory(destination);
}
foreach (string file in Directory.GetFiles(source))
{
File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), true);
}
Debug.Log($"文件拷贝完成: {source} -> {destination}");
}
catch (Exception e)
{
Debug.LogError($"文件拷贝失败: {e.Message}");
}
}
private void HandleBuildReport(UnityEditor.Build.Reporting.BuildReport report)
{
if (report.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded)
{
EditorUtility.DisplayDialog("构建成功",
$"应用程序构建完成!\n输出大小: {report.summary.totalSize / 1024 / 1024}MB", "确定");
}
else
{
EditorUtility.DisplayDialog("构建失败",
$"错误信息: {report.summary}", "确定");
}
}
private string GetExecutableName()
{
return _appBuildTarget switch
{
BuildTarget.StandaloneWindows64 => "Game.exe",
BuildTarget.StandaloneOSX => "Game.app",
BuildTarget.Android => "Game.apk",
_ => "Game"
};
}
}