using System; using System.Linq; using System.Reflection; using System.Text; using HarmonyLib; namespace StardewModdingAPI.Internal.Patching { /// Provides utility methods for patching game code with Harmony. internal static class PatchHelper { /********* ** Public methods *********/ /// Get a constructor and assert that it was found. /// The type containing the method. /// The method parameter types, or null if it's not overloaded. /// The type has no matching constructor. public static ConstructorInfo RequireConstructor(Type[] parameters = null) { return AccessTools.Constructor(typeof(TTarget), parameters) ?? throw new InvalidOperationException($"Can't find constructor {PatchHelper.GetMethodString(typeof(TTarget), null, parameters)} to patch."); } /// Get a method and assert that it was found. /// The type containing the method. /// The method name. /// The method parameter types, or null if it's not overloaded. /// The method generic types, or null if it's not generic. /// The type has no matching method. public static MethodInfo RequireMethod(string name, Type[] parameters = null, Type[] generics = null) { return AccessTools.Method(typeof(TTarget), name, parameters, generics) ?? throw new InvalidOperationException($"Can't find method {PatchHelper.GetMethodString(typeof(TTarget), name, parameters, generics)} to patch."); } /// Get a human-readable representation of a method target. /// The type containing the method. /// The method name, or null for a constructor. /// The method parameter types, or null if it's not overloaded. /// The method generic types, or null if it's not generic. public static string GetMethodString(Type type, string name, Type[] parameters = null, Type[] generics = null) { StringBuilder str = new StringBuilder(); // type str.Append(type.FullName); // method name (if not constructor) if (name != null) { str.Append('.'); str.Append(name); } // generics if (generics?.Any() == true) { str.Append('<'); str.Append(string.Join(", ", generics.Select(p => p.FullName))); str.Append('>'); } // parameters if (parameters?.Any() == true) { str.Append('('); str.Append(string.Join(", ", parameters.Select(p => p.FullName))); str.Append(')'); } return str.ToString(); } } }