118 lines
4.0 KiB
C#
118 lines
4.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UnityEngine;
|
|
|
|
namespace TH1_Logic.Hotfix
|
|
{
|
|
public static class HotfixBootstrap
|
|
{
|
|
private static bool _initialized;
|
|
|
|
public static bool IsLoaded { get; private set; }
|
|
public static string LoadedAssemblyFullName { get; private set; }
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
|
private static void AutoInitialize()
|
|
{
|
|
InitializeFromStreamingAssets(false);
|
|
}
|
|
|
|
public static bool InitializeFromStreamingAssets(bool requireHotfix)
|
|
{
|
|
if (_initialized) return IsLoaded;
|
|
|
|
try
|
|
{
|
|
var root = Path.Combine(Application.streamingAssetsPath, HotfixManifest.RootFolderName);
|
|
LoadAotMetadata(root);
|
|
|
|
var hotfixPath = Path.Combine(root, HotfixManifest.HotfixDllFolderName, HotfixManifest.HotfixAssemblyFileName);
|
|
if (!File.Exists(hotfixPath))
|
|
{
|
|
if (requireHotfix)
|
|
{
|
|
Debug.LogWarning($"[TH1.Hotfix] Hotfix dll missing: {hotfixPath}");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
var assembly = Assembly.Load(File.ReadAllBytes(hotfixPath));
|
|
LoadedAssemblyFullName = assembly.FullName;
|
|
InvokeHotfixEntry(assembly);
|
|
_initialized = true;
|
|
IsLoaded = true;
|
|
Debug.Log($"[TH1.Hotfix] Loaded {LoadedAssemblyFullName}");
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[TH1.Hotfix] Initialize failed: {e}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void LoadAotMetadata(string root)
|
|
{
|
|
var runtimeApiType = FindType("HybridCLR.RuntimeApi");
|
|
var modeType = FindType("HybridCLR.HomologousImageMode");
|
|
if (runtimeApiType == null || modeType == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var method = runtimeApiType.GetMethod(
|
|
"LoadMetadataForAOTAssembly",
|
|
BindingFlags.Public | BindingFlags.Static,
|
|
null,
|
|
new[] { typeof(byte[]), modeType },
|
|
null);
|
|
if (method == null)
|
|
{
|
|
Debug.LogWarning("[TH1.Hotfix] HybridCLR RuntimeApi.LoadMetadataForAOTAssembly not found.");
|
|
return;
|
|
}
|
|
|
|
var mode = Enum.Parse(modeType, "SuperSet");
|
|
var aotDir = Path.Combine(root, HotfixManifest.AotMetadataFolderName);
|
|
|
|
foreach (var fileName in HotfixManifest.AotMetadataAssemblyFileNames)
|
|
{
|
|
var path = Path.Combine(aotDir, fileName);
|
|
if (!File.Exists(path)) continue;
|
|
|
|
var result = method.Invoke(null, new object[] { File.ReadAllBytes(path), mode });
|
|
Debug.Log($"[TH1.Hotfix] Load AOT metadata {fileName}: {result}");
|
|
}
|
|
}
|
|
|
|
private static void InvokeHotfixEntry(Assembly assembly)
|
|
{
|
|
var entryType = assembly.GetType(HotfixManifest.EntryTypeName);
|
|
if (entryType == null)
|
|
{
|
|
Debug.LogWarning($"[TH1.Hotfix] Entry type not found: {HotfixManifest.EntryTypeName}");
|
|
return;
|
|
}
|
|
|
|
var method = entryType.GetMethod(HotfixManifest.EntryMethodName, BindingFlags.Public | BindingFlags.Static);
|
|
if (method == null)
|
|
{
|
|
Debug.LogWarning($"[TH1.Hotfix] Entry method not found: {HotfixManifest.EntryMethodName}");
|
|
return;
|
|
}
|
|
|
|
method.Invoke(null, null);
|
|
}
|
|
|
|
private static Type FindType(string fullName)
|
|
{
|
|
return AppDomain.CurrentDomain.GetAssemblies()
|
|
.Select(assembly => assembly.GetType(fullName, false))
|
|
.FirstOrDefault(type => type != null);
|
|
}
|
|
}
|
|
}
|