From 867ebd697ebbca1ad7d17da31d6435dca4bb9d19 Mon Sep 17 00:00:00 2001 From: Tryhard999 <95774540+Tryhard999@users.noreply.github.com> Date: Sat, 16 Dec 2023 22:43:56 +0200 Subject: [PATCH 1/6] More performant o.plugins --- src/RustCommands.cs | 66 ++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/src/RustCommands.cs b/src/RustCommands.cs index 96bfb3772..7be144448 100644 --- a/src/RustCommands.cs +++ b/src/RustCommands.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text; +using ConVar; namespace Oxide.Game.Rust { @@ -297,37 +299,63 @@ private void LoadCommand(IPlayer player, string command, string[] args) [HookMethod("PluginsCommand")] private void PluginsCommand(IPlayer player) { - Plugin[] loadedPlugins = pluginManager.GetPlugins().Where(pl => !pl.IsCorePlugin).ToArray(); - HashSet loadedPluginNames = new HashSet(loadedPlugins.Select(pl => pl.Name)); - Dictionary unloadedPluginErrors = new Dictionary(); - foreach (PluginLoader loader in Interface.Oxide.GetPluginLoaders()) + var plugins = pluginManager.GetPlugins(); + + var output = Facepunch.Pool.Get(); + output.Clear(); //Fp does not clear stringbuilders after using them + + output.Append("Listing ") // Plugin count appended later on + .Append(" plugins:"); // TODO: Localization + + int pluginCount = 1; + + foreach (var plugin in plugins.Where(p => p.Filename != null && !p.IsCorePlugin)) { - foreach (string name in loader.ScanDirectory(Interface.Oxide.PluginDirectory).Except(loadedPluginNames)) - { - unloadedPluginErrors[name] = loader.PluginErrors.TryGetValue(name, out string msg) ? msg : "Unloaded"; // TODO: Localization - } + output.AppendLine() + .Append(" ") + .Append(pluginCount++.ToString("00")) + .Append(" \"") + .Append(plugin.Title) + .Append("\"") + .Append(" (") + .Append(plugin.Version) + .Append(") by ") + .Append(plugin.Author) + .Append(" (") + .Append(plugin.TotalHookTime.ToString("0.00")) + .Append("s) - ") + .Append(plugin.Filename.Basename()); } - int totalPluginCount = loadedPlugins.Length + unloadedPluginErrors.Count; - if (totalPluginCount < 1) + if (pluginCount < 1) { player.Reply(lang.GetMessage("NoPluginsFound", this, player.Id)); + Facepunch.Pool.Free(ref output); return; } - string output = $"Listing {loadedPlugins.Length + unloadedPluginErrors.Count} plugins:"; // TODO: Localization - int number = 1; - foreach (Plugin plugin in loadedPlugins.Where(p => p.Filename != null)) + foreach (var loader in Interface.Oxide.GetPluginLoaders()) { - output += $"\n {number++:00} \"{plugin.Title}\" ({plugin.Version}) by {plugin.Author} ({plugin.TotalHookTime:0.00}s) - {plugin.Filename.Basename()}"; - } + var unloadedNames = loader.ScanDirectory(Interface.Oxide.PluginDirectory) + .Except(plugins.Select(pl => pl.Name)); - foreach (string pluginName in unloadedPluginErrors.Keys) - { - output += $"\n {number++:00} {pluginName} - {unloadedPluginErrors[pluginName]}"; + foreach (var name in unloadedNames) + { + output.AppendLine() + .Append(" ") + .Append(pluginCount++.ToString("00")) + .Append(" ") + .Append(name) + .Append(" - ") + .Append(loader.PluginErrors.TryGetValue(name, out var msg) ? msg : "Unloaded"); + } } - player.Reply(output); + output.Insert(8, pluginCount - 1); + + player.Reply(output.ToString()); + + Facepunch.Pool.Free(ref output); } #endregion Plugins Command From 0a6758cb81acb91373c9001c5054b54b61f023f9 Mon Sep 17 00:00:00 2001 From: Tryhard999 <95774540+Tryhard999@users.noreply.github.com> Date: Fri, 14 Jun 2024 21:44:19 +0300 Subject: [PATCH 2/6] Update RustCommands.cs --- src/RustCommands.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/RustCommands.cs b/src/RustCommands.cs index 7be144448..99ab036b8 100644 --- a/src/RustCommands.cs +++ b/src/RustCommands.cs @@ -309,8 +309,10 @@ private void PluginsCommand(IPlayer player) int pluginCount = 1; - foreach (var plugin in plugins.Where(p => p.Filename != null && !p.IsCorePlugin)) + foreach (var plugin in plugins) { + if (plugin.Filename == null || plugin.IsCorePlugin) continue; + output.AppendLine() .Append(" ") .Append(pluginCount++.ToString("00")) From a891fbf1f36a547a762d3c404853c737ac9a40b8 Mon Sep 17 00:00:00 2001 From: Tryhard999 <95774540+Tryhard999@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:30:26 +0300 Subject: [PATCH 3/6] Im here what is this --- src/RustCommands.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RustCommands.cs b/src/RustCommands.cs index 99ab036b8..6348fb365 100644 --- a/src/RustCommands.cs +++ b/src/RustCommands.cs @@ -307,7 +307,7 @@ private void PluginsCommand(IPlayer player) output.Append("Listing ") // Plugin count appended later on .Append(" plugins:"); // TODO: Localization - int pluginCount = 1; + int pluginCount = 0; foreach (var plugin in plugins) { @@ -329,7 +329,7 @@ private void PluginsCommand(IPlayer player) .Append(plugin.Filename.Basename()); } - if (pluginCount < 1) + if (pluginCount == 0) { player.Reply(lang.GetMessage("NoPluginsFound", this, player.Id)); Facepunch.Pool.Free(ref output); From ee28737bd03dad5716d469ae5328567fa3ae212e Mon Sep 17 00:00:00 2001 From: Tryhard999 <95774540+Tryhard999@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:40:23 +0300 Subject: [PATCH 4/6] New pooling and worse readability and memory stats --- src/RustCommands.cs | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/RustCommands.cs b/src/RustCommands.cs index 6348fb365..8ba5aa428 100644 --- a/src/RustCommands.cs +++ b/src/RustCommands.cs @@ -302,7 +302,6 @@ private void PluginsCommand(IPlayer player) var plugins = pluginManager.GetPlugins(); var output = Facepunch.Pool.Get(); - output.Clear(); //Fp does not clear stringbuilders after using them output.Append("Listing ") // Plugin count appended later on .Append(" plugins:"); // TODO: Localization @@ -313,26 +312,16 @@ private void PluginsCommand(IPlayer player) { if (plugin.Filename == null || plugin.IsCorePlugin) continue; - output.AppendLine() - .Append(" ") - .Append(pluginCount++.ToString("00")) - .Append(" \"") - .Append(plugin.Title) - .Append("\"") - .Append(" (") - .Append(plugin.Version) - .Append(") by ") - .Append(plugin.Author) - .Append(" (") - .Append(plugin.TotalHookTime.ToString("0.00")) - .Append("s) - ") - .Append(plugin.Filename.Basename()); + output.AppendLine().Append(" ").Append(pluginCount++.ToString("00")).Append(" \"").Append(plugin.Title) + .Append("\"").Append(" (").Append(plugin.Version).Append(") by ").Append(plugin.Author).Append(" (") + .Append(plugin.TotalHookTime.ToString("0.00")).Append("s) - ").Append("(") + .Append(FormatBytes(plugin.TotalHookMemory)).Append(" - ").Append(plugin.Filename.Basename()); } if (pluginCount == 0) { player.Reply(lang.GetMessage("NoPluginsFound", this, player.Id)); - Facepunch.Pool.Free(ref output); + Facepunch.Pool.FreeUnmanaged(ref output); return; } @@ -343,13 +332,8 @@ private void PluginsCommand(IPlayer player) foreach (var name in unloadedNames) { - output.AppendLine() - .Append(" ") - .Append(pluginCount++.ToString("00")) - .Append(" ") - .Append(name) - .Append(" - ") - .Append(loader.PluginErrors.TryGetValue(name, out var msg) ? msg : "Unloaded"); + output.AppendLine().Append(" ").Append(pluginCount++.ToString("00")).Append(" ").Append(name) + .Append(" - ").Append(loader.PluginErrors.TryGetValue(name, out var msg) ? msg : "Unloaded"); } } @@ -357,7 +341,7 @@ private void PluginsCommand(IPlayer player) player.Reply(output.ToString()); - Facepunch.Pool.Free(ref output); + Facepunch.Pool.FreeUnmanaged(ref output); } #endregion Plugins Command From 27aaea0c353083ceedb83a90fa25196d73e2f8d8 Mon Sep 17 00:00:00 2001 From: Tryhard999 <95774540+Tryhard999@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:59:40 +0300 Subject: [PATCH 5/6] More performant CUIHelper --- src/RustCui.cs | 95 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 22 deletions(-) diff --git a/src/RustCui.cs b/src/RustCui.cs index 4fddfe7ba..338a9f0aa 100644 --- a/src/RustCui.cs +++ b/src/RustCui.cs @@ -4,55 +4,106 @@ using References::Newtonsoft.Json; using References::Newtonsoft.Json.Converters; using References::Newtonsoft.Json.Linq; +using References::ProtoBuf; using System; using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; using UnityEngine; using UnityEngine.UI; namespace Oxide.Game.Rust.Cui { + public sealed class JsonArrayPool : IArrayPool + { + public static readonly JsonArrayPool Shared = new JsonArrayPool(); + public T[] Rent(int minimumLength) => System.Buffers.ArrayPool.Shared.Rent(minimumLength); + public void Return(T[] array) => System.Buffers.ArrayPool.Shared.Return(array); + } + public static class CuiHelper { - public static string ToJson(List elements, bool format = false) + private static readonly StringBuilder sb = new StringBuilder(64 * 1024); + + private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { - return JsonConvert.SerializeObject(elements, format ? Formatting.Indented : Formatting.None, new JsonSerializerSettings - { - DefaultValueHandling = DefaultValueHandling.Ignore - }).Replace("\\n", "\n"); + DefaultValueHandling = DefaultValueHandling.Ignore, + NullValueHandling = NullValueHandling.Ignore, + DateParseHandling = DateParseHandling.None, + FloatFormatHandling = FloatFormatHandling.Symbol, + StringEscapeHandling = StringEscapeHandling.Default + }; + + private static readonly JsonSerializer _serializer = JsonSerializer.Create(Settings); + private static readonly StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture); + private static readonly JsonTextWriter jw = new JsonTextWriter(sw) + { + Formatting = Formatting.None, + ArrayPool = JsonArrayPool.Shared, + CloseOutput = false + }; + private static readonly JsonTextWriter jwFormated = new JsonTextWriter(sw) + { + Formatting = Formatting.Indented, + ArrayPool = JsonArrayPool.Shared, + CloseOutput = false + }; + + public static string ToJson(IReadOnlyList elements, bool format = false) + { + sb.Clear(); + var writer = format ? jwFormated : jw; + _serializer.Serialize(writer, elements); + var json = sb.ToString().Replace("\\n", "\n"); + return json; } public static List FromJson(string json) => JsonConvert.DeserializeObject>(json); - public static string GetGuid() => Guid.NewGuid().ToString().Replace("-", string.Empty); + public static string GetGuid() => Guid.NewGuid().ToString("N"); - public static bool AddUi(BasePlayer player, List elements) => AddUi(player, ToJson(elements)); + public static bool AddUi(BasePlayer player, List elements) + { + if (player?.net == null) + return false; + + var json = ToJson(elements); + + if (Interface.CallHook("CanUseUI", player, json) != null) + return false; + + CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("AddUI", player.net.connection), json); + return true; + } public static bool AddUi(BasePlayer player, string json) { - if (player?.net != null && Interface.CallHook("CanUseUI", player, json) == null) - { - CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("AddUI", player.net.connection ), json); - return true; - } + if (player?.net == null || Interface.CallHook("CanUseUI", player, json) != null) + return false; - return false; + CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("AddUI", player.net.connection), json); + return true; } public static bool DestroyUi(BasePlayer player, string elem) { - if (player?.net != null) - { - Interface.CallHook("OnDestroyUI", player, elem); - CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("DestroyUI", player.net.connection ), elem); - return true; - } + if (player?.net == null) + return false; - return false; + Interface.CallHook("OnDestroyUI", player, elem); + CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("DestroyUI", player.net.connection ), elem); + return true; } public static void SetColor(this ICuiColor elem, Color color) { - elem.Color = $"{color.r} {color.g} {color.b} {color.a}"; + sb.Clear(); + sb.Append(color.r).Append(' ') + .Append(color.g).Append(' ') + .Append(color.b).Append(' ') + .Append(color.a); + elem.Color = sb.ToString(); } public static Color GetColor(this ICuiColor elem) => ColorEx.Parse(elem.Color); @@ -299,7 +350,7 @@ public class CuiRawImageComponent : ICuiComponent, ICuiColor [JsonProperty("png")] public string Png { get; set; } - + [JsonProperty("steamid")] public string SteamId { get; set; } From 923239c8e11ffb055f123deccaf90ef23874f4b5 Mon Sep 17 00:00:00 2001 From: Tryhard999 <95774540+Tryhard999@users.noreply.github.com> Date: Sun, 24 Aug 2025 18:11:35 +0300 Subject: [PATCH 6/6] Revert "More performant CUIHelper" This reverts commit 27aaea0c353083ceedb83a90fa25196d73e2f8d8. --- src/RustCui.cs | 95 ++++++++++++-------------------------------------- 1 file changed, 22 insertions(+), 73 deletions(-) diff --git a/src/RustCui.cs b/src/RustCui.cs index 338a9f0aa..4fddfe7ba 100644 --- a/src/RustCui.cs +++ b/src/RustCui.cs @@ -4,106 +4,55 @@ using References::Newtonsoft.Json; using References::Newtonsoft.Json.Converters; using References::Newtonsoft.Json.Linq; -using References::ProtoBuf; using System; using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; using UnityEngine; using UnityEngine.UI; namespace Oxide.Game.Rust.Cui { - public sealed class JsonArrayPool : IArrayPool - { - public static readonly JsonArrayPool Shared = new JsonArrayPool(); - public T[] Rent(int minimumLength) => System.Buffers.ArrayPool.Shared.Rent(minimumLength); - public void Return(T[] array) => System.Buffers.ArrayPool.Shared.Return(array); - } - public static class CuiHelper { - private static readonly StringBuilder sb = new StringBuilder(64 * 1024); - - private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings - { - DefaultValueHandling = DefaultValueHandling.Ignore, - NullValueHandling = NullValueHandling.Ignore, - DateParseHandling = DateParseHandling.None, - FloatFormatHandling = FloatFormatHandling.Symbol, - StringEscapeHandling = StringEscapeHandling.Default - }; - - private static readonly JsonSerializer _serializer = JsonSerializer.Create(Settings); - private static readonly StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture); - private static readonly JsonTextWriter jw = new JsonTextWriter(sw) + public static string ToJson(List elements, bool format = false) { - Formatting = Formatting.None, - ArrayPool = JsonArrayPool.Shared, - CloseOutput = false - }; - private static readonly JsonTextWriter jwFormated = new JsonTextWriter(sw) - { - Formatting = Formatting.Indented, - ArrayPool = JsonArrayPool.Shared, - CloseOutput = false - }; - - public static string ToJson(IReadOnlyList elements, bool format = false) - { - sb.Clear(); - var writer = format ? jwFormated : jw; - _serializer.Serialize(writer, elements); - var json = sb.ToString().Replace("\\n", "\n"); - return json; + return JsonConvert.SerializeObject(elements, format ? Formatting.Indented : Formatting.None, new JsonSerializerSettings + { + DefaultValueHandling = DefaultValueHandling.Ignore + }).Replace("\\n", "\n"); } public static List FromJson(string json) => JsonConvert.DeserializeObject>(json); - public static string GetGuid() => Guid.NewGuid().ToString("N"); + public static string GetGuid() => Guid.NewGuid().ToString().Replace("-", string.Empty); - public static bool AddUi(BasePlayer player, List elements) - { - if (player?.net == null) - return false; - - var json = ToJson(elements); - - if (Interface.CallHook("CanUseUI", player, json) != null) - return false; - - CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("AddUI", player.net.connection), json); - return true; - } + public static bool AddUi(BasePlayer player, List elements) => AddUi(player, ToJson(elements)); public static bool AddUi(BasePlayer player, string json) { - if (player?.net == null || Interface.CallHook("CanUseUI", player, json) != null) - return false; + if (player?.net != null && Interface.CallHook("CanUseUI", player, json) == null) + { + CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("AddUI", player.net.connection ), json); + return true; + } - CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("AddUI", player.net.connection), json); - return true; + return false; } public static bool DestroyUi(BasePlayer player, string elem) { - if (player?.net == null) - return false; + if (player?.net != null) + { + Interface.CallHook("OnDestroyUI", player, elem); + CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("DestroyUI", player.net.connection ), elem); + return true; + } - Interface.CallHook("OnDestroyUI", player, elem); - CommunityEntity.ServerInstance.ClientRPC(RpcTarget.Player("DestroyUI", player.net.connection ), elem); - return true; + return false; } public static void SetColor(this ICuiColor elem, Color color) { - sb.Clear(); - sb.Append(color.r).Append(' ') - .Append(color.g).Append(' ') - .Append(color.b).Append(' ') - .Append(color.a); - elem.Color = sb.ToString(); + elem.Color = $"{color.r} {color.g} {color.b} {color.a}"; } public static Color GetColor(this ICuiColor elem) => ColorEx.Parse(elem.Color); @@ -350,7 +299,7 @@ public class CuiRawImageComponent : ICuiComponent, ICuiColor [JsonProperty("png")] public string Png { get; set; } - + [JsonProperty("steamid")] public string SteamId { get; set; }