diff --git a/SecretAPI/Attributes/CallOnLoadAttribute.cs b/SecretAPI/Attributes/CallOnLoadAttribute.cs index 4ece8ce..ab0e265 100644 --- a/SecretAPI/Attributes/CallOnLoadAttribute.cs +++ b/SecretAPI/Attributes/CallOnLoadAttribute.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using SecretAPI.Extensions; using SecretAPI.Features; /// @@ -50,21 +51,14 @@ public static void Load(Assembly? assembly = null) internal static void CallAttributeMethodPriority(Assembly assembly) where TAttribute : Attribute, IPriority { - const BindingFlags methodFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; Dictionary methods = new(); - - // get all types - foreach (Type type in assembly.GetTypes()) + foreach (MethodInfo method in assembly.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) { - // get all static methods - foreach (MethodInfo method in type.GetMethods(methodFlags)) - { - TAttribute? attribute = method.GetCustomAttribute(); - if (attribute == null) - continue; + TAttribute? attribute = method.GetCustomAttribute(); + if (attribute == null) + continue; - methods.Add(attribute, method); - } + methods.Add(attribute, method); } foreach (KeyValuePair method in methods.OrderBy(static v => v.Key.Priority)) diff --git a/SecretAPI/Debugging/PrefabDebugging.cs b/SecretAPI/Debugging/PrefabDebugger.cs similarity index 97% rename from SecretAPI/Debugging/PrefabDebugging.cs rename to SecretAPI/Debugging/PrefabDebugger.cs index d82e9f2..dc2a893 100644 --- a/SecretAPI/Debugging/PrefabDebugging.cs +++ b/SecretAPI/Debugging/PrefabDebugger.cs @@ -15,7 +15,7 @@ namespace SecretAPI.Debugging; /// /// Debugs basegame prefabs by logging information about them. /// -internal static class PrefabDebugging +internal static class PrefabDebugger { /// /// Loads the prefab debugging. diff --git a/SecretAPI/Extensions/ReflectionExtensions.cs b/SecretAPI/Extensions/ReflectionExtensions.cs index f367c6e..32767cf 100644 --- a/SecretAPI/Extensions/ReflectionExtensions.cs +++ b/SecretAPI/Extensions/ReflectionExtensions.cs @@ -1,8 +1,10 @@ namespace SecretAPI.Extensions; using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; +using HarmonyLib; /// /// Extensions for reflection. @@ -36,16 +38,42 @@ public static string GetLongFuncName(Type type, MethodInfo method) } /// - /// Copies the properties. + /// Searches through an assembly and returns all based on the provided flags. + /// + /// The assembly to search through. + /// The used for the method search within a . + /// A collection of based on the provided assembly and flags. + public static IEnumerable GetMethods(this Assembly assembly, BindingFlags flags) + => assembly.GetTypes().SelectMany(type => type.GetMethods(flags)); + + /// + /// Gets a nested within a . + /// + /// The containing the needed method. + /// The name of the nested type, this does not need to be exact. + /// The name of the method, this does not need to be exact. + /// The found method, or null if none matched. + public static MethodInfo? GetNestedMethod(this Type type, string nestedTypeName, string methodName) + { + return type.GetNestedTypes(AccessTools.all) + .Where(t => t.Name.Contains(nestedTypeName)) + .SelectMany(t => t.GetMethods(AccessTools.all)) + .FirstOrDefault(m => m.Name.Contains(methodName)); + } + + /// + /// Copies the properties from a onto another instance. /// /// The source of the properties to copy. - /// Where to copy to. - public static void CopyProperties(this object source, object destination) + /// Where the source properties should be copied to, this should match the same as source. + public static void CopyPropertiesTo(this object source, object destination) { - Type destinationType = destination.GetType(); - foreach (PropertyInfo property in source.GetType().GetProperties()) - { - destinationType.GetProperty(property.Name)?.SetValue(destination, property.GetValue(source)); - } + Type type = source.GetType(); + + if (type != destination.GetType()) + throw new InvalidOperationException($"[ReflectionExtensions.CopyPropertiesTo] Source and destination types are mismatched: {type.FullName} | {destination.GetType().FullName}"); + + foreach (PropertyInfo property in type.GetProperties()) + property.SetValue(destination, property.GetValue(source)); } } \ No newline at end of file diff --git a/SecretAPI/Patches/Features/RoundEndIgnorePatch.cs b/SecretAPI/Patches/Features/RoundEndIgnorePatch.cs index d8611b1..0a6dc7a 100644 --- a/SecretAPI/Patches/Features/RoundEndIgnorePatch.cs +++ b/SecretAPI/Patches/Features/RoundEndIgnorePatch.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Reflection.Emit; using HarmonyLib; +using LabApi.Features.Console; using LabApi.Features.Wrappers; using PlayerRoles; using SecretAPI.Attributes; @@ -14,37 +15,33 @@ using SecretAPI.Features; /// -/// Handles patching to implement into . +/// Handles patching to implement into . /// [HarmonyPatchCategory(nameof(PlayerRoundIgnore))] [HarmonyPatch] internal static class RoundEndIgnorePatch { - private const string StateMachine = "<_ProcessServerSideCode>d__58"; + private const string StateMachine = "_ProcessServerSideCode"; private const string MoveNext = "MoveNext"; private const int ReferenceHubLocalIndex = 20; + private const int SkipAdvanceAmount = 4; // amount needed to get to IL_0131: br IL_01bd private static MethodInfo TargetMethod() { - // typeof(RoundSummary).GetNestedTypes(AccessTools.all).ForEach(type => Logger.Debug(type.FullName ?? "NULL")); - Type nestedType = typeof(RoundSummary).GetNestedTypes(AccessTools.all) - .FirstOrDefault(type => type.Name is StateMachine) ?? throw new Exception($"Could not locate state machine for {StateMachine}"); - - // nestedType.GetMethods(AccessTools.all).ForEach(method => Logger.Debug(method.Name)); - MethodInfo moveNextMethod = nestedType.GetMethods(AccessTools.all) - .FirstOrDefault(x => x.Name.Contains(MoveNext)) ?? throw new Exception($"Could not locate {MoveNext} method in state machine"); - - return moveNextMethod; + return typeof(RoundSummary).GetNestedMethod(StateMachine, MoveNext) + ?? throw new Exception($"Could not locate state machine for {StateMachine} | {MoveNext}"); } private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) { CodeMatcher matcher = new CodeMatcher(instructions, generator) .MatchEndForward(new CodeMatch(CodeInstruction.Call(typeof(PlayerRolesUtils), nameof(PlayerRolesUtils.GetTeam), [typeof(ReferenceHub)]))) + .Advance(SkipAdvanceAmount) .CreateLabel(out Label skip) + .Advance(-SkipAdvanceAmount) .Insert( new CodeInstruction(OpCodes.Ldloc_S, ReferenceHubLocalIndex), - CodeInstruction.Call(typeof(RoundEndIgnorePatch), nameof(IsPlayerIgnored)), + new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(RoundEndIgnorePatch), nameof(IsPlayerIgnored))), new CodeInstruction(OpCodes.Brtrue_S, skip)); return matcher.InstructionEnumeration(); diff --git a/SecretAPI/Patches/Features/RoundIgnoreCountPatch.cs b/SecretAPI/Patches/Features/RoundIgnoreCountPatch.cs index 0a1f32e..51b79a1 100644 --- a/SecretAPI/Patches/Features/RoundIgnoreCountPatch.cs +++ b/SecretAPI/Patches/Features/RoundIgnoreCountPatch.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Reflection.Emit; using HarmonyLib; +using LabApi.Features.Console; using LabApi.Features.Wrappers; using Mirror; using SecretAPI.Attributes; @@ -25,14 +26,8 @@ internal static class RoundIgnoreCountPatch private static MethodInfo TargetMethod() { - Type nestedType = typeof(RoundSummary).GetNestedTypes(AccessTools.all) - .FirstOrDefault(currentType => currentType.Name is StateMachine) ?? throw new Exception("Could not locate state machine for RoundSummary::<>c"); - - // nestedType.GetMethods(AccessTools.all).ForEach(method => Logger.Debug(method.Name)); - MethodInfo updateCountMethod = nestedType.GetMethods(AccessTools.all) - .FirstOrDefault(x => x.Name.Contains(UpdateTargetCount)) ?? throw new Exception($"Could not locate {UpdateTargetCount} method in state machine"); - - return updateCountMethod; + return typeof(RoundSummary).GetNestedMethod(StateMachine, UpdateTargetCount) + ?? throw new Exception($"Could not locate state machine for {StateMachine} | {UpdateTargetCount}"); } private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) @@ -41,21 +36,14 @@ private static IEnumerable Transpiler(IEnumerable Player.Get(hub).RoundIgnoreStatus.HasFlagFast(RoundIgnoreStatus.ScpTargetCount); } \ No newline at end of file