Files
7d2dXG/XG-Rebirth/Mods/0A-KFCommonUtilityLib/Harmony/ModularPatches.cs
2025-05-30 00:19:27 +09:30

344 lines
16 KiB
C#

using HarmonyLib;
using HarmonyLib.Public.Patching;
using System.Collections.Generic;
using UniLinq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System;
namespace KFCommonUtilityLib.Harmony
{
[HarmonyPatch]
public static class ModularPatches
{
[HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))]
[HarmonyPrefix]
private static bool Prefix_StartGame_GameManager()
{
ModuleManagers.InitNew();
return true;
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.Init))]
[HarmonyPostfix]
private static void Postfix_Init_ItemClass(ItemClass __instance)
{
ItemClassModuleManager.CheckItem(__instance);
ItemActionModuleManager.CheckItem(__instance);
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.worldInfoCo), MethodType.Enumerator)]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_worldInfoCo_GameManager(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_all = AccessTools.Method(typeof(WorldStaticData), nameof(WorldStaticData.AllConfigsReceivedAndLoaded));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_all))
{
codes.Insert(i + 2, CodeInstruction.Call(typeof(ModuleManagers), nameof(ModuleManagers.FinishAndLoad)).WithLabels(codes[i + 2].ExtractLabels()));
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ConnectionManager), nameof(ConnectionManager.ServerReady))]
[HarmonyPrefix]
private static void Prefix_ServerReady_ConnectionManager()
{
ModuleManagers.FinishAndLoad();
}
[HarmonyPatch(typeof(WorldStaticData), nameof(WorldStaticData.ReloadAllXmlsSync))]
[HarmonyPrefix]
private static void Prefix_ReloadAllXmlsSync_WorldStaticData()
{
ModuleManagers.InitNew();
}
[HarmonyPatch(typeof(WorldStaticData), nameof(WorldStaticData.ReloadAllXmlsSync))]
[HarmonyPostfix]
private static void Postfix_ReloadAllXmlsSync_WorldStaticData()
{
ModuleManagers.FinishAndLoad();
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.Disconnect))]
[HarmonyPostfix]
private static void Postfix_Disconnect_GameManager()
{
ModuleManagers.Cleanup();
}
[HarmonyPatch(typeof(PatchManager), "GetRealMethod")]
[HarmonyReversePatch]
public static MethodBase GetRealMethod(MethodInfo method, bool useReplacement)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
{
return null;
}
return new CodeInstruction[]
{
CodeInstruction.LoadField(typeof(PatchManager), "ReplacementToOriginals"),
CodeInstruction.LoadField(typeof(PatchManager), "ReplacementToOriginalsMono"),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.Call(typeof(ModularPatches), nameof(ModularPatches.GetPatched)),
new CodeInstruction(OpCodes.Ret)
};
}
_ = Transpiler(null);
return null;
}
private static MethodBase GetPatched(ConditionalWeakTable<MethodBase, MethodBase> ReplacementToOriginals, Dictionary<long, MethodBase[]> ReplacementToOriginalsMono, MethodInfo method)
{
MethodInfo methodInfo = method.Identifiable();
ConditionalWeakTable<MethodBase, MethodBase> replacementToOriginals = ReplacementToOriginals;
lock (replacementToOriginals)
{
foreach (var pair in replacementToOriginals)
{
if (pair.Value == method)
{
Log.Out($"Found method replacement {pair.Key.FullDescription()} for method {method.FullDescription()}");
return pair.Key;
}
}
}
if (AccessTools.IsMonoRuntime)
{
long num = (long)method.MethodHandle.GetFunctionPointer();
Dictionary<long, MethodBase[]> replacementToOriginalsMono = ReplacementToOriginalsMono;
lock (replacementToOriginalsMono)
{
foreach (var pair in replacementToOriginalsMono)
{
if (pair.Value[0] == method)
{
Log.Out($"Found MONO method replacement {pair.Value[1].FullDescription()} for method {method.FullDescription()}");
return pair.Value[1];
}
}
}
}
return method;
}
[HarmonyPatch(typeof(PatchManager), nameof(PatchManager.ToPatchInfo))]
[HarmonyReversePatch]
public static PatchInfo ToPatchInfoDontAdd(this MethodBase methodBase)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
{
return null;
}
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Dup)
{
codes[i - 1].WithLabels(codes[i - 3].ExtractLabels());
codes.RemoveAt(i + 2);
codes.RemoveAt(i);
codes.RemoveRange(i - 3, 2);
break;
}
}
return codes;
}
_ = Transpiler(null);
return null;
}
[HarmonyPatch(typeof(PatchInfo), "AddTranspilers")]
[HarmonyReversePatch]
public static void AddTranspilers(this PatchInfo self, string owner, params HarmonyMethod[] methods)
{
}
public static PatchInfo Copy(this PatchInfo self)
{
var res = new PatchInfo();
res.prefixes = new Patch[self.prefixes.Length];
res.postfixes = new Patch[self.postfixes.Length];
res.transpilers = new Patch[self.transpilers.Length];
res.finalizers = new Patch[self.finalizers.Length];
res.ilmanipulators = new Patch[self.ilmanipulators.Length];
Array.Copy(self.prefixes, res.prefixes, res.prefixes.Length);
Array.Copy(self.postfixes, res.postfixes, res.postfixes.Length);
Array.Copy(self.transpilers, res.transpilers, res.transpilers.Length);
Array.Copy(self.finalizers, res.finalizers, res.finalizers.Length);
Array.Copy(self.ilmanipulators, res.ilmanipulators, res.ilmanipulators.Length);
return res;
}
//public static MethodBase GetOriginalMethod(this HarmonyMethod attr)
//{
// try
// {
// MethodType? methodType = attr.methodType;
// if (methodType != null)
// {
// switch (methodType.GetValueOrDefault())
// {
// case MethodType.Normal:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null);
// case MethodType.Getter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo = AccessTools.DeclaredIndexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo != null) ? propertyInfo.GetGetMethod(true) : null;
// }
// PropertyInfo propertyInfo2 = AccessTools.DeclaredProperty(attr.declaringType, attr.methodName);
// return (propertyInfo2 != null) ? propertyInfo2.GetGetMethod(true) : null;
// }
// case MethodType.Setter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo3 = AccessTools.DeclaredIndexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo3 != null) ? propertyInfo3.GetSetMethod(true) : null;
// }
// PropertyInfo propertyInfo4 = AccessTools.DeclaredProperty(attr.declaringType, attr.methodName);
// return (propertyInfo4 != null) ? propertyInfo4.GetSetMethod(true) : null;
// }
// case MethodType.Constructor:
// return AccessTools.DeclaredConstructor(attr.declaringType, attr.argumentTypes, false);
// case MethodType.StaticConstructor:
// return AccessTools.GetDeclaredConstructors(attr.declaringType, null).FirstOrDefault((ConstructorInfo c) => c.IsStatic);
// case MethodType.Enumerator:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// case MethodType.Async:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.AsyncMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// }
// }
// }
// catch (AmbiguousMatchException ex)
// {
// throw new Exception("Ambiguous match for HarmonyMethod[" + attr.ToString() + "]", ex.InnerException ?? ex);
// }
// return null;
//}
//public static MethodBase GetBaseMethod(this HarmonyMethod attr)
//{
// try
// {
// MethodType? methodType = attr.methodType;
// if (methodType != null)
// {
// switch (methodType.GetValueOrDefault())
// {
// case MethodType.Normal:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null);
// case MethodType.Getter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo = AccessTools.Indexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo != null) ? propertyInfo.GetGetMethod(true) : null;
// }
// PropertyInfo propertyInfo2 = AccessTools.Property(attr.declaringType, attr.methodName);
// return (propertyInfo2 != null) ? propertyInfo2.GetGetMethod(true) : null;
// }
// case MethodType.Setter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo3 = AccessTools.Indexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo3 != null) ? propertyInfo3.GetSetMethod(true) : null;
// }
// PropertyInfo propertyInfo4 = AccessTools.Property(attr.declaringType, attr.methodName);
// return (propertyInfo4 != null) ? propertyInfo4.GetSetMethod(true) : null;
// }
// case MethodType.Constructor:
// return AccessTools.Constructor(attr.declaringType, attr.argumentTypes, false);
// case MethodType.StaticConstructor:
// return AccessTools.GetDeclaredConstructors(attr.declaringType, null).FirstOrDefault((ConstructorInfo c) => c.IsStatic);
// case MethodType.Enumerator:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.EnumeratorMoveNext(AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// case MethodType.Async:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.AsyncMoveNext(AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// }
// }
// }
// catch (AmbiguousMatchException ex)
// {
// throw new Exception("Ambiguous match for HarmonyMethod[" + attr.ToString() + "]", ex.InnerException ?? ex);
// }
// return null;
//}
}
[HarmonyPatch]
public static class PatchToolsPatches
{
public static MethodBase TargetMethod()
{
return AccessTools.DeclaredMethod(AccessTools.TypeByName("HarmonyLib.PatchTools"), "GetOriginalMethod");
}
[HarmonyReversePatch]
public static MethodBase GetOriginalMethod(this HarmonyMethod attr)
{
return null;
}
[HarmonyReversePatch]
public static MethodBase GetBaseMethod(this HarmonyMethod attr)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
return null;
return instructions.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredMethod), new[] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Method), new[] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }))
.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredIndexer)),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Indexer)))
.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredProperty), new[] { typeof(Type), typeof(string) }),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Property), new[] { typeof(Type), typeof(string) }))
.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredConstructor)),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Constructor)));
}
_ = Transpiler(null);
return null;
}
}
}