Beispiel #1
0
        /// <summary>Serializes a patch info</summary>
        /// <param name="patchInfo">The <see cref="PatchInfo"/></param>
        /// <returns>The serialized data</returns>
        ///
        internal static byte[] Serialize(this PatchInfo patchInfo)
        {
#pragma warning disable XS0001
            using var streamMemory = new MemoryStream();
            var formatter = new BinaryFormatter();
            formatter.Serialize(streamMemory, patchInfo);
            return(streamMemory.GetBuffer());

#pragma warning restore XS0001
        }
Beispiel #2
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 = method.GetPatchInfo();

            if (patchInfo is null)
            {
                return(null);
            }
            return(new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers, patchInfo.finalizers, patchInfo.ilmanipulators));
        }
        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;
        }
Beispiel #4
0
        /// <summary>Adds a finalizer</summary>
        /// <param name="patchInfo">The patch info</param>
        /// <param name="owner">The owner (Harmony ID)</param>
        /// <param name="info">The annotation info</param>
        ///
        internal static void AddFinalizer(PatchInfo patchInfo, string owner, HarmonyMethod info)
        {
            if (info == null || info.method == null)
            {
                return;
            }

            var priority = info.priority == -1 ? Priority.Normal : info.priority;
            var before   = info.before ?? new string[0];
            var after    = info.after ?? new string[0];

            patchInfo.AddFinalizer(info.method, owner, priority, before, after);
        }
Beispiel #5
0
        /// <summary>Adds a postfix</summary>
        /// <param name="patchInfo">The patch info</param>
        /// <param name="owner">The owner (Harmony ID)</param>
        /// <param name="info">The annotation info</param>
        ///
        internal static void AddPostfix(PatchInfo patchInfo, string owner, HarmonyMethod info)
        {
            if (info == null || info.method == null)
            {
                return;
            }

            var priority = info.priority == -1 ? Priority.Normal : info.priority;
            var before   = info.before ?? new string[0];
            var after    = info.after ?? new string[0];
            var debug    = info.debug ?? false;

            patchInfo.AddPostfix(info.method, owner, priority, before, after, debug);
        }
Beispiel #6
0
        /// <summary>Serializes a patch info</summary>
        /// <param name="patchInfo">The patch info</param>
        /// <returns>A byte array</returns>
        ///
        internal static byte[] Serialize(this PatchInfo patchInfo)
        {
#pragma warning disable XS0001
            using (var streamMemory = new MemoryStream())
            {
                var surrogateSelector = PatchSurrogate.GetSelector();
                var formatter         = new BinaryFormatter()
                {
                    SurrogateSelector = surrogateSelector
                };
                formatter.Serialize(streamMemory, patchInfo);
                return(streamMemory.GetBuffer());
            }
#pragma warning restore XS0001
        }
Beispiel #7
0
        /// <summary>Creates new dynamic method with the latest patches and detours the original method</summary>
        /// <param name="original">The original method</param>
        /// <param name="patchInfo">Information describing the patches</param>
        /// <param name="instanceID">Harmony ID</param>
        /// <returns>The newly created dynamic method</returns>
        ///
        internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo, string instanceID)
        {
            var sortedPrefixes    = GetSortedPatchMethods(original, patchInfo.prefixes);
            var sortedPostfixes   = GetSortedPatchMethods(original, patchInfo.postfixes);
            var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers);
            var sortedFinalizers  = GetSortedPatchMethods(original, patchInfo.finalizers);

            var replacement = MethodPatcher.CreatePatchedMethod(original, null, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers);

            if (replacement == null)
            {
                throw new MissingMethodException($"Cannot create dynamic replacement for {original.FullDescription()}");
            }

            Memory.DetourMethodAndPersist(original, replacement);
            return(replacement);
        }
Beispiel #8
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);
            }
        }
Beispiel #9
0
        /// <summary>Serializes a patch info</summary>
        /// <param name="patchInfo">The <see cref="PatchInfo"/></param>
        /// <returns>The serialized data</returns>
        ///
        internal static byte[] Serialize(this PatchInfo patchInfo)
        {
#if NET50_OR_GREATER
            if (UseBinaryFormatter)
            {
#endif
            using var streamMemory = new MemoryStream();
            binaryFormatter.Serialize(streamMemory, patchInfo);
            return(streamMemory.GetBuffer());

#if NET50_OR_GREATER
        }

        else
        {
            return(JsonSerializer.SerializeToUtf8Bytes(patchInfo));
        }
#endif
        }
Beispiel #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);
                }
            }
        }
Beispiel #11
0
        /// <summary>Creates new replacement method with the latest patches and detours the original method</summary>
        /// <param name="original">The original method</param>
        /// <param name="patchInfo">Information describing the patches</param>
        /// <returns>The newly created replacement method</returns>
        ///
        internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo)
        {
            var patcher = original.GetMethodPatcher();
            var dmd     = patcher.PrepareOriginal();

            if (dmd != null)
            {
                var ctx = new ILContext(dmd.Definition);
                HarmonyManipulator.Manipulate(original, patchInfo, ctx);
            }

            try
            {
                return(patcher.DetourTo(dmd?.Generate()) as MethodInfo);
            }
            catch (Exception ex)
            {
                throw HarmonyException.Create(ex, dmd?.Definition?.Body);
            }
        }
Beispiel #12
0
 public static void UpdatePatchInfo(MethodBase methodBase, PatchInfo patchInfo)
 {
     // skip
 }
Beispiel #13
0
        internal static void UpdateRecompiledMethod(MethodBase original, IntPtr codeStart, PatchInfo patchInfo)
        {
            try
            {
                var sortedPrefixes    = GetSortedPatchMethods(original, patchInfo.prefixes, false);
                var sortedPostfixes   = GetSortedPatchMethods(original, patchInfo.postfixes, false);
                var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers, false);
                var sortedFinalizers  = GetSortedPatchMethods(original, patchInfo.finalizers, false);

                var patcher     = new MethodPatcher(original, null, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers, false);
                var replacement = patcher.CreateReplacement(out var finalInstructions);
                if (replacement is null)
                {
                    throw new MissingMethodException($"Cannot create replacement for {original.FullDescription()}");
                }

                Memory.DetourCompiledMethod(codeStart, replacement);
            }
            catch
            {
            }
        }
Beispiel #14
0
 /// <summary>Removes a transpiler</summary>
 /// <param name="patchInfo">The patch info</param>
 /// <param name="owner">The owner (Harmony ID)</param>
 ///
 internal static void RemoveTranspiler(PatchInfo patchInfo, string owner)
 {
     patchInfo.RemoveTranspiler(owner);
 }
Beispiel #15
0
 /// <summary>Removes a postfix</summary>
 /// <param name="patchInfo">The patch info</param>
 /// <param name="owner">The owner (Harmony ID)</param>
 ///
 internal static void RemovePostfix(PatchInfo patchInfo, string owner)
 {
     patchInfo.RemovePostfix(owner);
 }
Beispiel #16
0
 /// <summary>Removes a patch method</summary>
 /// <param name="patchInfo">The patch info</param>
 /// <param name="patch">The patch method</param>
 ///
 internal static void RemovePatch(PatchInfo patchInfo, MethodInfo patch)
 {
     patchInfo.RemovePatch(patch);
 }
Beispiel #17
0
 /// <summary>Removes a finalizer</summary>
 /// <param name="patchInfo">The patch info</param>
 /// <param name="owner">The owner (Harmony ID)</param>
 ///
 internal static void RemoveFinalizer(PatchInfo patchInfo, string owner)
 {
     patchInfo.RemoveFinalizer(owner);
 }
 internal static void UpdatePatchInfo(MethodBase method, PatchInfo patchInfo)
 {
     GetState()[method] = patchInfo.Serialize();
 }
Beispiel #19
0
        internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement, PatchInfo patchInfo)
        {
            var bytes = patchInfo.Serialize();
            var info  = GetState();

            lock (info.state) info.state[original] = bytes;
            lock (info.originals) info.originals[replacement] = original;
        }
Beispiel #20
0
 public static DynamicMethod UpdateWrapper(MethodBase original, PatchInfo info, string id)
 {
     original.GetMethodPatcher().Apply();
     return(null);
 }
Beispiel #21
0
        internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement, PatchInfo patchInfo)
        {
            var bytes = patchInfo.Serialize();

            _ = WithState <object>(() =>
            {
                state[original]        = bytes;
                originals[replacement] = original;
                return(null);
            });
        }