381 lines
12 KiB
C#
381 lines
12 KiB
C#
|
|
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"
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|