From 7ec125622105b5c9f5c0c1ae02757c556c03126c Mon Sep 17 00:00:00 2001 From: Tyler Young Date: Mon, 11 May 2020 23:33:30 -0400 Subject: [PATCH] fix up and relax Dynamic some add some paranoia to OneStepAheadPatch --- src/CommunityPatch/Dynamic.cs | 30 ++++++++++++------- .../Cunning/Tactics/OneStepAheadPatch.cs | 14 ++++----- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/CommunityPatch/Dynamic.cs b/src/CommunityPatch/Dynamic.cs index 5930f3f..0332868 100644 --- a/src/CommunityPatch/Dynamic.cs +++ b/src/CommunityPatch/Dynamic.cs @@ -54,7 +54,6 @@ private static void AccessInternals(Assembly asm) { } } - public static FieldRef BuildRef(this FieldInfo fieldInfo, bool skipVerification = true) { if (fieldInfo == null) throw new ArgumentNullException(nameof(fieldInfo)); @@ -82,7 +81,6 @@ public static FieldRef BuildRef(this FieldInfo fieldInfo, return (FieldRef) dmi!.CreateDelegate(typeof(FieldRef)); } - public static Func BuildGetter(this FieldInfo fieldInfo, bool skipVerification = true) { if (fieldInfo == null) throw new ArgumentNullException(nameof(fieldInfo)); @@ -137,38 +135,48 @@ public static Action BuildSetter(this FieldInfo fieldInfo, return (Action) dmi!.CreateDelegate(typeof(Action)); } - public static TDelegate BuildInvoker(this MethodBase m) where TDelegate : Delegate { + public static TDelegate BuildInvoker(this MethodBase m, bool skipVerification = true) where TDelegate : Delegate { var td = typeof(TDelegate); - Dynamic.AccessInternals(m); + AccessInternals(m); var dtMi = td.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); var dtPs = dtMi!.GetParameters(); var dt = Dynamic.CreateStaticClass(); var mn = $"{m.Name}Invoker"; - var d = Emit.BuildStaticMethod(dt, mn, MethodAttributes.Public); + var d = Emit.BuildStaticMethod(dt, mn, MethodAttributes.Public, + allowUnverifiableCode: skipVerification, doVerify: !skipVerification); var ps = m.GetParameters(); if (m.IsStatic) { for (ushort i = 0; i < ps.Length; i++) { var p = ps[i]; var dp = dtPs[i]; - if (p.ParameterType != dp.ParameterType) + if (!p.ParameterType.IsAssignableFrom(dp.ParameterType)) throw new NotImplementedException($"Unhandled parameter difference: {p.ParameterType.FullName} vs. {dp.ParameterType.FullName}"); - d.LoadArgument(i); + if (p.ParameterType.IsByRef && !dp.ParameterType.IsByRef) + d.LoadArgumentAddress(i); + else + d.LoadArgument(i); } } else { var thisParamType = m.GetThisParamType(); - if (dtPs[0].ParameterType != thisParamType) - throw new NotImplementedException($"Unhandled this parameter difference: {dtPs[0].ParameterType.FullName} vs. {thisParamType}"); + if (thisParamType.IsValueType) + if (dtPs[0].ParameterType != typeof(object) && dtPs[0].ParameterType != thisParamType) + throw new NotImplementedException($"Unhandled this parameter difference: {dtPs[0].ParameterType.FullName} vs. {thisParamType}"); + else if (dtPs[0].ParameterType != typeof(IntPtr) && dtPs[0].ParameterType != thisParamType) + throw new NotImplementedException($"Unhandled this parameter difference: {dtPs[0].ParameterType.FullName} vs. {thisParamType}"); d.LoadArgument(0); for (var i = 0; i < ps.Length; i++) { var p = ps[i]; var dp = dtPs[i + 1]; - if (p.ParameterType != dp.ParameterType) + if (!p.ParameterType.IsAssignableFrom(dp.ParameterType)) throw new NotImplementedException($"Unhandled parameter difference: {p.ParameterType.FullName} vs. {dp.ParameterType.FullName}"); - d.LoadArgument((ushort) (i + 1)); + if (p.ParameterType.IsByRef && !dp.ParameterType.IsByRef) + d.LoadArgumentAddress((ushort) (i + 1)); + else + d.LoadArgument((ushort) (i + 1)); } } diff --git a/src/CommunityPatch/Patches/Perks/Cunning/Tactics/OneStepAheadPatch.cs b/src/CommunityPatch/Patches/Perks/Cunning/Tactics/OneStepAheadPatch.cs index d700f9a..d3998bb 100644 --- a/src/CommunityPatch/Patches/Perks/Cunning/Tactics/OneStepAheadPatch.cs +++ b/src/CommunityPatch/Patches/Perks/Cunning/Tactics/OneStepAheadPatch.cs @@ -13,9 +13,9 @@ public class OneStepAheadPatch : PerkPatchBase { public override bool Applied { get; protected set; } - private static readonly Type MapNavigationHandler = Type.GetType("SandBox.View.Map.MapNavigationHandler, SandBox.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); + private static readonly Type MapNavigationHandlerType = Type.GetType("SandBox.View.Map.MapNavigationHandler, SandBox.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); - private static readonly MethodInfo TargetMethodInfo = MapNavigationHandler?.GetMethod("get_PartyEnabled", Public | Instance | DeclaredOnly); + private static readonly MethodInfo TargetMethodInfo = MapNavigationHandlerType?.GetMethod("get_PartyEnabled", Public | Instance | DeclaredOnly); private static readonly MethodInfo PatchMethodInfo = typeof(OneStepAheadPatch).GetMethod(nameof(Postfix), Public | NonPublic | Static | DeclaredOnly); @@ -33,6 +33,9 @@ public override IEnumerable GetMethodsChecked() { } }; + private static readonly Func MapNavHandlerPartyActiveGetter = MapNavigationHandlerType?.GetMethod("get_PartyActive", Public | Instance | DeclaredOnly) + ?.BuildInvoker>(); + public OneStepAheadPatch() : base("V6mvBGDV") { } @@ -56,7 +59,7 @@ public override void Apply(Game game) { public static void Postfix(ref bool __result, ref object __instance) { if (__result) return; - if (IsPartyActive(__instance)) return; + if (MapNavHandlerPartyActiveGetter(__instance)) return; if (Hero.MainHero.HeroState == Hero.CharacterStates.Prisoner) return; if (MobileParty.MainParty.MapEvent == null) return; @@ -64,11 +67,6 @@ public static void Postfix(ref bool __result, ref object __instance) { __result = Hero.MainHero.GetPerkValue(perk); } - private static bool IsPartyActive(object handler) { - var property = MapNavigationHandler.GetProperty("PartyActive", Public | Instance | DeclaredOnly); - return property != null && (bool) property.GetValue(handler); - } - } } \ No newline at end of file