Иконка ресурса

FREE AAAMethodTimer : 1.0.1 1.0.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*▄▄▄    ███▄ ▄███▓  ▄████  ▄▄▄██▀▀▀▓█████▄▄▄█████▓
▓█████▄ ▓██▒▀█▀ ██▒ ██▒ ▀█▒   ▒██   ▓█   ▀▓  ██▒ ▓▒
▒██▒ ▄██▓██    ▓██░▒██░▄▄▄░   ░██   ▒███  ▒ ▓██░ ▒░
▒██░█▀  ▒██    ▒██ ░▓█  ██▓▓██▄██▓  ▒▓█  ▄░ ▓██▓ ░ 
░▓█  ▀█▓▒██▒   ░██▒░▒▓███▀▒ ▓███▒   ░▒████▒ ▒██▒ ░ 
░▒▓███▀▒░ ▒░   ░  ░ ░▒   ▒  ▒▓▒▒░   ░░ ▒░ ░ ▒ ░░   
▒░▒   ░ ░  ░      ░  ░   ░  ▒ ░▒░    ░ ░  ░   ░    
 ░    ░ ░      ░   ░ ░   ░  ░ ░ ░      ░    ░      
 ░             ░         ░  ░   ░      ░  */
using HarmonyLib;
using System;
using Oxide.Core.Plugins;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using System.Text;
namespace Oxide.Plugins {
    [Info("AAAMethodTimer", "bmgjet", "1.0.1")]
    class AAAMethodTimer : RustPlugin {
        public Harmony harmony;
        public Coroutine coroutine = null;
        public static AAAMethodTimer plugin;
        private IDictionary<string, AssemblyData> Patched = new Dictionary<string, AssemblyData>();
        public Stopwatch HookTimer = new Stopwatch();
        public bool TimerRunning = false;
        private bool ServerStarting = false;
        List<string> Blacklist;
        string[] BlacklistMethods = new string[] {
            "directcallhook", "movenext", "tostring", "memberwiseclone", "gettype", "gethashcode", "finalize", "equals", "isinvoking", "stopallcoroutines", "stopcoroutine", "startcoroutine", "adduniversalcommand", "addcovalencecommand", "raiseerror", "trackstart", "trackend", "<>m__finally1", "<>m__finally2", "system.idisposable.dispose", "system.collections.generic.ienumerator<system.object>.get_current", "system.collections.ienumerator.reset", "system.collections.ienumerator.get_current", "getcomponentsinchildren", "getcomponentsinparent", "printtoconsole", "printtochat", "sendreply", "getcomponentinchildren", "getcomponentinparent", "getcomponents", "sendmessageupwards", "sendmessage", "broadcastmessage", "get_name", "get_typeid"
        }
        ;
        public class AssemblyData {
            public IDictionary<MethodInfo, MethodLog> MethodRunTime = new Dictionary<MethodInfo, MethodLog>();
            public IDictionary<MethodBase, MethodInfo> Patches = new Dictionary<MethodBase, MethodInfo>();
        }
        public class DataRecord {
            public Stopwatch stopwatch = new Stopwatch();
            public long memory = 0;
            public DataRecord Init() {
                stopwatch.Start();
                return this;
            }
        }
        public class MethodLog {
            public TimeSpan TotalHookTime = new TimeSpan();
            public int HookCount = 0;
            public long MemoryAllocations = 0;
            public MethodLog(TimeSpan totalHookTime, int hookCount, long MemUse) {
                TotalHookTime = totalHookTime;
                HookCount = hookCount;
                MemoryAllocations = MemUse;
            }
        }
#region Oxide Hooks
        private void Init() {
            plugin = this;
            harmony = new Harmony(Name + "_Patch");
            //Create Black list from system files
            DirectoryInfo d = new DirectoryInfo(Path.Combine("RustDedicated_Data", "Managed"));
            FileInfo[] files = d.GetFiles("*.dll");
            Blacklist = files.Select(x => x.Name.Replace(".dll", "")).ToList();
            for (int i = Blacklist.Count - 1; i > 0; i--) {
                if (Blacklist[i].StartsWith("Oxide.Ext.")) {
                    Blacklist.Remove(Blacklist[i]);
                }
            }
            //Allow Extensions
            Ready();
            //check if ready
        }
        void OnPluginUnloaded(Plugin plugin) {
            if (plugin.Name == Name) {
                return;
            }
            for (int i = Patched.Count - 1; i >= 0; i--) {
                bool found = false;
                foreach (var p in Patched.ElementAt(i).Value.Patches) {
                    if (p.Key.DeclaringType.Name.Contains(plugin.Name) && Patched.ElementAt(i).Value.Patches.Count > 0) {
                        found = true;
                        break;
                    }
                }
                if (found) {
                    Puts("Unpatching Plugin " + plugin.Name);
                    foreach (var p in Patched.ElementAt(i).Value.Patches) {
                        harmony.Unpatch(p.Key, p.Value);
                    }
                    Patched.ElementAt(i).Value.Patches.Clear();
                    Patched.ElementAt(i).Value.MethodRunTime.Clear();
                }
            }
        }
        private void Unload() {
            //Save data
            SaveInfo();
            SavePluginInfo();
            //unload
            if (plugin != null) {
                plugin = null;
            }
            if (coroutine != null) {
                ServerMgr.Instance.StopCoroutine(coroutine);
            }
            coroutine = ServerMgr.Instance.StartCoroutine(Startup(false));
        }
#endregion
#region Startup Loop
        private void Ready() {
            if (ServerMgr.Instance == null)  //Server No start enough for a coroutine
            {
                ServerStarting = true;
                timer.Once(1, () => {
                    Ready();
                }
                );
                //Check if ready again 1 sec
                return;
            }
            //Patch Oxide Hook Caller
            Puts("Patching All Plugin Methods, Server May Freeze For A While!!!");
            if (ServerStarting) {
                ScanForNewAssemblys();
            }
            //Server first start so thread lock doesnt matter to players
            coroutine = ServerMgr.Instance.StartCoroutine(Startup(true));
            //Start checker
        }
        private IEnumerator Startup(bool Starting) {
            if (Starting)  //Starting
            {
                yield return CoroutineEx.waitForSeconds(10);
                //Wait for code to load
                int methodChecks = 0;
                while (true) {
                    //Check again for new plugins every 5sec
                    yield return CoroutineEx.waitForSeconds(5);
                    yield return ScanForNewAssemblys(methodChecks);
                }
            }
            else {
                //Unload patches
                if (harmony != null) {
                    Puts("UnPatching " + Patched.Count + " Assemblies Might Take A While And Freeze/Kick Players");
                    int patchChecks = 0;
                    foreach (var patch in Patched) {
                        foreach (var p in patch.Value.Patches) {
                            if (patchChecks++ > 50) {
                                yield return CoroutineEx.waitForSeconds(0.01f);
                                //Attempt to prevent freeze
                                patchChecks = 0;
                            }
                            harmony.Unpatch(p.Key, p.Value);
                        }
                    }
                }
            }
        }
#endregion
#region CUI
        [ConsoleCommand("exportmethodinfo")]
        private void exportmethodinfo(ConsoleSystem.Arg arg) {
            if (arg.Player() != null) {
                if (arg.Player().IsAdmin) {
                    SaveInfo(arg.Player());
                    CuiHelper.DestroyUi(arg.Player(), "MTUI");
                }
            }
        }
        [ConsoleCommand("exportplugininfo")]
        private void exportplugininfo(ConsoleSystem.Arg arg) {
            if (arg.Player() != null) {
                if (arg.Player().IsAdmin) {
                    SavePluginInfo(arg.Player());
                    CuiHelper.DestroyUi(arg.Player(), "MTUI");
                }
            }
        }
        [ConsoleCommand("clearmethodinfo")]
        private void clearmethodinfo(ConsoleSystem.Arg arg) {
            if (arg.Player() != null) {
                if (arg.Player().IsAdmin) {
                    foreach (var p in Patched.Values) {
                        p.MethodRunTime.Clear();
                    }
                    arg.Player().ChatMessage("Cleared Logging Info");
                    CuiHelper.DestroyUi(arg.Player(), "MTUI");
                }
            }
        }
        [ChatCommand("plugininfo")]
        private void ShowPluginInfo(BasePlayer player) {
            Plugin[] plugins = this.plugins.GetAll().Where((Plugin p) => p.Filename != null).ToArray();
            int loops = plugins.Length;
            int offset = (loops - (int)(loops * 0.25f)) - 25;
            var container = new CuiElementContainer();
            container.Add(new CuiPanel {
                CursorEnabled = true, Image = {
                    Color = ".1.1.1 1.0"
                }
                , RectTransform = {
                    AnchorMin = "0 0", AnchorMax = "1 1"
                }
            }
            , "Overlay", "MTUI", "MTUI");
            container.Add(new CuiElement {
                Name = "SB", Parent = "MTUI", Components = {
                    new CuiScrollViewComponent {
                        MovementType = UnityEngine.UI.ScrollRect.MovementType.Elastic, Vertical = true, Inertia = true, Horizontal = false, Elasticity = 0.25f, DecelerationRate = 0.3f, ScrollSensitivity = 24f, ContentTransform = new CuiRectTransform {
                            AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = "0 " + ((25 * (loops + 2)) * -1), OffsetMax = "0 0"
                        }
                        , VerticalScrollbar = new CuiScrollbar() {
                            Size = 20f, AutoHide = false
                        }
                        ,
                    }
                    , new CuiRawImageComponent {
                        Sprite = "assets/content/effects/crossbreed/fx gradient skewed.png", Color = ".05.05.05.5"
                    }
                }
            }
            );
            container.Add(new CuiElement {
                Name = "Title", Parent = "MTUI", Components = {
                    new CuiRawImageComponent {
                        Sprite = "assets/content/ui/ui.background.transparent.radial.psd", Color = ".25.25.25 1",
                    }
                    , new CuiRectTransformComponent {
                        AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = "0 -50", OffsetMax = "-18 0"
                    }
                    ,
                }
            }
            );
            container.Add(new CuiElement {
                Name = "TT", Parent = "MTUI", Components = {
                    new CuiTextComponent {
                        Text = PadBoth("Plugin Name", 44) + PadBoth("Plugin File Name", 35) + PadBoth("Mem [kb]", 20) + PadBoth("Total [ms]", 20) + PadBoth("Version", 10), Font = "droidsansmono.ttf", FontSize = 14, Align = TextAnchor.MiddleCenter
                    }
                    , new CuiOutlineComponent {
                        Color = "0 0 0 1", Distance = "1 1"
                    }
                    , new CuiRectTransformComponent {
                        AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = "0 -50", OffsetMax = "-18 0"
                    }
                    ,
                }
            }
            );
            foreach (var data in plugins) {
                offset -= 25;
                string name = offset.ToString();
                container.Add(new CuiElement {
                    Name = name, Parent = "SB", Components = {
                        new CuiRawImageComponent {
                            Sprite = "assets/content/ui/ui.background.transparent.radial.psd", Color = ".2.2.2 1",
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = ".03.97", AnchorMax = ".97.97", OffsetMin = "0 " + (offset - 24).ToString(), OffsetMax = "0 " + name
                        }
                        ,
                    }
                }
                );
                container.Add(new CuiElement {
                    Name = "_" + name, Parent = name, Components = {
                        new CuiTextComponent {
                            Text = PadBoth(data.Name, 40).PadLeft(0) + PadBoth(data.Filename.Basename(), 50)+ PadBoth((data.TotalHookMemory / 1024L).ToString(), 20) + PadBoth((data.TotalHookTime).ToString("0.0000"), 20) + PadBoth(data.Version.ToString(), 10), Font = "droidsansmono.ttf", FontSize = 12, Align = TextAnchor.MiddleCenter
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = "0 0", AnchorMax = "1 1"
                        }
                        ,
                    }
                }
                );
            }
            container.Add(new CuiButton {
                Button = {
                    Color = ".5.2.2 1", Close = "MTUI"
                }
                , Text = {
                    Text = "X", Font = "droidsansmono.ttf", FontSize = 20, Align = TextAnchor.MiddleCenter
                }
                , RectTransform = {
                    AnchorMin = ".94.93", AnchorMax = ".98 1"
                }
            }
            , "MTUI", "CloseBttn");
            container.Add(new CuiButton {
                Button = {
                    Color = ".2.3.2 1", Command = "exportplugininfo"
                }
                , Text = {
                    Text = "Export", Font = "droidsansmono.ttf", FontSize = 16, Align = TextAnchor.MiddleCenter
                }
                , RectTransform = {
                    AnchorMin = "0.93", AnchorMax = ".06 1"
                }
            }
            , "MTUI", "ExportBttn");
            CuiHelper.AddUi(player, container);
        }
        [ChatCommand("methodinfo")]
        private void ShowMethodInfo(BasePlayer player) {
            if (player.IsAdmin) {
                Dictionary<MethodInfo, MethodLog> Clean = CleanAndSort();
                int loops = Clean.Count;
                int offset = (loops - (int)(loops * 0.25f)) - 25;
                var container = new CuiElementContainer();
                container.Add(new CuiPanel {
                    CursorEnabled = true, Image = {
                        Color = ".1.1.1 1.0"
                    }
                    , RectTransform = {
                        AnchorMin = "0 0", AnchorMax = "1 1"
                    }
                }
                , "Overlay", "MTUI", "MTUI");
                container.Add(new CuiElement {
                    Name = "SB", Parent = "MTUI", Components = {
                        new CuiScrollViewComponent {
                            MovementType = UnityEngine.UI.ScrollRect.MovementType.Elastic, Vertical = true, Inertia = true, Horizontal = false, Elasticity = 0.25f, DecelerationRate = 0.3f, ScrollSensitivity = 24f, ContentTransform = new CuiRectTransform {
                                AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = "0 " + ((25 * (loops + 2)) * -1), OffsetMax = "0 0"
                            }
                            , VerticalScrollbar = new CuiScrollbar() {
                                Size = 20f, AutoHide = false
                            }
                            ,
                        }
                        , new CuiRawImageComponent {
                            Sprite = "assets/content/effects/crossbreed/fx gradient skewed.png", Color = ".05.05.05.5"
                        }
                    }
                }
                );
                container.Add(new CuiElement {
                    Name = "Title", Parent = "MTUI", Components = {
                        new CuiRawImageComponent {
                            Sprite = "assets/content/ui/ui.background.transparent.radial.psd", Color = ".25.25.25 1",
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = "0 -50", OffsetMax = "-18 0"
                        }
                        ,
                    }
                }
                );
                container.Add(new CuiElement {
                    Name = "TT", Parent = "MTUI", Components = {
                        new CuiTextComponent {
                            Text = PadBoth("Plugin Name", 35) + PadBoth("Method Name", 35) + PadBoth("AVG [ms]", 15) + PadBoth("Total [ms]", 15) + PadBoth("#Invokes", 10) + PadBoth("Memory", 10), Font = "droidsansmono.ttf", FontSize = 14, Align = TextAnchor.MiddleCenter
                        }
                        , new CuiOutlineComponent {
                            Color = "0 0 0 1", Distance = "1 1"
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = "0 -50", OffsetMax = "-18 0"
                        }
                        ,
                    }
                }
                );
                foreach (var data in Clean) {
                    offset -= 25;
                    string name = offset.ToString();
                    container.Add(new CuiElement {
                        Name = name, Parent = "SB", Components = {
                            new CuiRawImageComponent {
                                Sprite = "assets/content/ui/ui.background.transparent.radial.psd", Color = ".2.2.2 1",
                            }
                            , new CuiRectTransformComponent {
                                AnchorMin = ".03.97", AnchorMax = ".97.97", OffsetMin = "0 " + (offset - 24).ToString(), OffsetMax = "0 " + name
                            }
                            ,
                        }
                    }
                    );
                    Type Parent = data.Key.DeclaringType;
                    string ParentType = Parent?.Name;
                    while (Parent.DeclaringType != null) {
                        ParentType = Parent.DeclaringType?.Name + "/" + ParentType;
                        Parent = Parent.DeclaringType;
                    }
                    container.Add(new CuiElement {
                        Name = "_" + name, Parent = name, Components = {
                            new CuiTextComponent {
                                Text = PadBoth(ParentType, 35).PadLeft(0) + PadBoth(data.Key.Name, 45) + PadBoth((data.Value.TotalHookTime.TotalMilliseconds / (double)data.Value.HookCount).ToString("0.0000"), 20) + PadBoth(data.Value.TotalHookTime.TotalMilliseconds.ToString("0.0000"), 20) + PadBoth(data.Value.HookCount.ToString(), 10) + PadBoth(data.Value.MemoryAllocations.ToString("0"), 10), Font = "droidsansmono.ttf", FontSize = 12, Align = TextAnchor.MiddleCenter
                            }
                            , new CuiRectTransformComponent {
                                AnchorMin = "0 0", AnchorMax = "1 1"
                            }
                            ,
                        }
                    }
                    );
                }
                container.Add(new CuiButton {
                    Button = {
                        Color = ".5.2.2 1", Close = "MTUI"
                    }
                    , Text = {
                        Text = "X", Font = "droidsansmono.ttf", FontSize = 16, Align = TextAnchor.MiddleCenter
                    }
                    , RectTransform = {
                        AnchorMin = ".94.93", AnchorMax = ".98 1"
                    }
                }
                , "MTUI", "CloseBttn");
                container.Add(new CuiButton {
                    Button = {
                        Color = ".3.2.2 1", Command = "clearmethodinfo"
                    }
                    , Text = {
                        Text = "Clear", Font = "droidsansmono.ttf", FontSize = 16, Align = TextAnchor.MiddleCenter
                    }
                    , RectTransform = {
                        AnchorMin = "0.93", AnchorMax = ".06 1"
                    }
                }
                , "MTUI", "ClearBttn");
                container.Add(new CuiButton {
                    Button = {
                        Color = ".2.3.2 1", Command = "exportmethodinfo"
                    }
                    , Text = {
                        Text = "Export", Font = "droidsansmono.ttf", FontSize = 16, Align = TextAnchor.MiddleCenter
                    }
                    , RectTransform = {
                        AnchorMin = ".07.93", AnchorMax = ".13 1"
                    }
                }
                , "MTUI", "ExportBttn");
                CuiHelper.AddUi(player, container);
            }
        }
#endregion
#region Methods
        public static string RemoveSpecialCharacters(string str) {
            StringBuilder sb = new StringBuilder();
            foreach (char c in str) {
                if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_' || c == ' ' || c == '[' || c == ']' || c == '/' || c == '\\' || c == '@' || c == '(' || c == ')' || c == '{' || c == '}' || c == '#') {
                    sb.Append(c);
                }
                else {
                    sb.Append('_');
                }
            }
            string output = sb.ToString();
            return (output.StartsWith("_____________________")) ? "Obfuscated_MethodName" : output;
        }
        private string PadBoth(string source, int length) {
            source = RemoveSpecialCharacters(source);
            int spaces = length - source.Length;
            int padLeft = spaces / 2 + source.Length;
            return WithMaxLength(source.PadLeft(padLeft).PadRight(length), length);
        }
        private string WithMaxLength(string value, int maxLength) {
            return value?.Substring(0, Math.Min(value.Length, maxLength));
        }
        private Dictionary<MethodInfo, MethodLog> CleanAndSort() {
            var Clean = new Dictionary<MethodInfo, MethodLog>();
            foreach (var p in Patched.Values) {
                foreach (var methodinfo in p.MethodRunTime)  //Read Out Direct Hook Info (More Accurate)
                {
                    if (methodinfo.Key.Name.EndsWith(")")) {
                        Clean.Add(methodinfo.Key, methodinfo.Value);
                    }
                }
                foreach (var methodinfo in p.MethodRunTime)  //Add the rest but not duplcates that have a direct hook value already
                {
                    bool c = false;
                    foreach (var k in Clean.Keys) {
                        Type Parent = methodinfo.Key.DeclaringType;
                        string ParentType = Parent?.Name;
                        while (Parent.DeclaringType != null) {
                            ParentType = Parent.DeclaringType?.Name + "/" + ParentType;
                            Parent = Parent.DeclaringType;
                        }
                        if (k.Name.Contains(methodinfo.Key.Name) || ParentType.Contains(Name)) {
                            c = true;
                            break;
                        }
                    }
                    if (!c && !Clean.ContainsKey(methodinfo.Key)) {
                        if(methodinfo.Value.MemoryAllocations < 0) {
                            methodinfo.Value.MemoryAllocations = 0;
                        }
                        Clean.Add(methodinfo.Key, methodinfo.Value);
                    }
                }
            }
            return Clean.Keys.OrderBy(k => k.DeclaringType.Name).ToDictionary(k => k, k => Clean[k]);
        }
        private void SaveInfo(BasePlayer player = null) {
            int methods = 0;
            foreach (var p in Patched.Values) {
                if (p.MethodRunTime != null && p.MethodRunTime.Count > 0) {
                    string datastring = "Plugin Name,Method Name,AVG Time[ms],Total Time[ms],#Invokes,Memory Allocations" + System.Environment.NewLine;
                    foreach (var data in CleanAndSort()) {
                        Type Parent = data.Key.DeclaringType;
                        string ParentType = Parent?.Name;
                        while (Parent.DeclaringType != null) {
                            ParentType = Parent.DeclaringType?.Name + "/" + ParentType;
                            Parent = Parent.DeclaringType;
                        }
                        try {
                            datastring += ParentType + "," + data.Key.Name + "," + (data.Value.TotalHookTime.TotalMilliseconds / (double)data.Value.HookCount) + "," + data.Value.TotalHookTime.TotalMilliseconds + "," + data.Value.HookCount.ToString() + "," + data.Value.MemoryAllocations + System.Environment.NewLine;
                        }
                        catch {
                        }
                    }
                    methods += p.MethodRunTime.Count;
                    File.WriteAllText(GetBackupPath("Method", DateTime.Now), datastring);
                }
            }
            Puts("Saved Data For " + methods + " Methods");
            if (player != null) {
                player.ChatMessage("Saved Data For " + methods + " Methods");
            }
        }
        private void SavePluginInfo(BasePlayer player = null) {
            Plugin[] plugins = this.plugins.GetAll().Where((Plugin p) => p.Filename != null).ToArray();
            if (plugins != null && plugins.Length > 0) {
                string datastring = "Plugin Name,File Name,Mem [kb],Total [ms],Version" + System.Environment.NewLine;
                foreach (var data in plugins) {
                    try {
                        datastring += data.Name + "," + data.Filename.Basename() + "," + (data.TotalHookMemory / 1024L).ToString() + "," + (data.TotalHookTime).ToString("0.0000") + "," + data.Version.ToString() + System.Environment.NewLine;
                    }
                    catch {
                    }
                }
                File.WriteAllText(GetBackupPath("Plugin", DateTime.Now), datastring);
                Puts("Saved Data For " + plugins.Count() + " Plugins");
                if (player != null) {
                    player.ChatMessage("Saved Data For " + plugins.Count() + " Plugins");
                }
            }
        }
        private string GetBackupPath(string prefix, DateTime date) {
            return Path.Combine(ConVar.Server.GetServerFolder("MethodTimer"), string.Format(prefix + "_{0}_{1}_{2}_{3}_{4}.csv", new object[] {
                date.Minute, date.Hour, date.Day, date.Month, date.Year
            }
            ));
        }
        private void ScanForNewAssemblys() {
            int patched = 0;
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())  //Scan Loaded Modules
            {
                if (assembly == null) {
                    continue;
                }
                string n = assembly?.GetName()?.Name;
                if (string.IsNullOrEmpty(n) || Blacklist.Contains(n) || Patched.ContainsKey(n)) {
                    continue;
                }
                //Only Target harmony and oxide plugins/extentions
                AssemblyData assemblyData = new AssemblyData();
                foreach (Type type in assembly.GetTypes())  //get all types
                {
                    try {
                        if (type == null || string.IsNullOrEmpty(type?.Name)) {
                            continue;
                        }
                        if (type.Name != this.Name && !type.Name.StartsWith("<") && !type.Name.Contains("<>"))  //Dont patch self or it will be endless loop
                        {
                            foreach (MethodInfo mi2 in type.GetRuntimeMethods())  //get all methods
                            {
                                if (!BlacklistMethods.Contains(mi2?.Name.ToLower()))  //Make sure its not blacklisted
                                {
                                    try {
                                        //Add pre/postfix stopwatch
                                        assemblyData.Patches.Add(mi2, harmony.Patch(mi2, new HarmonyMethod(AccessTools.Method(typeof(AAAMethodTimer), "Prefix")), new HarmonyMethod(AccessTools.Method(typeof(AAAMethodTimer), "Postfix"))));
                                        patched++;
                                    }
                                    catch {
                                    }
                                }
                            }
                        }
                    }
                    catch {
                    }
                }
                Patched.Add(n, assemblyData);
                //Add to list so dont check it again.}
                if (patched != 0) {
                    Puts("Patched " + patched + " Methods");
                }
                //Only Output on new patches added
            }
            //Same as above but in coroutines not to thread lock server
            private IEnumerator ScanForNewAssemblys(int Checks) {
                int patched = 0;
                foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
                    if (assembly == null) {
                        continue;
                    }
                    string n = assembly?.GetName()?.Name;
                    if (string.IsNullOrEmpty(n) || Blacklist.Contains(n) || Patched.ContainsKey(n)) {
                        continue;
                    }
                    AssemblyData assemblyData = new AssemblyData();
                    foreach (Type type in assembly.GetTypes()) {
                        if (type == null || string.IsNullOrEmpty(type?.Name)) {
                            continue;
                        }
                        if (type?.Name != this.Name && !type.Name.Contains("<>") && !type.Name.Contains("OfType")) {
                            foreach (MethodInfo mi2 in type.GetRuntimeMethods()) {
                                if (Checks++ > 40) {
                                    if (Performance.report.frameRateAverage < 15) {
                                        yield return CoroutineEx.waitForSeconds(0.01f);
                                    }
                                    else {
                                        yield return CoroutineEx.waitForSeconds(0.003f);
                                    }
                                    Checks = 0;
                                }
                                string name = mi2?.DeclaringType?.Name;
                                if (!BlacklistMethods.Contains(mi2?.Name.ToLower()) && !name.Contains(Name)) {
                                    try {
                                        assemblyData.Patches.Add(mi2, harmony.Patch(mi2, new HarmonyMethod(AccessTools.Method(typeof(AAAMethodTimer), "Prefix")), new HarmonyMethod(AccessTools.Method(typeof(AAAMethodTimer), "Postfix"))));
                                        patched++;
                                    }
                                    catch {
                                    }
                                }
                            }
                        }
                    }
                    Patched.Add(n, assemblyData);
                }
                if (patched != 0) {
                    Puts("Patched " + patched + " New Methods");
                }
            }
            //Run a normal oxide hook call but do it with a stopwatch to time it.public void HookPerformance(HookMethod method, object[] args, CSharpPlugin __instance, ref object __result)
            {
                bool flag = !TimerRunning && (method.Method.Name.Length >= 0);
                if (flag) {
                    TimerRunning = true;
                    HookTimer.Restart();
                }
                long Memory = -1;
                try {
                    if (!method.IsBaseHook && args != null && args.Length != 0) {
                        for (int i = 0; i < args.Length; i++) {
                            object obj = args[i];
                            if (obj != null) {
                                Type parameterType = method.Parameters[i].ParameterType;
                                bool isValueType = parameterType.IsValueType;
                                if (isValueType) {
                                    if (parameterType != typeof(object) && obj.GetType() != parameterType) {
                                        args[i] = Convert.ChangeType(obj, parameterType);
                                    }
                                }
                            }
                        }
                    }
                    if (!__instance.DirectCallHook(method.Name, out __result, args)) {
                        __result = method.Method.Invoke(__instance, args);
                    }
                }
                catch (Exception ex) {
                    string[] array = new string[5];
                    array[0] = "Failed to call hook ";
                    int num = 1;
                    string text;
                    if (method == null) {
                        text = null;
                    }
                    else {
                        string name = method.Name;
                        text = ((name != null) ? name.ToString() : null);
                    }
                    array[num] = (text ?? "NULL");
                    array[2] = ":\n";
                    array[3] = ((ex != null) ? ex.ToString() : null);
                    array[4] = "\n\n\n";
                    __instance.RaiseError(string.Concat(array));
                }
                if (flag) {
                    HookTimer.Stop();
                    TimerRunning = false;
                    if (__instance.Name.Contains(Name)) {
                        return;
                    }
                    //Dont log self
                    foreach (var p in Patched.Values) {
                        if (p.MethodRunTime.ContainsKey(method.Method)) {
                            p.MethodRunTime[method.Method].MemoryAllocations += Memory;
                            p.MethodRunTime[method.Method].TotalHookTime = p.MethodRunTime[method.Method].TotalHookTime.Add(HookTimer.Elapsed);
                            p.MethodRunTime[method.Method].HookCount++;
                        }
                        else {
                            p.MethodRunTime.Add(method.Method, new MethodLog(HookTimer.Elapsed, 1, Memory));
                        }
                    }
                }
            }
#endregion
#region Harmony
            [AutoPatch]
            [HarmonyPatch(typeof(CSharpPlugin), "InvokeMethod", typeof(HookMethod), typeof(object[]))]
            internal class Performance_Update {
                static bool Prefix(HookMethod method, object[] args, CSharpPlugin __instance, ref object __result) {
                    try {
                        plugin.HookPerformance(method, args, __instance, ref __result);
                        return false;
                    }
                    catch {
                    }
                    return true;
                }
            }
            static void Prefix(out DataRecord __state) {
                try {
                    __state = new DataRecord();
                    // assign your own state
                    __state.memory = GC.GetTotalMemory(false);
                    __state.stopwatch = Stopwatch.StartNew();
                    return;
                }
                catch {
                }
                __state = null;
            }
            static void Postfix(DataRecord __state, MethodInfo __originalMethod) {
                if (__state != null) {
                    __state.stopwatch.Stop();
                    try {
                        if (plugin != null) {
                            foreach (var p in plugin.Patched.Values) {
                                if (p.MethodRunTime.ContainsKey(__originalMethod)) {
                                    p.MethodRunTime[__originalMethod].TotalHookTime = p.MethodRunTime[__originalMethod].TotalHookTime.Add(__state.stopwatch.Elapsed);
                                    p.MethodRunTime[__originalMethod].HookCount++;
                                    p.MethodRunTime[__originalMethod].MemoryAllocations += (GC.GetTotalMemory(false) - __state.memory) / 1024;
                                }
                                else {
                                    p.MethodRunTime.Add(__originalMethod, new MethodLog(__state.stopwatch.Elapsed, 1, (GC.GetTotalMemory(false) - __state.memory) / 1024));
                                }
                            }
                        }
                    }
                    catch {
                    }
                }
            }
#endregion
        }
    }

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху