예제 #1
0
        /// <summary>Creates patches by manually specifying the methods</summary>
        /// <param name="original">The original method</param>
        /// <param name="prefix">An optional prefix method wrapped in a HarmonyMethod object</param>
        /// <param name="postfix">An optional postfix method wrapped in a HarmonyMethod object</param>
        /// <param name="transpiler">An optional transpiler method wrapped in a HarmonyMethod object</param>
        /// <param name="finalizer">An optional finalizer method wrapped in a HarmonyMethod object</param>
        /// <returns>The dynamic method that was created to patch the original method</returns>
        ///
        public DynamicMethod Patch(MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null)
        {
            var processor = new PatchProcessor(this, original);

            processor.AddPrefix(prefix);
            processor.AddPostfix(postfix);
            processor.AddTranspiler(transpiler);
            processor.AddFinalizer(finalizer);
            return(processor.Patch().FirstOrDefault());
        }
예제 #2
0
        /// <summary>Creates patches by manually specifying the methods</summary>
        /// <param name="original">The original method</param>
        /// <param name="prefix">An optional prefix method wrapped in a HarmonyMethod object</param>
        /// <param name="postfix">An optional postfix method wrapped in a HarmonyMethod object</param>
        /// <param name="transpiler">An optional transpiler method wrapped in a HarmonyMethod object</param>
        /// <param name="finalizer">An optional finalizer method wrapped in a HarmonyMethod object</param>
        /// <returns>The dynamic method that was created to patch the original method</returns>
        ///
        public DynamicMethod Patch(MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null,
                                   HarmonyMethod transpiler = null, HarmonyMethod finalizer = null)
        {
            // TODO: Figure out allow MethodInfo return type (maybe shimming?)
            var processor = new PatchProcessor(this, original);

            processor.AddPrefix(prefix);
            processor.AddPostfix(postfix);
            processor.AddTranspiler(transpiler);
            processor.AddFinalizer(finalizer);
            return(processor.Patch().FirstOrDefault());
        }
예제 #3
0
        /// <summary>
        /// Applies all patches specified in the type.
        /// </summary>
        /// <param name="type">The type to scan.</param>
        public void PatchAll(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
            {
                var patchAttributeMethods = HarmonyMethodExtensions.GetFromMethod(method);
                if (patchAttributeMethods != null && patchAttributeMethods.Any())
                {
                    var attributes = method.GetCustomAttributes(true);

                    var combinedInfo = HarmonyMethod.Merge(patchAttributeMethods);

                    var completeMethods = patchAttributeMethods.Where(x => x.declaringType != null && x.methodName != null).ToList();

                    if (patchAttributeMethods.All(x => x.declaringType != combinedInfo.declaringType && x.methodName != combinedInfo.methodName))
                    {
                        completeMethods.Add(combinedInfo);
                    }

                    var originalMethods = new List <MethodBase>();

                    foreach (var methodToPatch in completeMethods)
                    {
                        foreach (var index in attributes.OfType <ParameterByRefAttribute>().SelectMany(x => x.ParameterIndices))
                        {
                            if (!methodToPatch.argumentTypes[index].IsByRef)
                            {
                                methodToPatch.argumentTypes[index] = methodToPatch.argumentTypes[index].MakeByRefType();
                            }
                        }

                        if (!methodToPatch.methodType.HasValue)
                        {
                            methodToPatch.methodType = MethodType.Normal;
                        }

                        if (methodToPatch.method == null)
                        {
                            methodToPatch.method = method;
                        }

                        var originalMethod = PatchProcessor.GetOriginalMethod(methodToPatch);

                        if (originalMethod != null)
                        {
                            originalMethods.Add(originalMethod);
                        }
                    }

                    var processor = new PatchProcessor(this);

                    foreach (var originalMethod in originalMethods)
                    {
                        processor.AddOriginal(originalMethod);
                    }

                    if (attributes.Any(x => x is HarmonyPrefix))
                    {
                        processor.AddPrefix(new HarmonyMethod(method));
                    }

                    if (attributes.Any(x => x is HarmonyTranspiler))
                    {
                        processor.AddTranspiler(new HarmonyMethod(method));
                    }

                    if (attributes.Any(x => x is HarmonyPostfix))
                    {
                        processor.AddPostfix(new HarmonyMethod(method));
                    }

                    if (attributes.Any(x => x is HarmonyFinalizer))
                    {
                        processor.AddFinalizer(new HarmonyMethod(method));
                    }

                    processor.Patch();
                }
                else
                {
                    // Only check when logging warnings
                    if ((Logger.ChannelFilter & Logger.LogChannel.Warn) != 0)
                    {
                        if (method.GetCustomAttributes(typeof(HarmonyAttribute), true).Any())
                        {
                            Logger.LogText(Logger.LogChannel.Warn, "Method " + method.FullDescription() + " has an invalid combination of Harmony attributes and will be ignored");
                        }
                    }
                }
            }
        }