Exemplo n.º 1
0
        /// <summary>
        /// Get the member specified by the <paramref name="attribute"/>. Throws if the member was not found.
        /// </summary>
        /// <exception cref="ArgumentException">Thrown if the member described in the <paramref name="attribute"/> couldn't be found.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="attribute"/> is <see langword="null"/></exception>
        internal static MethodBase GetOriginalMethod(HarmonyMethod attribute)
        {
            if (attribute == null)
            {
                throw new ArgumentNullException(nameof(attribute));
            }

            string GetPatchName()
            {
                return(attribute.method?.FullDescription() ?? "Unknown patch");
            }

            MethodBase MakeFailure(string reason)
            {
                Logger.Log(Logger.LogChannel.Error, () => $"Failed to process patch {GetPatchName()} - {reason}");
                return(null);
            }

            if (attribute.declaringType == null)
            {
                return(MakeFailure("declaringType cannot be null"));
            }

            switch (attribute.methodType)
            {
            case MethodType.Normal:
            {
                if (string.IsNullOrEmpty(attribute.methodName))
                {
                    return(MakeFailure("methodName can't be empty"));
                }

                if (attribute.methodName == ".ctor")
                {
                    Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - MethodType.Constructor should be used instead of setting methodName to .ctor");
                    goto case MethodType.Constructor;
                }
                if (attribute.methodName == ".cctor")
                {
                    Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - MethodType.StaticConstructor should be used instead of setting methodName to .cctor");
                    goto case MethodType.StaticConstructor;
                }

                if (attribute.methodName.StartsWith("get_") || attribute.methodName.StartsWith("set_"))
                {
                    Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - MethodType.Getter and MethodType.Setter should be used instead adding get_ and set_ to property names");
                }

                var result = AccessTools.DeclaredMethod(attribute.declaringType, attribute.methodName, attribute.argumentTypes);
                if (result != null)
                {
                    return(result);
                }

                result = AccessTools.Method(attribute.declaringType, attribute.methodName, attribute.argumentTypes);
                if (result != null)
                {
                    Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + $" - Could not find method {attribute.methodName} with {attribute.argumentTypes?.Length ?? 0} parameters in type {attribute.declaringType.FullDescription()}, but it was found in base class of this type {result.DeclaringType.FullDescription()}");
                    return(result);
                }

                return(MakeFailure($"Could not find method {attribute.methodName} with {attribute.argumentTypes.Description()} parameters in type {attribute.declaringType.FullDescription()}"));
            }

            case MethodType.Getter:
            {
                if (string.IsNullOrEmpty(attribute.methodName))
                {
                    return(MakeFailure("methodName can't be empty"));
                }

                var result = AccessTools.DeclaredProperty(attribute.declaringType, attribute.methodName);
                if (result != null)
                {
                    var getter = result.GetGetMethod(true);
                    if (getter == null)
                    {
                        return(MakeFailure($"Property {attribute.methodName} does not have a Getter"));
                    }
                    return(getter);
                }

                result = AccessTools.Property(attribute.declaringType, attribute.methodName);
                if (result != null)
                {
                    Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + $" - Could not find property {attribute.methodName} in type {attribute.declaringType.FullDescription()}, but it was found in base class of this type: {result.DeclaringType.FullDescription()}");
                    var getter = result.GetGetMethod(true);
                    if (getter == null)
                    {
                        return(MakeFailure($"Property {attribute.methodName} does not have a Getter"));
                    }
                    return(getter);
                }

                return(MakeFailure($"Could not find property {attribute.methodName} in type {attribute.declaringType.FullDescription()}"));
            }

            case MethodType.Setter:
            {
                if (string.IsNullOrEmpty(attribute.methodName))
                {
                    return(MakeFailure("methodName can't be empty"));
                }

                var result = AccessTools.DeclaredProperty(attribute.declaringType, attribute.methodName);
                if (result != null)
                {
                    var getter = result.GetSetMethod(true);
                    if (getter == null)
                    {
                        return(MakeFailure($"Property {attribute.methodName} does not have a Setter"));
                    }
                    return(getter);
                }

                result = AccessTools.Property(attribute.declaringType, attribute.methodName);
                if (result != null)
                {
                    Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + $" - Could not find property {attribute.methodName} in type {attribute.declaringType.FullDescription()}, but it was found in base class of this type: {result.DeclaringType.FullDescription()}");
                    var getter = result.GetSetMethod(true);
                    if (getter == null)
                    {
                        return(MakeFailure($"Property {attribute.methodName} does not have a Setter"));
                    }
                    return(getter);
                }

                return(MakeFailure($"Could not find property {attribute.methodName} in type {attribute.declaringType.FullDescription()}"));
            }

            case MethodType.Constructor:
            {
                var constructor = AccessTools.DeclaredConstructor(attribute.declaringType, attribute.argumentTypes);
                if (constructor != null)
                {
                    return(constructor);
                }

                return(MakeFailure($"Could not find constructor with {attribute.argumentTypes.Description()} parameters in type {attribute.declaringType.FullDescription()}"));
            }

            case MethodType.StaticConstructor:
            {
                var constructor = AccessTools.GetDeclaredConstructors(attribute.declaringType).FirstOrDefault(c => c.IsStatic);
                if (constructor != null)
                {
                    return(constructor);
                }

                return(MakeFailure($"Could not find static constructor in type {attribute.declaringType.FullDescription()}"));
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(attribute.methodType), attribute.methodType, "Unknown method type");
            }
        }