internal static void DoDetours() { // provide some info Verse.Log.Message("FluffyLib :: Detours :: Scanning mod assemblies for detour requests..."); // loop over all methods and properties in all mod's assemblies foreach (ModContentPack mod in LoadedModManager.RunningMods) { #if DEBUG_SPAMMY_DETOURS Verse.Log.Message(mod.Name); #endif foreach (Assembly assembly in mod.assemblies.loadedAssemblies) { #if DEBUG_SPAMMY_DETOURS Verse.Log.Message("\t" + assembly.FullName); #endif foreach (Type type in assembly.GetTypes()) { #if DEBUG_SPAMMY_DETOURS Verse.Log.Message("\t\t" + type.FullName); #endif foreach (MethodInfo methodInfo in type.GetMethods(AllBindingFlags)) { #if DEBUG_SPAMMY_DETOURS Verse.Log.Message("\t\t\t" + methodInfo.Name); #endif if (methodInfo.HasAttribute <DetourMethodAttribute>()) { #if DEBUG_SPAMMY_DETOURS Verse.Log.Message("\t\t\t\t" + "DING!"); #endif // if attribute is defined, do the detour DetourMethodAttribute detourAttribute = methodInfo.GetCustomAttributes(typeof(DetourMethodAttribute), false).First() as DetourMethodAttribute; HandleDetour(detourAttribute, methodInfo); } } foreach (PropertyInfo propertyInfo in type.GetProperties((AllBindingFlags))) { #if DEBUG_SPAMMY_DETOURS Verse.Log.Message("\t\t\t" + propertyInfo.Name); #endif if (propertyInfo.HasAttribute <DetourPropertyAttribute>()) { #if DEBUG_SPAMMY_DETOURS Verse.Log.Message("\t\t\t\t" + "DING!"); #endif // if attribute is defined, do the detour DetourPropertyAttribute detourAttribute = propertyInfo.GetCustomAttributes(typeof(DetourPropertyAttribute), false).First() as DetourPropertyAttribute; HandleDetour(detourAttribute, propertyInfo); } } } } } #if DEBUG DetourTest.RunTests(); #endif }
private static MethodInfo GetMatchingMethodInfo(DetourMethodAttribute sourceAttribute, MethodInfo targetInfo) { // we should only ever get here in case the attribute was not defined with a sourceMethodInfo, but let's check just in case. if (sourceAttribute.WasSetByMethodInfo) { return(sourceAttribute.sourceMethodInfo); } // aight, let's search by name MethodInfo[] candidates = sourceAttribute.sourceType.GetMethods(AllBindingFlags) .Where(mi => mi.Name == sourceAttribute.sourceMethodName).ToArray(); // if we only get one result, we've got our method info - if the length is zero, the method doesn't exist. if (candidates.Length == 0) { return(null); } if (candidates.Length == 1) { return(candidates.First()); } // this is where things get slightly complicated, we'll have to search by parameters. candidates = candidates.Where(mi => mi.ReturnType == targetInfo.ReturnType && mi.GetParameters() .Select(pi => pi.ParameterType) .SequenceEqual(targetInfo.GetParameters().Select(pi => pi.ParameterType))) .ToArray(); // if we only get one result, we've got our method info - if the length is zero, the method doesn't exist. if (candidates.Length == 0) { return(null); } if (candidates.Length == 1) { return(candidates.First()); } // if we haven't returned anything by this point there were still multiple candidates. This is theoretically impossible, // unless I missed something. return(null); }
private static void HandleDetour(DetourMethodAttribute sourceAttribute, MethodInfo targetInfo) { // we need to get the method info of the source (usually, vanilla) method. // if it was specified in the attribute, this is easy. Otherwise, we'll have to do some digging. MethodInfo sourceInfo = sourceAttribute.WasSetByMethodInfo ? sourceAttribute.sourceMethodInfo : GetMatchingMethodInfo(sourceAttribute, targetInfo); // make sure we've got what we wanted. if (sourceInfo == null) { throw new NullReferenceException("sourceMethodInfo could not be found based on attribute"); } if (targetInfo == null) { throw new ArgumentNullException(nameof(targetInfo)); } // call the actual detour TryDetourFromTo(sourceInfo, targetInfo); }