Example #1
0
        /// <summary>Gets Harmony version for all active Harmony instances</summary>
        /// <param name="currentVersion">[out] The current Harmony version</param>
        /// <returns>A dictionary containing assembly version keyed by Harmony ID</returns>
        ///
        public static Dictionary <string, Version> VersionInfo(out Version currentVersion)
        {
            currentVersion = typeof(Harmony).Assembly.GetName().Version;
            var assemblies = new Dictionary <string, Assembly>();

            GetAllPatchedMethods().Do(method =>
            {
                PatchInfo info;
                lock (locker) { info = HarmonySharedState.GetPatchInfo(method); }
                info.prefixes.Do(fix => assemblies[fix.owner]    = fix.PatchMethod.DeclaringType.Assembly);
                info.postfixes.Do(fix => assemblies[fix.owner]   = fix.PatchMethod.DeclaringType.Assembly);
                info.transpilers.Do(fix => assemblies[fix.owner] = fix.PatchMethod.DeclaringType.Assembly);
                info.finalizers.Do(fix => assemblies[fix.owner]  = fix.PatchMethod.DeclaringType.Assembly);
            });

            var result = new Dictionary <string, Version>();

            assemblies.Do(info =>
            {
                var assemblyName = info.Value.GetReferencedAssemblies().FirstOrDefault(a => a.FullName.StartsWith("0Harmony, Version", StringComparison.Ordinal));
                if (assemblyName != null)
                {
                    result[info.Key] = assemblyName.Version;
                }
            });
            return(result);
        }
Example #2
0
        /// <summary>Applies all registered patches</summary>
        /// <returns>The generated replacement method</returns>
        ///
        public MethodInfo Patch()
        {
            if (original == null)
            {
                throw new NullReferenceException($"Null method for {instance.Id}");
            }

            if (original.IsDeclaredMember() == false)
            {
                var declaredMember = original.GetDeclaredMember();
                throw new ArgumentException($"You can only patch implemented methods/constructors. Path the declared method {declaredMember.FullDescription()} instead.");
            }

            lock (locker)
            {
                var patchInfo = HarmonySharedState.GetPatchInfo(original);
                if (patchInfo == null)
                {
                    patchInfo = new PatchInfo();
                }

                PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
                PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
                PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler);
                PatchFunctions.AddFinalizer(patchInfo, instance.Id, finalizer);
                var replacement = PatchFunctions.UpdateWrapper(original, patchInfo);

                HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                return(replacement);
            }
        }
Example #3
0
        /// <summary>Unpatches patches of a given type and/or Harmony ID</summary>
        /// <param name="type">The <see cref="HarmonyPatchType"/> patch type</param>
        /// <param name="harmonyID">Harmony ID or <c>*</c> for any</param>
        /// <returns>A <see cref="PatchProcessor"/> for chaining calls</returns>
        ///
        public PatchProcessor Unpatch(HarmonyPatchType type, string harmonyID)
        {
            lock (locker)
            {
                var patchInfo = HarmonySharedState.GetPatchInfo(original);
                if (patchInfo == null)
                {
                    patchInfo = new PatchInfo();
                }

                if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix)
                {
                    PatchFunctions.RemovePrefix(patchInfo, harmonyID);
                }
                if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix)
                {
                    PatchFunctions.RemovePostfix(patchInfo, harmonyID);
                }
                if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler)
                {
                    PatchFunctions.RemoveTranspiler(patchInfo, harmonyID);
                }
                if (type == HarmonyPatchType.All || type == HarmonyPatchType.Finalizer)
                {
                    PatchFunctions.RemoveFinalizer(patchInfo, harmonyID);
                }
                _ = PatchFunctions.UpdateWrapper(original, patchInfo);

                HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                return(this);
            }
        }
Example #4
0
        void ProcessPatchJob(PatchJobs <MethodInfo> .Job job)
        {
            MethodInfo replacement = default;

            var       individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, false, null, job.original);
            Exception exception = null;

            if (individualPrepareResult)
            {
                lock (PatchProcessor.locker)
                {
                    try
                    {
                        var patchInfo = HarmonySharedState.GetPatchInfo(job.original) ?? new PatchInfo();

                        patchInfo.AddPrefixes(instance.Id, job.prefixes.ToArray());
                        patchInfo.AddPostfixes(instance.Id, job.postfixes.ToArray());
                        patchInfo.AddTranspilers(instance.Id, job.transpilers.ToArray());
                        patchInfo.AddFinalizers(instance.Id, job.finalizers.ToArray());

                        replacement = PatchFunctions.UpdateWrapper(job.original, patchInfo);
                        HarmonySharedState.UpdatePatchInfo(job.original, replacement, patchInfo);
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }
                }
            }
            RunMethod <HarmonyCleanup>(ref exception, job.original, exception);
            ReportException(exception, job.original);
            job.replacement = replacement;
        }
Example #5
0
        /// <summary>Applies the patch</summary>
        /// <returns>A list of all created dynamic methods</returns>
        ///
        public List <DynamicMethod> Patch()
        {
            lock (locker)
            {
                var dynamicMethods = new List <DynamicMethod>();
                foreach (var original in originals)
                {
                    if (original == null)
                    {
                        throw new NullReferenceException("Null method for " + instance.Id);
                    }

                    var individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, original);
                    if (individualPrepareResult)
                    {
                        var patchInfo = HarmonySharedState.GetPatchInfo(original);
                        if (patchInfo == null)
                        {
                            patchInfo = new PatchInfo();
                        }

                        PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
                        PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
                        PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler);
                        PatchFunctions.AddFinalizer(patchInfo, instance.Id, finalizer);
                        dynamicMethods.Add(PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id));

                        HarmonySharedState.UpdatePatchInfo(original, patchInfo);

                        RunMethod <HarmonyCleanup>(original);
                    }
                }
                return(dynamicMethods);
            }
        }
Example #6
0
        /// <summary>Unpatches patches of a given type and/or Harmony ID</summary>
        /// <param name="type">The patch type</param>
        /// <param name="harmonyID">Harmony ID or (*) for any</param>
        ///
        public void Unpatch(HarmonyPatchType type, string harmonyID)
        {
            lock (locker)
            {
                foreach (var original in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(original);
                    if (patchInfo == null)
                    {
                        patchInfo = new PatchInfo();
                    }

                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix)
                    {
                        PatchFunctions.RemovePrefix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix)
                    {
                        PatchFunctions.RemovePostfix(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler)
                    {
                        PatchFunctions.RemoveTranspiler(patchInfo, harmonyID);
                    }
                    if (type == HarmonyPatchType.All || type == HarmonyPatchType.Finalizer)
                    {
                        PatchFunctions.RemoveFinalizer(patchInfo, harmonyID);
                    }
                    PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id);

                    HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                }
            }
        }
Example #7
0
        /// <summary>Gets patch information on an original</summary>
        /// <param name="method">The original method/constructor</param>
        /// <returns>The patch information as <see cref="Patches"/></returns>
        ///
        public static Patches GetPatchInfo(MethodBase method)
        {
            PatchInfo patchInfo;

            lock (locker) { patchInfo = HarmonySharedState.GetPatchInfo(method); }
            if (patchInfo == null)
            {
                return(null);
            }
            return(new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers, patchInfo.finalizers));
        }
Example #8
0
        void ProcessPatchJob(PatchJobs <MethodInfo> .Job job)
        {
            MethodInfo replacement = default;

            var       individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, false, null, job.original);
            Exception exception = null;

            if (individualPrepareResult)
            {
                lock (PatchProcessor.locker)
                {
                    try
                    {
                        var patchInfo = HarmonySharedState.GetPatchInfo(job.original);
                        if (patchInfo == null)
                        {
                            patchInfo = new PatchInfo();
                        }

                        foreach (var prefix in job.prefixes)
                        {
                            PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix);
                        }
                        foreach (var postfix in job.postfixes)
                        {
                            PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix);
                        }
                        foreach (var transpiler in job.transpilers)
                        {
                            PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler);
                        }
                        foreach (var finalizer in job.finalizers)
                        {
                            PatchFunctions.AddFinalizer(patchInfo, instance.Id, finalizer);
                        }

                        replacement = PatchFunctions.UpdateWrapper(job.original, patchInfo);
                        HarmonySharedState.UpdatePatchInfo(job.original, patchInfo);
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }
                }
            }
            RunMethod <HarmonyCleanup>(ref exception, job.original, exception);
            if (exception != null)
            {
                ReportException(exception, job.original);
            }
            job.replacement = replacement;
        }
Example #9
0
        /// <summary>Unpatches a specific patch</summary>
        /// <param name="patch">The method of the patch</param>
        /// <returns>A <see cref="PatchProcessor"/> for chaining calls</returns>
        ///
        public PatchProcessor Unpatch(MethodInfo patch)
        {
            lock (locker)
            {
                var patchInfo = HarmonySharedState.GetPatchInfo(original);
                if (patchInfo == null)
                {
                    patchInfo = new PatchInfo();
                }

                PatchFunctions.RemovePatch(patchInfo, patch);
                _ = PatchFunctions.UpdateWrapper(original, patchInfo);

                HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                return(this);
            }
        }
Example #10
0
        /// <summary>Unpatches the given patch</summary>
        /// <param name="patch">The patch</param>
        ///
        public void Unpatch(MethodInfo patch)
        {
            lock (locker)
            {
                foreach (var original in originals)
                {
                    var patchInfo = HarmonySharedState.GetPatchInfo(original);
                    if (patchInfo == null)
                    {
                        patchInfo = new PatchInfo();
                    }

                    PatchFunctions.RemovePatch(patchInfo, patch);
                    PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id);

                    HarmonySharedState.UpdatePatchInfo(original, patchInfo);
                }
            }
        }