diff --git a/R2API.Test/ReflectionTests.cs b/R2API.Test/ReflectionTests.cs index 1db5de09..8e24d622 100644 --- a/R2API.Test/ReflectionTests.cs +++ b/R2API.Test/ReflectionTests.cs @@ -199,16 +199,11 @@ public void TestReflectionStructPublicPropertyGetAndSet() { [Fact] public void TestReflectionItemDropAPI() { - var method = typeof(PickupIndex).GetMethodCached("get_itemIndex"); - Assert.NotNull(method); - - - var nextElementUniform = typeof(Xoroshiro128Plus) - .GetMethods() - .First(x => x.Name == "NextElementUniform" - && x.GetParameters()[0].ParameterType.GUID == typeof(List<>).GUID); - + var nextElementUniform = typeof(Xoroshiro128Plus).GetMethodWithConstructedGenericParameter("NextElementUniform", typeof(List<>)); Assert.NotNull(nextElementUniform); + + var nextElementUniformExact = nextElementUniform.MakeGenericMethod(typeof(PickupIndex)); + Assert.NotNull(nextElementUniformExact); } [Fact] diff --git a/R2API/ItemDropAPI.cs b/R2API/ItemDropAPI.cs index a6819fcf..835fd720 100644 --- a/R2API/ItemDropAPI.cs +++ b/R2API/ItemDropAPI.cs @@ -242,19 +242,19 @@ private static void RunOnBuildDropTable(On.RoR2.Run.orig_BuildDropTable orig, Ru } // These lists should be replaced soon. self.availableTier1DropList.Clear(); - self.availableTier1DropList.AddRange(GetDefaultDropList(ItemTier.Tier1).Select(x => PickupCatalog.FindPickupIndex(x)) + self.availableTier1DropList.AddRange(GetDefaultDropList(ItemTier.Tier1).Select(PickupCatalog.FindPickupIndex) .ToList()); self.availableTier2DropList.Clear(); - self.availableTier2DropList.AddRange(GetDefaultDropList(ItemTier.Tier2).Select(x => PickupCatalog.FindPickupIndex(x)) + self.availableTier2DropList.AddRange(GetDefaultDropList(ItemTier.Tier2).Select(PickupCatalog.FindPickupIndex) .ToList()); self.availableTier3DropList.Clear(); - self.availableTier3DropList.AddRange(GetDefaultDropList(ItemTier.Tier3).Select(x => PickupCatalog.FindPickupIndex(x)) + self.availableTier3DropList.AddRange(GetDefaultDropList(ItemTier.Tier3).Select(PickupCatalog.FindPickupIndex) .ToList()); self.availableEquipmentDropList.Clear(); - self.availableEquipmentDropList.AddRange(GetDefaultEquipmentDropList().Select(x => PickupCatalog.FindPickupIndex(x)) + self.availableEquipmentDropList.AddRange(GetDefaultEquipmentDropList().Select(PickupCatalog.FindPickupIndex) .ToList()); self.availableLunarDropList.Clear(); @@ -290,21 +290,14 @@ private static void DropRewards(ILContext il) { cursor.Emit(OpCodes.Stloc_0); - cursor.GotoNext(x => x.MatchCall(typeof(PickupIndex).GetMethodCached("get_itemIndex"))); - - var itemIndex = Reflection.ReadLocalIndex(cursor.Next.Next.OpCode, cursor.Next.Next.Operand); - - cursor.GotoNext(x => x.MatchCall(typeof(PickupIndex).GetConstructorCached(new[] { typeof(ItemIndex) }))); - cursor.GotoPrev(x => x.OpCode == OpCodes.Ldloca_S); - - var pickupIndex = (VariableDefinition)cursor.Next.Operand; + var nextElementUniform = typeof(Xoroshiro128Plus) + .GetMethodWithConstructedGenericParameter("NextElementUniform", typeof(List<>)) + .MakeGenericMethod(typeof(PickupIndex)); + cursor.GotoNext(MoveType.After, x => x.MatchCallOrCallvirt(nextElementUniform)); + var pickupIndex = Reflection.ReadLocalIndex(cursor.Next.OpCode, cursor.Next.Operand); cursor.Goto(0); - cursor.GotoNext(x => x.MatchStloc(itemIndex)); - cursor.Emit(OpCodes.Stloc_S, itemIndex); - - cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Dup); cursor.Emit(OpCodes.Ldfld, typeof(BossGroup).GetFieldCached("rng")); @@ -321,8 +314,6 @@ private static void DropRewards(ILContext il) { }); cursor.Emit(OpCodes.Stloc_S, pickupIndex); - cursor.Emit(OpCodes.Ldloca_S, pickupIndex); - cursor.Emit(OpCodes.Call, typeof(PickupIndex).GetMethodCached("get_itemIndex")); } public static void AddDrops(ItemDropLocation dropLocation, params PickupSelection[] pickups) { diff --git a/R2API/R2API.cs b/R2API/R2API.cs index 13447931..66948481 100644 --- a/R2API/R2API.cs +++ b/R2API/R2API.cs @@ -23,7 +23,7 @@ public class R2API : BaseUnityPlugin { public const string PluginVersion = "0.0.1"; - private const int GameBuild = 4892828; + private const int GameBuild = 5381045; internal new static ManualLogSource Logger { get; set; } @@ -107,9 +107,9 @@ public static bool IsLoaded(string submodule) { } private static void AddHookLogging() { - ModManager.OnHook += (hookOwner, @base, arg3, arg4) => LogMethod(@base, hookOwner); - ModManager.OnDetour += (hookOwner, @base, arg3) => LogMethod(@base, hookOwner); - ModManager.OnNativeDetour += (hookOwner, @base, arg3, arg4) => LogMethod(@base, hookOwner); + ModManager.OnHook += (hookOwner, @base, _, __) => LogMethod(@base, hookOwner); + ModManager.OnDetour += (hookOwner, @base, _) => LogMethod(@base, hookOwner); + ModManager.OnNativeDetour += (hookOwner, @base, _, __) => LogMethod(@base, hookOwner); HookEndpointManager.OnAdd += (@base, @delegate) => LogMethod(@base, @delegate.Method.Module.Assembly); HookEndpointManager.OnModify += (@base, @delegate) => LogMethod(@base, @delegate.Method.Module.Assembly); diff --git a/R2API/R2API.csproj b/R2API/R2API.csproj index 6e94ff64..473d2d23 100644 --- a/R2API/R2API.csproj +++ b/R2API/R2API.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 7.2 + preview 2.0.0 diff --git a/R2API/Utils/Reflection.cs b/R2API/Utils/Reflection.cs index ce9c0ab9..78cdf546 100644 --- a/R2API/Utils/Reflection.cs +++ b/R2API/Utils/Reflection.cs @@ -362,11 +362,34 @@ public static MethodInfo GetMethodCached(string name) => /// /// The type to search /// The name of the method to find - /// + /// The found public static MethodInfo GetMethodCached(this Type T, string name) => MethodCache.GetOrAddOnNull((T, name), x => x.T.GetMethod(x.name, AllFlags) ?? throw new Exception($"Could not find {nameof(MethodInfo)} on {T.FullName} with the name {name}")); + /// + /// Gets the generic method of the specified type with the specified generic type definition parameter + /// + /// The type to search + /// The name of the method to find + /// The generic type definition parameter + /// The found + public static MethodInfo GetMethodWithConstructedGenericParameter(this Type T, string name, Type genericTypeDefinition) { + return T.GetMethods().First(method => { + if (method.Name != name) { + return false; + } + + var parameterType = method.GetParameters().First().ParameterType; + if (!parameterType.IsConstructedGenericType) { + return false; + } + + var t = parameterType.GetGenericArguments().First(); + return parameterType == genericTypeDefinition.MakeGenericType(t); + }); + } + /// /// Gets the method on the specified type and caches it. This overload is used when the method is ambiguous /// @@ -777,7 +800,7 @@ private static FastReflectionDelegate GenerateCallDelegate(this MethodInfo metho throw new ArgumentException("Method cannot be null.", nameof(method)); } - var dmd = new DynamicMethodDefinition( + using var dmd = new DynamicMethodDefinition( $"CallDelegate<{method.Name}>", typeof(object), new[] { typeof(object), typeof(object[]) }); var il = dmd.GetILProcessor();