TH1/Unity/Assets/Scripts/TH1_Logic/Editor/HybridCLR/TH1HybridCLRBuildTools.cs
2026-06-09 20:49:52 +08:00

176 lines
7.2 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using TH1_Logic.Hotfix;
using UnityEditor;
using UnityEngine;
namespace TH1_Logic.Editor.HybridCLR
{
public static class TH1HybridCLRBuildTools
{
private const string HybridClrInstallerMenu = "HybridCLR/Installer...";
private const string HybridClrGenerateAllMenu = "HybridCLR/Generate/All";
private const string HybridClrCompileDllMenu = "HybridCLR/CompileDll/ActiveBuildTarget";
[MenuItem("Tools/TH1/iOS Migration/HybridCLR/1. Run HybridCLR Installer")]
public static void RunHybridClrInstaller()
{
ExecuteHybridClrMenu(HybridClrInstallerMenu);
}
[MenuItem("Tools/TH1/iOS Migration/HybridCLR/2. Configure TH1 Hotfix Settings")]
public static void ConfigureHotfixSettings()
{
var settingsType = FindType("HybridCLR.Editor.Settings.HybridCLRSettings");
if (settingsType == null)
{
Debug.LogWarning("[TH1.HybridCLR] HybridCLR package is not available yet. Let Unity resolve packages, then run this menu again.");
return;
}
var instance = settingsType.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static)?.GetValue(null);
if (instance == null)
{
Debug.LogWarning("[TH1.HybridCLR] HybridCLRSettings.Instance is unavailable.");
return;
}
SetBoolField(settingsType, instance, "enable", true);
AddStringToArrayField(settingsType, instance, "hotUpdateAssemblies", HotfixManifest.HotfixAssemblyName);
AddStringToArrayField(settingsType, instance, "patchAOTAssemblies", "mscorlib");
AddStringToArrayField(settingsType, instance, "patchAOTAssemblies", "System");
AddStringToArrayField(settingsType, instance, "patchAOTAssemblies", "System.Core");
settingsType.GetMethod("Save", BindingFlags.Public | BindingFlags.Static)?.Invoke(null, null);
Debug.Log("[TH1.HybridCLR] Configured HybridCLRSettings for TH1.Hotfix.");
}
[MenuItem("Tools/TH1/iOS Migration/HybridCLR/3. Generate All")]
public static void GenerateAll()
{
ExecuteHybridClrMenu(HybridClrGenerateAllMenu);
}
[MenuItem("Tools/TH1/iOS Migration/HybridCLR/4. Compile Hotfix Dll")]
public static void CompileHotfixDll()
{
if (!ExecuteHybridClrMenu(HybridClrCompileDllMenu))
{
Debug.LogWarning("[TH1.HybridCLR] Compile menu was not found. Run HybridCLR/Generate/All or use the package CompileDll menu manually.");
}
}
[MenuItem("Tools/TH1/iOS Migration/HybridCLR/5. Copy Hotfix Artifacts To StreamingAssets")]
public static void CopyHotfixArtifactsToStreamingAssets()
{
CopyHotfixDll();
CopyAotMetadataDlls();
AssetDatabase.Refresh();
}
[MenuItem("Tools/TH1/iOS Migration/HybridCLR/6. Test Load StreamingAssets Hotfix In Editor")]
public static void TestLoadHotfixInEditor()
{
var loaded = HotfixBootstrap.InitializeFromStreamingAssets(true);
Debug.Log($"[TH1.HybridCLR] Test load result: {loaded}, assembly: {HotfixBootstrap.LoadedAssemblyFullName}");
}
private static void CopyHotfixDll()
{
var buildTarget = EditorUserBuildSettings.activeBuildTarget.ToString();
var source = Path.Combine("HybridCLRData", "HotUpdateDlls", buildTarget, HotfixManifest.HotfixAssemblyName + ".dll");
if (!File.Exists(source))
{
source = Path.Combine("Library", "ScriptAssemblies", HotfixManifest.HotfixAssemblyName + ".dll");
}
var destination = Path.Combine(
Application.streamingAssetsPath,
HotfixManifest.RootFolderName,
HotfixManifest.HotfixDllFolderName,
HotfixManifest.HotfixAssemblyFileName);
CopyFile(source, destination, "hotfix dll");
}
private static void CopyAotMetadataDlls()
{
var buildTarget = EditorUserBuildSettings.activeBuildTarget.ToString();
var sourceDir = Path.Combine("HybridCLRData", "AssembliesPostIl2CppStrip", buildTarget);
var destinationDir = Path.Combine(Application.streamingAssetsPath, HotfixManifest.RootFolderName, HotfixManifest.AotMetadataFolderName);
if (!Directory.Exists(sourceDir))
{
Debug.LogWarning($"[TH1.HybridCLR] AOT metadata source missing: {sourceDir}. Run HybridCLR/Generate/All after an IL2CPP target is selected.");
return;
}
Directory.CreateDirectory(destinationDir);
foreach (var fileName in HotfixManifest.AotMetadataAssemblyFileNames)
{
var source = Path.Combine(sourceDir, fileName.Replace(".bytes", ""));
var destination = Path.Combine(destinationDir, fileName);
if (!File.Exists(source))
{
Debug.LogWarning($"[TH1.HybridCLR] AOT metadata dll missing: {source}");
continue;
}
File.Copy(source, destination, true);
Debug.Log($"[TH1.HybridCLR] Copied AOT metadata: {destination}");
}
}
private static bool ExecuteHybridClrMenu(string menuPath)
{
if (EditorApplication.ExecuteMenuItem(menuPath))
{
return true;
}
Debug.LogWarning($"[TH1.HybridCLR] Unity menu not found: {menuPath}. Make sure the HybridCLR package has been resolved.");
return false;
}
private static void CopyFile(string source, string destination, string label)
{
if (!File.Exists(source))
{
Debug.LogWarning($"[TH1.HybridCLR] {label} source missing: {source}");
return;
}
Directory.CreateDirectory(Path.GetDirectoryName(destination));
File.Copy(source, destination, true);
Debug.Log($"[TH1.HybridCLR] Copied {label}: {destination}");
}
private static Type FindType(string fullName)
{
return AppDomain.CurrentDomain.GetAssemblies()
.Select(assembly => assembly.GetType(fullName, false))
.FirstOrDefault(type => type != null);
}
private static void SetBoolField(Type type, object instance, string fieldName, bool value)
{
type.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance)?.SetValue(instance, value);
}
private static void AddStringToArrayField(Type type, object instance, string fieldName, string value)
{
var field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance);
if (field == null) return;
var values = ((string[])field.GetValue(instance) ?? Array.Empty<string>()).ToList();
if (!values.Contains(value))
{
values.Add(value);
field.SetValue(instance, values.ToArray());
}
}
}
}