2025-02-06 17:59:35 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using YooAsset;
|
|
|
|
|
|
using YooAsset.Editor;
|
|
|
|
|
|
|
2025-03-04 18:40:14 +08:00
|
|
|
|
public class AssetBundleBuildTab : EditorWindowTabBase
|
2025-02-06 17:59:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
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 List<string> _encryptionClasses;
|
|
|
|
|
|
private List<string> _buildPackageNames;
|
|
|
|
|
|
|
2025-03-04 18:40:14 +08:00
|
|
|
|
internal override void OnEnable()
|
2025-02-06 17:59:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-04 18:40:14 +08:00
|
|
|
|
internal override void OnGUI()
|
2025-02-06 17:59:35 +08:00
|
|
|
|
{
|
2025-03-04 18:40:14 +08:00
|
|
|
|
base.OnGUI();
|
|
|
|
|
|
DrawABBuildTab();
|
2025-02-06 17:59:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 DrawBuildTarget(ref BuildTarget target)
|
|
|
|
|
|
{
|
|
|
|
|
|
target = (BuildTarget)EditorGUILayout.EnumPopup("目标平台:", target);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 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 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}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-04 18:40:14 +08:00
|
|
|
|
private IEncryptionServices CreateEncryptionInstance()
|
2025-02-06 17:59:35 +08:00
|
|
|
|
{
|
2025-03-04 18:40:14 +08:00
|
|
|
|
if (string.IsNullOrEmpty(_selectedEncryption)) return null;
|
|
|
|
|
|
|
|
|
|
|
|
var type = Type.GetType(_selectedEncryption);
|
|
|
|
|
|
if (type != null)
|
2025-02-06 17:59:35 +08:00
|
|
|
|
{
|
2025-03-04 18:40:14 +08:00
|
|
|
|
return (IEncryptionServices)Activator.CreateInstance(type);
|
2025-02-06 17:59:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-04 18:40:14 +08:00
|
|
|
|
return null;
|
2025-02-06 17:59:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|