Ejemplo n.º 1
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);

                    bool IsMethodComplete(HarmonyMethod m)
                    {
                        return(m.declaringType != null &&
                               (m.methodName != null || m.methodType == MethodType.Constructor || m.methodType == MethodType.StaticConstructor));
                    }

                    var completeMethods = patchAttributeMethods.Where(IsMethodComplete).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");
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        void PrepareType()
        {
            var mainPrepareResult = RunMethod <HarmonyPrepare, bool>(true);

            if (mainPrepareResult == false)
            {
                return;
            }

            var originalMethodType = containerAttributes.methodType;

            // MethodType default is Normal
            if (containerAttributes.methodType == null)
            {
                containerAttributes.methodType = MethodType.Normal;
            }

            var reversePatchMethods = PatchTools.GetReversePatches(container);

            foreach (var reversePatchMethod in reversePatchMethods)
            {
                var originalMethod = GetReverseOriginal(reversePatchMethod);
                var reversePatcher = instance.CreateReversePatcher(originalMethod, reversePatchMethod);
                reversePatcher.Patch();
            }

            var customOriginals = RunMethod <HarmonyTargetMethods, IEnumerable <MethodBase> >(null);

            if (customOriginals != null)
            {
                originals.Clear();
                originals.AddRange(customOriginals);
            }
            else
            {
                var isPatchAll = container.GetCustomAttributes(true).Any(a => a.GetType().FullName == typeof(HarmonyPatchAll).FullName);
                if (isPatchAll)
                {
                    var type = containerAttributes.declaringType;
                    originals.AddRange(AccessTools.GetDeclaredConstructors(type).Cast <MethodBase>());
                    originals.AddRange(AccessTools.GetDeclaredMethods(type).Cast <MethodBase>());
                    var props = AccessTools.GetDeclaredProperties(type);
                    originals.AddRange(props.Select(prop => prop.GetGetMethod(true)).Where(method => method != null).Cast <MethodBase>());
                    originals.AddRange(props.Select(prop => prop.GetSetMethod(true)).Where(method => method != null).Cast <MethodBase>());
                }
                else
                {
                    var original = RunMethod <HarmonyTargetMethod, MethodBase>(null);

                    if (original == null)
                    {
                        original = GetOriginalMethod();
                    }

                    if (original == null)
                    {
                        var info = "(";
                        info += "declaringType=" + containerAttributes.declaringType + ", ";
                        info += "methodName =" + containerAttributes.methodName + ", ";
                        info += "methodType=" + originalMethodType + ", ";
                        info += "argumentTypes=" + containerAttributes.argumentTypes.Description();
                        info += ")";
                        throw new ArgumentException("No target method specified for class " + container.FullName + " " + info);
                    }

                    originals.Add(original);
                }
            }

            PatchTools.GetPatches(container, out var prefixMethod, out var postfixMethod, out var transpilerMethod, out var finalizerMethod);
            if (prefix != null)
            {
                prefix.method = prefixMethod;
            }
            if (postfix != null)
            {
                postfix.method = postfixMethod;
            }
            if (transpiler != null)
            {
                transpiler.method = transpilerMethod;
            }
            if (finalizer != null)
            {
                finalizer.method = finalizerMethod;
            }

            if (prefixMethod != null)
            {
                if (prefixMethod.IsStatic == false)
                {
                    throw new ArgumentException("Patch method " + prefixMethod.FullDescription() + " must be static");
                }

                var prefixAttributes = HarmonyMethodExtensions.GetFromMethod(prefixMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(prefixAttributes)).CopyTo(prefix);
            }

            if (postfixMethod != null)
            {
                if (postfixMethod.IsStatic == false)
                {
                    throw new ArgumentException("Patch method " + postfixMethod.FullDescription() + " must be static");
                }

                var postfixAttributes = HarmonyMethodExtensions.GetFromMethod(postfixMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(postfixAttributes)).CopyTo(postfix);
            }

            if (transpilerMethod != null)
            {
                if (transpilerMethod.IsStatic == false)
                {
                    throw new ArgumentException("Patch method " + transpilerMethod.FullDescription() + " must be static");
                }

                var transpilerAttributes = HarmonyMethodExtensions.GetFromMethod(transpilerMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(transpilerAttributes)).CopyTo(transpiler);
            }

            if (finalizerMethod != null)
            {
                if (finalizerMethod.IsStatic == false)
                {
                    throw new ArgumentException("Patch method " + finalizerMethod.FullDescription() + " must be static");
                }

                var finalizerAttributes = HarmonyMethodExtensions.GetFromMethod(finalizerMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(finalizerAttributes)).CopyTo(finalizer);
            }
        }