feat(cordis): 接入上下文组合与模组事务热替换
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShrinkModFramework
|
||||
{
|
||||
internal static class ShrinkHarmonyPatchService
|
||||
{
|
||||
private sealed class EmptyLease : IDisposable
|
||||
{
|
||||
public static readonly EmptyLease Instance = new();
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
private sealed class HarmonyLease : IDisposable
|
||||
{
|
||||
private readonly Type _harmonyType;
|
||||
private readonly object _harmony;
|
||||
private readonly string _harmonyId;
|
||||
private readonly bool _verboseLogging;
|
||||
private bool _disposed;
|
||||
|
||||
public HarmonyLease(Type harmonyType, object harmony, string harmonyId, bool verboseLogging)
|
||||
{
|
||||
_harmonyType = harmonyType;
|
||||
_harmony = harmony;
|
||||
_harmonyId = harmonyId;
|
||||
_verboseLogging = verboseLogging;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
_disposed = true;
|
||||
|
||||
try
|
||||
{
|
||||
var unpatchSelf = _harmonyType.GetMethod("UnpatchSelf",
|
||||
BindingFlags.Public | BindingFlags.Instance,
|
||||
null,
|
||||
Type.EmptyTypes,
|
||||
null);
|
||||
if (unpatchSelf != null)
|
||||
{
|
||||
unpatchSelf.Invoke(_harmony, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var unpatchAll = _harmonyType.GetMethod("UnpatchAll",
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new[] { typeof(string) },
|
||||
null);
|
||||
if (unpatchAll == null)
|
||||
throw new MissingMethodException("Harmony.UnpatchSelf()/UnpatchAll(string) 不存在。");
|
||||
unpatchAll.Invoke(null, new object[] { _harmonyId });
|
||||
}
|
||||
|
||||
if (_verboseLogging)
|
||||
Debug.Log($"[ShrinkModFramework] 已撤回 Harmony 补丁:{_harmonyId}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[ShrinkModFramework] 撤回 Harmony 补丁失败:{_harmonyId}\n{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
AppliedHarmonyIds.Remove(_harmonyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> AppliedHarmonyIds = new(StringComparer.Ordinal);
|
||||
|
||||
public static void ApplyPatchesIfNeeded(ShrinkModInfo modInfo, bool enableHarmonyPatching, bool verboseLogging)
|
||||
{
|
||||
_ = ApplyPatchesCore(modInfo, enableHarmonyPatching, verboseLogging, reversible: false);
|
||||
}
|
||||
|
||||
public static IDisposable AcquirePatchesIfNeeded(ShrinkModInfo modInfo, bool enableHarmonyPatching,
|
||||
bool verboseLogging)
|
||||
{
|
||||
return ApplyPatchesCore(modInfo, enableHarmonyPatching, verboseLogging, reversible: true);
|
||||
}
|
||||
|
||||
private static IDisposable ApplyPatchesCore(ShrinkModInfo modInfo, bool enableHarmonyPatching,
|
||||
bool verboseLogging, bool reversible)
|
||||
{
|
||||
if (!enableHarmonyPatching || !modInfo.AutoApplyHarmonyPatches)
|
||||
return EmptyLease.Instance;
|
||||
|
||||
var harmonyType = Type.GetType("HarmonyLib.Harmony, 0Harmony");
|
||||
if (harmonyType == null)
|
||||
{
|
||||
if (verboseLogging)
|
||||
Debug.Log($"[ShrinkModFramework] 未检测到 Harmony,跳过模组 {modInfo.ModId} 的补丁自动应用。");
|
||||
return EmptyLease.Instance;
|
||||
}
|
||||
|
||||
var harmonyId = $"shrink.mod.{modInfo.ModId}";
|
||||
if (!AppliedHarmonyIds.Add(harmonyId))
|
||||
return EmptyLease.Instance;
|
||||
|
||||
try
|
||||
{
|
||||
var harmony = Activator.CreateInstance(harmonyType, harmonyId);
|
||||
var patchAll = harmonyType.GetMethod("PatchAll", new[] { typeof(Assembly) });
|
||||
if (patchAll == null)
|
||||
throw new MissingMethodException("Harmony.PatchAll(Assembly) 不存在。");
|
||||
|
||||
patchAll.Invoke(harmony, new object[] { modInfo.EntryType.Assembly });
|
||||
|
||||
if (verboseLogging)
|
||||
Debug.Log($"[ShrinkModFramework] 已应用 Harmony 补丁:{modInfo.ModId}");
|
||||
|
||||
return reversible
|
||||
? new HarmonyLease(harmonyType, harmony, harmonyId, verboseLogging)
|
||||
: EmptyLease.Instance;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppliedHarmonyIds.Remove(harmonyId);
|
||||
throw new InvalidOperationException($"模组 {modInfo.ModId} 应用 Harmony 补丁失败:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ResetForTesting() => AppliedHarmonyIds.Clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user