From 3984daa8f9263b6392d91db047a98f47c55a0763 Mon Sep 17 00:00:00 2001 From: Tyler Young Date: Mon, 11 May 2020 20:43:49 -0400 Subject: [PATCH] made TramplerPatch2 not panic e1.2.1 --- src/CommunityPatch/CommunityPatch.csproj | 27 ++++--- .../Perks/Endurance/Riding/TramplerPatch2.cs | 63 +++++++-------- tools/Antijank.Debugger/DebuggerContext.cs | 5 +- tools/Antijank/MbObjectManagerPatch.cs | 79 +++++++++++++------ tools/Antijank/MemoryCleanupPatch.cs | 7 +- 5 files changed, 109 insertions(+), 72 deletions(-) diff --git a/src/CommunityPatch/CommunityPatch.csproj b/src/CommunityPatch/CommunityPatch.csproj index a93a40a..eca9d7b 100644 --- a/src/CommunityPatch/CommunityPatch.csproj +++ b/src/CommunityPatch/CommunityPatch.csproj @@ -6,7 +6,7 @@ Debug;Release x64 x64 - + Community Patch Tyler Young The Mount & Blade II: Bannerlord Community @@ -33,6 +33,7 @@ True + SubModule.xml @@ -40,24 +41,24 @@ README.md - + - - + + True NU1701 - - - - - - - - - + + + + + + + + + diff --git a/src/CommunityPatch/Patches/Perks/Endurance/Riding/TramplerPatch2.cs b/src/CommunityPatch/Patches/Perks/Endurance/Riding/TramplerPatch2.cs index af779bd..61d98d4 100644 --- a/src/CommunityPatch/Patches/Perks/Endurance/Riding/TramplerPatch2.cs +++ b/src/CommunityPatch/Patches/Perks/Endurance/Riding/TramplerPatch2.cs @@ -4,6 +4,7 @@ using TaleWorlds.CampaignSystem; using TaleWorlds.Core; using HarmonyLib; +using JetBrains.Annotations; using TaleWorlds.Engine; using TaleWorlds.MountAndBlade; using static System.Reflection.BindingFlags; @@ -12,21 +13,21 @@ namespace CommunityPatch.Patches.Perks.Endurance.Riding { public sealed class TramplerPatch2 : PerkPatchBase { + public override bool Applied { get; protected set; } private static readonly MethodInfo OverloadedTargetMethodInfo = typeof(Mission).GetMethod("GetAttackCollisionResults", Public | Static | DeclaredOnly); - private static readonly Type AttackInformationType = Type.GetType("AttackInformation"); - - private static readonly ConstructorInfo TargetConstructorInfo = typeof(AttackInformation).GetConstructor(new [] { + [CanBeNull] + private static readonly Type AttackInformationType = Type.GetType("TaleWorlds.MountAndBlade.AttackInformation, TaleWorlds.MountAndBlade, Version=1.0.0.0, Culture=neutral", false); + + private static readonly ConstructorInfo TargetConstructorInfo = AttackInformationType?.GetConstructor(new[] { typeof(Agent), typeof(Agent), typeof(GameEntity), typeof(AttackCollisionData).MakeByRefType() }); - private static readonly MethodInfo UpdateCharacterPostfixPatchMethodInfo = typeof(TramplerPatch2). - GetMethod(nameof(UpdateCorrectCharacterForHorseChargeDamagePostfix), NonPublic | Static | DeclaredOnly); + private static readonly MethodInfo UpdateCharacterPostfixPatchMethodInfo = typeof(TramplerPatch2).GetMethod(nameof(UpdateCorrectCharacterForHorseChargeDamagePostfix), NonPublic | Static | DeclaredOnly); - private static readonly MethodInfo UpdateHorseDamagePostfixPatchMethodInfo = typeof(TramplerPatch2). - GetMethod(nameof(UpdateHorseDamagePostfix), NonPublic | Static | DeclaredOnly); + private static readonly MethodInfo UpdateHorseDamagePostfixPatchMethodInfo = typeof(TramplerPatch2).GetMethod(nameof(UpdateHorseDamagePostfix), NonPublic | Static | DeclaredOnly); public override IEnumerable GetMethodsChecked() { yield return TargetConstructorInfo; @@ -42,7 +43,7 @@ public override IEnumerable GetMethodsChecked() { 0x90, 0x4E, 0x8B, 0x8C, 0x14, 0xB1, 0xE6, 0xC7 } }; - + public static readonly byte[][] ConstructorHashes = { new byte[] { // e1.4.0.228616 @@ -57,19 +58,18 @@ public TramplerPatch2() : base("GKlmIYik") { } public override bool? IsApplicable(Game game) { - if (OverloadedTargetMethodInfo == null) return false; - + if (AlreadyPatchedByOthers(Harmony.GetPatchInfo(OverloadedTargetMethodInfo))) return false; if (!OverloadedTargetMethodInfo.MakeCilSignatureSha256().MatchesAnySha256(OverloadedTargetHashes)) return false; - + if (TargetConstructorInfo == null) return false; - + if (AlreadyPatchedByOthers(Harmony.GetPatchInfo(TargetConstructorInfo))) return false; @@ -82,30 +82,26 @@ public TramplerPatch2() : base("GKlmIYik") { public override void Apply(Game game) { if (Applied) return; - CommunityPatchSubModule.Harmony.Patch(TargetConstructorInfo, - postfix: new HarmonyMethod(UpdateCharacterPostfixPatchMethodInfo)); + CommunityPatchSubModule.Harmony.Patch(TargetConstructorInfo, + postfix: new HarmonyMethod(UpdateCharacterPostfixPatchMethodInfo)); - CommunityPatchSubModule.Harmony.Patch(OverloadedTargetMethodInfo, - postfix: new HarmonyMethod(UpdateHorseDamagePostfixPatchMethodInfo)); + CommunityPatchSubModule.Harmony.Patch(OverloadedTargetMethodInfo, + postfix: new HarmonyMethod(UpdateHorseDamagePostfixPatchMethodInfo)); Applied = true; } - - private static readonly FieldInfo AttackerAgentCharacterFieldInfo = typeof(AttackInformation) - .GetField(nameof(AttackInformation.AttackerAgentCharacter), Public | Instance | DeclaredOnly); - - private static void SetAttackerAgentCharacter(ref AttackInformation attackInformation, BasicCharacterObject attackerCharacter) { - object boxed = attackInformation; - AttackerAgentCharacterFieldInfo.SetValue(boxed, attackerCharacter); - attackInformation = (AttackInformation) boxed; - } - - private static void UpdateCorrectCharacterForHorseChargeDamagePostfix(ref AttackInformation __instance, Agent attackerAgent, ref AttackCollisionData attackCollisionData) { - if (attackCollisionData.IsHorseCharge && attackerAgent.RiderAgent?.Character != null) { - SetAttackerAgentCharacter(ref __instance, attackerAgent.RiderAgent.Character); - } + + private static readonly FieldInfo AttackerAgentCharacterFieldInfo = AttackInformationType?.GetField("AttackerAgentCharacter", Public | Instance | DeclaredOnly); + + [CanBeNull] + private static readonly AccessTools.FieldRef AttackerAgentCharacter + = AttackerAgentCharacterFieldInfo == null ? null : AccessTools.FieldRefAccess(AttackerAgentCharacterFieldInfo); + + private static void UpdateCorrectCharacterForHorseChargeDamagePostfix(ref object __instance, Agent attackerAgent, ref AttackCollisionData attackCollisionData) { + if (attackCollisionData.IsHorseCharge && attackerAgent.RiderAgent?.Character != null) + AttackerAgentCharacter!(__instance) = attackerAgent.RiderAgent.Character; } - + private static bool HeroHasPerk(BasicCharacterObject character, PerkObject perk) => (character as CharacterObject)?.GetPerkValue(perk) ?? false; @@ -114,14 +110,15 @@ private int TramplerDamageModifier(int baseDamage) { return (int) Math.Round(tramplerDamage, MidpointRounding.AwayFromZero); } - private static void UpdateHorseDamagePostfix(ref AttackInformation attackInformation, ref AttackCollisionData attackCollisionData, ref CombatLogData combatLog) { - if (!(attackCollisionData.IsHorseCharge && HeroHasPerk(attackInformation.AttackerAgentCharacter, ActivePatch.Perk))) { + private static void UpdateHorseDamagePostfix(ref object attackInformation, ref AttackCollisionData attackCollisionData, ref CombatLogData combatLog) { + if (!(attackCollisionData.IsHorseCharge && HeroHasPerk(AttackerAgentCharacter!(attackInformation), ActivePatch.Perk))) { return; } combatLog.InflictedDamage = ActivePatch.TramplerDamageModifier(combatLog.InflictedDamage); attackCollisionData.InflictedDamage = ActivePatch.TramplerDamageModifier(attackCollisionData.InflictedDamage); } + } } \ No newline at end of file diff --git a/tools/Antijank.Debugger/DebuggerContext.cs b/tools/Antijank.Debugger/DebuggerContext.cs index 7cfed7f..48b4ae3 100644 --- a/tools/Antijank.Debugger/DebuggerContext.cs +++ b/tools/Antijank.Debugger/DebuggerContext.cs @@ -103,14 +103,14 @@ private void Start() public static ICorDebugProcess? DebugProcess; [ThreadStatic] - public static ICLRRuntimeInfo ClrRuntime; + public static ICLRRuntimeInfo? ClrRuntime; [ThreadStatic] public static ICorProfilerInfo? ProfilerInfo; public static int ThreadId; - public static readonly MethodInfo TestEnCMethod = typeof(DebuggerContext).GetMethod(nameof(TestEnC), DeclaredOnly | Public | Static); + //public static readonly MethodInfo TestEnCMethod = typeof(DebuggerContext).GetMethod(nameof(TestEnC), DeclaredOnly | Public | Static); public static bool TestEnC() => false; @@ -203,6 +203,7 @@ out var flags */ } + // debugger loop foreach (var callback in _executionQueue.GetConsumingEnumerable()) { try { callback(); diff --git a/tools/Antijank/MbObjectManagerPatch.cs b/tools/Antijank/MbObjectManagerPatch.cs index 27af55e..d6c1ffc 100644 --- a/tools/Antijank/MbObjectManagerPatch.cs +++ b/tools/Antijank/MbObjectManagerPatch.cs @@ -7,15 +7,60 @@ using System.Runtime.CompilerServices; using System.Xml; using HarmonyLib; -using TaleWorlds.ObjectSystem; using static System.Reflection.BindingFlags; namespace Antijank { public static class MbObjectManagerPatch { - private static int InitCount = 0; + private static readonly Type MbObjectMgrType + = Type.GetType("TaleWorlds.ObjectSystem.MBObjectManager, TaleWorlds.ObjectSystem, Version=1.0.0.0, Culture=neutral", false) + ?? Type.GetType("TaleWorlds.Core.MBObjectManager, TaleWorlds.Core, Version=1.0.0.0, Culture=neutral", true); + + private static readonly Type MbObjectBaseType + = Type.GetType("TaleWorlds.ObjectSystem.MBObjectBase, TaleWorlds.ObjectSystem, Version=1.0.0.0, Culture=neutral", false) + ?? Type.GetType("TaleWorlds.Core.MBObjectBase, TaleWorlds.Core, Version=1.0.0.0, Culture=neutral", true); + + + private static readonly Type ObjTypeRecType = MbObjectMgrType.GetNestedType("IObjectTypeRecord", NonPublic | Instance | Static); + + private static readonly MethodInfo ObjTypeRecElementListNameMethod = AccessTools.PropertyGetter(ObjTypeRecType, "ElementListName"); + + private static readonly MethodInfo ObjTypeRecElementNameMethod = AccessTools.PropertyGetter(ObjTypeRecType, "ElementName"); + + //private static string ObjTypeRecElementListName(object otr) => (string) ObjTypeRecElementListNameMethod.Invoke(otr, null); + private static readonly Func ObjTypeRecElementListName + = ObjTypeRecElementListNameMethod.BuildInvoker>(); + + //private static string ObjTypeRecElementName(object otr) => (string) ObjTypeRecElementNameMethod.Invoke(otr, null); + private static readonly Func ObjTypeRecElementName + = ObjTypeRecElementNameMethod.BuildInvoker>(); + + private static readonly MethodInfo MbObjectManagerGetPresumedObjectMethod = AccessTools.Method(MbObjectMgrType, "GetPresumedObject"); + private static readonly MethodInfo MbObjectBaseDeserializeMethod1 + = MbObjectBaseType.GetMethod("Deserialize", Public | NonPublic | Instance | DeclaredOnly, null, new[] {MbObjectMgrType, typeof(XmlNode)}, null); + + private static readonly MethodInfo MbObjectBaseDeserializeMethod2 + = MbObjectBaseType.GetMethod("Deserialize", Public | NonPublic | Instance | DeclaredOnly, null, new[] {MbObjectMgrType, typeof(XmlNode), typeof(Type)}, null); + + private static readonly MethodInfo MbObjectBaseAfterInitializedMethod + = MbObjectBaseType.GetMethod("AfterInitialized", Public | NonPublic | Instance | DeclaredOnly); + + private static readonly Action MbObjectBaseDeserialize1 + = MbObjectBaseDeserializeMethod1.BuildInvoker>(); + + private static readonly Action MbObjectBaseDeserialize2 + = MbObjectBaseDeserializeMethod2.BuildInvoker>(); + + private static readonly Action MbObjectBaseAfterInitialized + = MbObjectBaseAfterInitializedMethod.BuildInvoker>(); + + private static readonly Func MbObjectManagerGetPresumedObject + = MbObjectManagerGetPresumedObjectMethod.BuildInvoker>(); + + private static int InitCount = 0; + static MbObjectManagerPatch() { if (InitCount > 0) { if (Debugger.IsAttached) @@ -24,11 +69,12 @@ static MbObjectManagerPatch() { } ++InitCount; - Context.Harmony.Patch(AccessTools.Method(typeof(MBObjectManager), "CreateDocumentFromXmlFile"), + + Context.Harmony.Patch(AccessTools.Method(MbObjectMgrType, "CreateDocumentFromXmlFile"), postfix: new HarmonyMethod(typeof(MbObjectManagerPatch), nameof(CreateDocumentFromXmlFilePostfix))); - Context.Harmony.Patch(AccessTools.Method(typeof(MBObjectManager), "MergeTwoXmls"), + Context.Harmony.Patch(AccessTools.Method(MbObjectMgrType, "MergeTwoXmls"), new HarmonyMethod(typeof(MbObjectManagerPatch), nameof(MergeTwoXmlsReplacement))); - Context.Harmony.Patch(AccessTools.Method(typeof(MBObjectManager), "LoadXml"), + Context.Harmony.Patch(AccessTools.Method(MbObjectMgrType, "LoadXml"), new HarmonyMethod(typeof(MbObjectManagerPatch), nameof(LoadXmlReplacement))); } @@ -98,24 +144,12 @@ private static bool MergeTwoXmlsReplacement(ref XmlDocument __result, XmlDocumen return false; } - private static readonly Type ObjTypeRecType = typeof(MBObjectManager).GetNestedType("IObjectTypeRecord", NonPublic | Instance | Static); - - private static readonly MethodInfo ObjTypeRecElementListNameMethod = AccessTools.PropertyGetter(ObjTypeRecType, "ElementListName"); - - private static readonly MethodInfo ObjTypeRecElementNameMethod = AccessTools.PropertyGetter(ObjTypeRecType, "ElementName"); - - private static readonly MethodInfo MbObjectManagerGetPresumedObjectMethod = AccessTools.Method(typeof(MBObjectManager), "GetPresumedObject"); - - private static string ObjTypeRecElementListName(object otr) => (string) ObjTypeRecElementListNameMethod.Invoke(otr, null); - - private static string ObjTypeRecElementName(object otr) => (string) ObjTypeRecElementNameMethod.Invoke(otr, null); - private static readonly Dictionary ContinueWithErrorRememberChoice = new Dictionary(); private static readonly string AntijankXmlNamespace = "https://antijank/"; [MethodImpl(MethodImplOptions.NoInlining)] - private static bool LoadXmlReplacement(MBObjectManager __instance, IList ___ObjectTypeRecords, IList ___NonSerializedObjectTypeRecords, XmlDocument doc, Type typeOfGameMenusCallbacks) { + private static bool LoadXmlReplacement(object __instance, IList ___ObjectTypeRecords, IList ___NonSerializedObjectTypeRecords, XmlDocument doc, Type typeOfGameMenusCallbacks) { var nodeIndex = 0; var found = false; string typeName = null; @@ -157,12 +191,13 @@ private static bool LoadXmlReplacement(MBObjectManager __instance, IList ___Obje var id = elem.GetAttribute("id"); try { - var obj = (MBObjectBase) MbObjectManagerGetPresumedObjectMethod.Invoke(__instance, new object[] {typeName, id, true}); + // (MBObjectBase) + var obj = MbObjectManagerGetPresumedObject(__instance, typeName, id, true); if (typeOfGameMenusCallbacks != null) - obj.Deserialize(__instance, node, typeOfGameMenusCallbacks); + MbObjectBaseDeserialize2(obj, __instance, node, typeOfGameMenusCallbacks); else - obj.Deserialize(__instance, node); - obj.AfterInitialized(); + MbObjectBaseDeserialize1(obj, __instance, node); + MbObjectBaseAfterInitialized(obj); } catch (Exception ex) { var source = elem.GetAttribute("source", AntijankXmlNamespace); diff --git a/tools/Antijank/MemoryCleanupPatch.cs b/tools/Antijank/MemoryCleanupPatch.cs index db1d961..b45280f 100644 --- a/tools/Antijank/MemoryCleanupPatch.cs +++ b/tools/Antijank/MemoryCleanupPatch.cs @@ -33,8 +33,11 @@ static MemoryCleanupPatch() { Context.Harmony.Patch(AccessTools.Method(typeof(Managed), "GarbageCollect"), new HarmonyMethod(typeof(MemoryCleanupPatch), nameof(MemoryCleanupReplacement))); - Context.Harmony.Patch(AccessTools.Method(Type.GetType("TaleWorlds.SaveSystem.Load.LoadCallbackInitializator, TaleWorlds.SaveSystem, Version=1.0.0.0, Culture=neutral"), "InitializeObjects"), - transpiler: new HarmonyMethod(typeof(MemoryCleanupPatch), nameof(GcCallsTranspiler))); + var loadCallbackInit = Type.GetType("TaleWorlds.SaveSystem.Load.LoadCallbackInitializator, TaleWorlds.SaveSystem, Version=1.0.0.0, Culture=neutral", false); + if (loadCallbackInit != null) { + var initObjs = AccessTools.Method(loadCallbackInit, "InitializeObjects"); + Context.Harmony.Patch(initObjs, transpiler: new HarmonyMethod(typeof(MemoryCleanupPatch), nameof(GcCallsTranspiler))); + } Context.Harmony.Patch(AccessTools.Method(typeof(LoadContext), nameof(LoadContext.Load)), transpiler: new HarmonyMethod(typeof(MemoryCleanupPatch), nameof(GcCallsTranspiler)));