示例#1
0
        public static void ExecuteWorker(int[] LocalCalls, double[] LocalTimes, int currentLogCount)
        {
            try
            {
                // todo
                // implement a custom sorting which also keeps track of the sum.
                // this will take this from
                // o(2*nlogn + n) to o(2*nlogn)

                var stats = GatherStats(LocalCalls, LocalTimes, currentLogCount);

                lock (CurrentLogStats.sync) // Dump our current statistics into our static class which our drawing class uses
                {
                    CurrentLogStats.stats = stats;
                }
            }
            catch (Exception e)
            {
#if DEBUG
                ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed while calculating stats for profiler");
#else
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed while calculating stats for profiler");
                }
#endif
            }
        }
        public static void ProfilePatch()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            var filteredTranspilers = patches
                                      .Where(m => Harmony.GetPatchInfo(m).Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner) && !TranspilerMethodUtility.PatchedMeths.Contains(m)))
                                      .ToList();

            TranspilerMethodUtility.PatchedMeths.AddRange(filteredTranspilers);

            foreach (var meth in filteredTranspilers)
            {
                try
                {
                    Modbase.Harmony.Patch(meth, transpiler: TranspilerMethodUtility.TranspilerProfiler);
                }
                catch (Exception e)
                {
#if DEBUG
                    ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}");
#endif
#if NDEBUG
                    if (Settings.verboseLogging)
                    {
                        ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}");
                    }
#endif
                }
            }
        }
 public static void ProfilePatch()
 {
     try
     {
         MethodTransplanting.PatchMethods(typeof(H_HarmonyPatches));
     }
     catch (Exception e)
     {
         ThreadSafeLogger.ReportException(e, "Failed to patch HarmonyPatches");
     }
 }
示例#4
0
        public static void ExecutePatch(CurrentInput mode, string strinput, Category cat)
        {
            try
            {
                var entry = cat == Category.Tick ? typeof(CustomProfilersTick) : typeof(CustomProfilersUpdate);
                List <MethodInfo> methods = null;

                var temp = mode switch
                {
                    CurrentInput.Method => Utility.GetMethods(strinput),
                    CurrentInput.Type => Utility.GetTypeMethods(AccessTools.TypeByName(strinput)),
                    CurrentInput.MethodHarmony => Utility.GetMethodsPatching(strinput),
                    CurrentInput.SubClasses => Utility.SubClassImplementationsOf(AccessTools.TypeByName(strinput), m => true),
                    CurrentInput.TypeHarmony => Utility.GetMethodsPatchingType(AccessTools.TypeByName(strinput)),
                    _ => null,
                };

                if (temp is null)
                {
                    if (mode == CurrentInput.InternalMethod)
                    {
                        Utility.PatchInternalMethod(strinput, cat);
                    }
                    else
                    {
                        Utility.PatchAssembly(strinput, cat);
                    }

                    return;
                }

                methods = temp.ToList();

                if (methods.Count == 0)
                {
                    Messages.Message($"Failed to find the method(s) represented by {strinput}", MessageTypeDefOf.CautionInput, false);
                    return;
                }

                Messages.Message(methods.Count != 1 ? $"Patching {methods.Count} methods in the category {cat}" : $"Patching {Utility.GetSignature(methods[0])} in the category {cat}", MessageTypeDefOf.CautionInput, false);

                MethodTransplanting.UpdateMethods(entry, methods.ToList());
                GUIController.Tab(cat).collapsed = false;

                var entryName = (cat == Category.Tick) ? "Custom Tick" : "Custom Update";
                GUIController.SwapToEntry(entryName);
            }
            catch (Exception e)
            {
                ThreadSafeLogger.ReportException(e, $"Failed to process search bar input");
            }
        }
        private static void ReportException(Exception e, string message)
        {
#if DEBUG
            ThreadSafeLogger.ReportException(e, $"[Analyzer] Patching error: {message}");
#endif
#if NDEBUG
            if (!displayMessages)
            {
                return;
            }
            ThreadSafeLogger.ReportException(e, message);
#endif
        }
        public static void ProfilePatch()
        {
            var jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(BuildableDef), typeof(StatDef), typeof(ThingDef) });
            var pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAb));
            var post = new HarmonyMethod(typeof(H_GetStatValue), nameof(Postfix));

            Modbase.Harmony.Patch(jiff, pre, post);

            jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(AbilityDef), typeof(StatDef), typeof(Pawn) });
            pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAbility));
            Modbase.Harmony.Patch(jiff, pre, post);

            jiff = AccessTools.Method(typeof(StatWorker), nameof(StatWorker.GetValue), new[] { typeof(StatRequest), typeof(bool) });
            pre  = new HarmonyMethod(typeof(H_GetStatValue), nameof(GetValueDetour));
            Modbase.Harmony.Patch(jiff, pre);

            HarmonyMethod go   = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPrefix));
            HarmonyMethod biff = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPostfix));

            foreach (Type allLeafSubclass in typeof(StatPart).AllSubclassesNonAbstract())
            {
                try
                {
                    MethodInfo mef = AccessTools.Method(allLeafSubclass, nameof(StatPart.TransformValue), new Type[] { typeof(StatRequest), typeof(float).MakeByRefType() });
                    if (mef.DeclaringType == allLeafSubclass)
                    {
                        HarmonyLib.Patches info = Harmony.GetPatchInfo(mef);
                        bool F = true;
                        if (info != null)
                        {
                            foreach (Patch infoPrefix in info.Prefixes)
                            {
                                if (infoPrefix.PatchMethod == go.method)
                                {
                                    F = false;
                                }
                            }
                        }

                        if (F)
                        {
                            Modbase.Harmony.Patch(mef, go, biff);
                        }
                    }
                }
                catch (Exception e)
                {
                    ThreadSafeLogger.ReportException(e, $"Failed to patch {allLeafSubclass} from {allLeafSubclass.Assembly.FullName} for profiling");
                }
            }
        }
        internal static void Prefix(string id)
        {
            try
            {
                if (Utility.IsNotAnalyzerPatch(id) is false)
                {
                    return;
                }

                // Can't be sure that the JIT won't inline the constructor of harmony
                // so we need to manually trawl until we find a method which doesn't belong
                // to either dpa or harmony. (this prefix, and the harmony ctor)
                var frames = new StackTrace(false).GetFrames();
                if (frames == null)
                {
                    return;
                }

                var methods = frames.Select(Harmony.GetMethodFromStackframe).Select(m => m is MethodInfo mi ? Harmony.GetOriginalMethod(mi) ?? m : m);

                // find the first non harmony/dpa method in the stack trace and assoc the asm
                // that method is from with the stack trace
                foreach (var method in methods)
                {
                    var asm = method.DeclaringType?.Assembly ?? method.ReflectedType?.Assembly;
                    if (asm == null)
                    {
                        continue;
                    }

                    if (asm.FullName.Contains("Harmony") || asm == dpaAssembly)
                    {
                        continue;
                    }

                    // we snipe this in another way
                    if (method.Name == "ApplyHarmonyPatches")
                    {
                        return;
                    }

                    StackTraceUtility.RegisterHarmonyId(id, asm);
                    return;
                }
            }
            catch (Exception e) // lets be exceedingly careful.
            {
                ThreadSafeLogger.ReportException(e, "Failed to capture Harmony ctor");
            }
        }
        public static EntryFile ReadFile(FileInfo file)
        {
            var entryFile = new EntryFile();

            try
            {
                using (var reader = new BinaryReader(file.OpenRead()))
                {
                    entryFile.header = ReadHeader(reader);
                    if (entryFile.header.MAGIC == -1)
                    {
                        return(null);
                    }

                    entryFile.times = new double[entryFile.header.entries];
                    entryFile.calls = new int[entryFile.header.entries];
                    if (entryFile.header.entryPerCall)
                    {
                        Array.Fill(entryFile.calls, 1);
                    }

                    for (int i = 0; i < entryFile.header.entries; i++)
                    {
                        entryFile.times[i] = reader.ReadDouble();
                        if (!entryFile.header.entryPerCall)
                        {
                            entryFile.calls[i] = reader.ReadInt32();
                        }
                    }

                    reader.Close();
                    reader.Dispose();
                }
            }
            catch (Exception e)
            {
                ThreadSafeLogger.ReportException(e, "Failed while reading entry file from disk.");
            }

            return(entryFile);
        }
        private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> codeInstructions)
        {
            try
            {
                var instructions = codeInstructions.ToList();

                for (int i = 0; i < instructions.Count; i++)
                {
                    if (!Utility.ValidCallInstruction(instructions[i], i == 0 ? null : instructions[i - 1], out var meth, out var key))
                    {
                        continue;
                    }

                    var index = MethodInfoCache.AddMethod(key, meth);

                    var inst = MethodTransplanting.ReplaceMethodInstruction(
                        instructions[i],
                        key,
                        GUIController.types[__originalMethod.DeclaringType + ":" + __originalMethod.Name + "-int"],
                        index);

                    instructions[i] = inst;
                }

                return(instructions);
            }
            catch (Exception e)
            {
#if DEBUG
                ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}");
#else
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}");
                }
#endif

                return(codeInstructions);
            }
        }
        public static void WriteFile(EntryFile file)
        {
            var fileName = FinalFileNameFor(file.header.methodName);

            try
            {
                using (var writer = new BinaryWriter(File.Open(fileName, FileMode.Create)))
                {
                    writer.Write(file.header.MAGIC);
                    writer.Write(file.header.scribingVer);
                    writer.Write(file.header.methodName);
                    writer.Write(file.header.name);
                    writer.Write(file.header.entryPerCall);
                    writer.Write(file.header.onlyEntriesWithValues);
                    writer.Write(file.header.entries);
                    writer.Write(file.header.targetEntries);

                    // interleaved is faster by profiling, (even if less cache-efficient)
                    for (var i = 0; i < file.header.entries; i++)
                    {
                        writer.Write(file.times[i]);
                        if (!file.header.entryPerCall)
                        {
                            writer.Write(file.calls[i]);
                        }
                    }

                    writer.Close();
                    writer.Dispose();
                }
            }
            catch (Exception e)
            {
                ThreadSafeLogger.ReportException(e, $"Caught an exception when writing file to disk, if the file exists on disk, it should be deleted at {fileName}");
            }


            changed = true;
        }
示例#11
0
        public static IEnumerable <MethodInfo> GetPatchMethods()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            foreach (var patch in patches)
            {
                HarmonyLib.Patches p = null;
                try
                {
                    p = Harmony.GetPatchInfo(patch);
                }
                catch (Exception e)
                {
                    ThreadSafeLogger.ReportException(e, $"Failed to get patch info for {Utility.GetSignature(patch)}");
                    continue;
                }

                if (patch is MethodInfo info && p.Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner)))
                {
                    yield return(info);
                }
            }
        }
        internal static void UpdateMethod(Type type, MethodInfo meth)
        {
            if (patchedMeths.Contains(meth))
            {
#if DEBUG
                ThreadSafeLogger.Warning($"[Analyzer] Already patched method {meth.DeclaringType.FullName + ":" + meth.Name}");
#else
                if (Settings.verboseLogging)
                {
                    ThreadSafeLogger.Warning($"[Analyzer] Already patched method {Utility.GetSignature(meth, false)}");
                }
#endif
                return;
            }

            patchedMeths.Add(meth);
            typeInfo.TryAdd(meth, type);

            Task.Factory.StartNew(delegate
            {
                try
                {
                    Modbase.Harmony.Patch(meth, transpiler: transpiler);
                }
                catch (Exception e)
                {
#if DEBUG
                    ThreadSafeLogger.ReportException(e, $"Failed to patch the method {Utility.GetSignature(meth, false)}");
#else
                    if (Settings.verboseLogging)
                    {
                        ThreadSafeLogger.ReportException(e, $"Failed to patch the method {Utility.GetSignature(meth, false)}");
                    }
#endif
                }
            });
        }