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 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(); } }