Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ServerDiceRoll v1.0.1
bbar.Mods.ServerDiceRoll.dll
Decompiled 2 years agousing System; using System.Collections.Concurrent; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using ServerDiceRoll.Patches; using ServerDiceRoll.Support; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")] [assembly: AssemblyCompany("bbar.Mods.ServerDiceRoll")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("Simple Server Dice Roller")] [assembly: AssemblyTitle("bbar.Mods.ServerDiceRoll")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.0")] [module: UnverifiableCode] namespace ServerDiceRoll { [BepInPlugin("bbar.Mods.ServerDiceRoll", "Simple Server Dice Roller", "1.0.1")] public class VSDR : BaseUnityPlugin { private Harmony _harmony; public static VSDR Instance { get; private set; } public ManualLogSource Log { get; private set; } public PluginConfig PluginConfig { get; private set; } public void Awake() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; PluginConfig = new PluginConfig(((BaseUnityPlugin)this).Config); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony = new Harmony("bbar.Mods.ServerDiceRoll"); _harmony.PatchAll(executingAssembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin bbar.Mods.ServerDiceRoll is loaded!"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } PluginConfig?.Dispose(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "bbar.Mods.ServerDiceRoll"; public const string PLUGIN_NAME = "Simple Server Dice Roller"; public const string PLUGIN_VERSION = "1.0.1"; } } namespace ServerDiceRoll.Support { public class MessageHelper { private readonly MessageQueue _messages; private readonly MessageType _location; public MessageHelper() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) _messages = new MessageQueue(VSDR.Instance.PluginConfig.MessageQueueLength, TimeSpan.FromSeconds(VSDR.Instance.PluginConfig.MessageQueueTimeout).Ticks); _location = VSDR.Instance.PluginConfig.MessageLocation; } public void ResendBroadcasts(long peerId) { _messages.PurgeOutdated(1); MessagePeer(peerId, _messages.ConcatMessages()); } public void MessagePeer(long peerId, string text) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected I4, but got Unknown VSDR.Instance.Log.LogDebug((object)$"Messaging peer {peerId}: {text}"); ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "ShowMessage", new object[2] { (int)_location, text }); } public void Broadcast(string text) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) _messages.AddMessage(text); string text2 = _messages.ConcatMessages(); VSDR.Instance.Log.LogDebug((object)("Messaging everyone: " + text2)); MessageHud.instance.MessageAll(_location, text2); } } public class MessageQueue { protected struct MsgPair { public string Message; public long TimeStamp; public MsgPair(string message, long timeStamp) { Message = message; TimeStamp = timeStamp; } } private readonly ConcurrentQueue<MsgPair> _msgQueue = new ConcurrentQueue<MsgPair>(); public int Count => _msgQueue.Count; public int Limit { get; } public long Timeout { get; } public MessageQueue(int limit, long timeout) { Limit = limit; Timeout = timeout; } public void AddMessage(string message) { _msgQueue.Enqueue(new MsgPair(message, DateTime.Now.Ticks)); while (_msgQueue.Count > Limit) { _msgQueue.TryDequeue(out var _); } PurgeOutdated(); } public void PurgeOutdated(int keep = 0) { if (Timeout >= 1) { long ticks = DateTime.Now.Ticks; MsgPair result; while (_msgQueue.Count > keep && _msgQueue.TryPeek(out result) && ticks - result.TimeStamp > Timeout) { _msgQueue.TryDequeue(out var _); } } } public string ConcatMessages() { return ToString(); } public override string ToString() { MsgPair[] source = _msgQueue.ToArray(); return string.Join("\n", source.Select((MsgPair p) => p.Message)); } } public class PluginConfig : IDisposable { private readonly ConfigEntry<string> _cmdPrefix; private readonly ConfigEntry<string> _cmdRoll; private readonly ConfigEntry<string> _cmdAward; private readonly ConfigEntry<string> _cmdViewResults; private readonly ConfigEntry<int> _rollMax; private readonly ConfigEntry<string> _colorUsage; private readonly ConfigEntry<string> _colorRoll; private readonly ConfigEntry<string> _colorAward; private readonly ConfigEntry<string> _colorHighlight; private readonly ConfigEntry<int> _msgQueueSize; private readonly ConfigEntry<int> _msgQueueTimeoutSecs; private readonly ConfigEntry<MessageType> _msgLocation; public string CmdPrefix => _cmdPrefix.Value; public string CmdRoll => _cmdRoll.Value; public string CmdAward => _cmdAward.Value; public string CmdResults => _cmdViewResults.Value; public int RollMax => _rollMax.Value; public string ColorUsage => _colorUsage.Value; public string ColorRoll => _colorRoll.Value; public string ColorAward => _colorAward.Value; public string ColorHighlight => _colorHighlight.Value; public int MessageQueueLength => _msgQueueSize.Value; public int MessageQueueTimeout => _msgQueueTimeoutSecs.Value; public MessageType MessageLocation => _msgLocation.Value; public PluginConfig(ConfigFile config) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Expected O, but got Unknown _cmdPrefix = config.Bind<string>("Commands", "CommandPrefix", "!", new ConfigDescription("Character to use to start a command with this plugin. Since this is a server-side plugin a slash cannot be used (as that indicates a Valheim command, handled client-side).", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "!", "@", "#", "$", "%" }), Array.Empty<object>())); _cmdRoll = config.Bind<string>("Commands", "RollCommand", "roll", "String to use to trigger the 'roll' command."); _cmdAward = config.Bind<string>("Commands", "AwardCommand", "award", "String to use to trigger the 'award' command."); _cmdViewResults = config.Bind<string>("Commands", "CommandViewResults", "results", "String to use to trigger the 'results' command."); _rollMax = config.Bind<int>("Commands", "DefaultRoll", 100, new ConfigDescription("The default value to use for the 'roll' command.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 100000), Array.Empty<object>())); _colorUsage = config.Bind<string>("Color", "Usage", "red", "The color to use for the usage messages. (Messages sent to players when the enter a command incorrectly.) Unset this to use the Valheim default."); _colorRoll = config.Bind<string>("Color", "Roll", "orange", "The color to use for the 'roll' messages. Unset this to use the Valheim default."); _colorAward = config.Bind<string>("Color", "Award", "orange", "The color to use for the 'award' messages. Unset this to use the Valheim default."); _colorHighlight = config.Bind<string>("Color", "Highlight", "red", "The color to use to highlight important information in the message (e.g. the number of a roll, or winner of an award)."); _msgQueueSize = config.Bind<int>("Advanced", "MessageQueueSize", 7, new ConfigDescription("How many messages to keep in the history buffer that gets sent to clients after a 'roll', 'award', or 'results' command.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); _msgQueueTimeoutSecs = config.Bind<int>("Advanced", "MessageQueueTimeout", 60, new ConfigDescription("How many seconds messages should remain in the history buffer that gets sent to clients. Set this to 0 to disable time based history pruning (the buffer will fill to the MessageQueueSize set above before being replaced).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 600), Array.Empty<object>())); _msgLocation = config.Bind<MessageType>("Advanced", "MessageLocation", (MessageType)1, "Location to display 'roll' and 'award' messages. Top left is more out of the way, center lasts longer and is easier to read."); _msgQueueSize.SettingChanged += OnSettingsChanged; _msgQueueTimeoutSecs.SettingChanged += OnSettingsChanged; _msgLocation.SettingChanged += OnSettingsChanged; } public void Dispose() { if (_msgQueueSize != null) { _msgQueueSize.SettingChanged -= OnSettingsChanged; } if (_msgQueueTimeoutSecs != null) { _msgQueueTimeoutSecs.SettingChanged -= OnSettingsChanged; } if (_msgLocation != null) { _msgLocation.SettingChanged -= OnSettingsChanged; } } private void OnSettingsChanged(object sender, EventArgs args) { ZRoutedRpcPatch.OnMessageHelperSettingsChanged(); } } } namespace ServerDiceRoll.Patches { [HarmonyPatch(typeof(ZRoutedRpc))] public class ZRoutedRpcPatch { public static int SayHashCode = StringExtensionMethods.GetStableHashCode("Say"); private static MessageHelper s_messageHelper = new MessageHelper(); private static PluginConfig Config => VSDR.Instance.PluginConfig; [HarmonyPatch("HandleRoutedRPC")] [HarmonyPostfix] public static void OnHandleRoutedRPC(RoutedRPCData data) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown if (!ZNet.instance.IsServer() || data.m_methodHash != SayHashCode) { return; } try { ZPackage val = new ZPackage(data.m_parameters.GetArray()); val.SetPos(0); val.ReadInt(); UserInfo val2 = new UserInfo(); val2.Deserialize(ref val); string text = val.ReadString() ?? ""; text = text.Trim(); VSDR.Instance.Log.LogDebug((object)("Testing message " + text)); if (text.StartsWith(Config.CmdPrefix + Config.CmdRoll)) { HandleRoll(data.m_senderPeerID, val2.Name, text); } else if (text.StartsWith(Config.CmdPrefix + Config.CmdAward)) { HandleAward(data.m_senderPeerID, val2.Name, text); } else if (text.StartsWith(Config.CmdPrefix + Config.CmdResults)) { s_messageHelper.ResendBroadcasts(data.m_senderPeerID); } } catch (Exception arg) { VSDR.Instance.Log.LogError((object)$"Exception while handling roll/award action: {arg}"); } } internal static void OnMessageHelperSettingsChanged() { s_messageHelper = new MessageHelper(); } private static void HandleRoll(long triggeringPeerId, string triggeringPlayer, string message) { string[] array = message.Split(new char[1] { ' ' }); int result = Config.RollMax; if (array.Length > 1) { string text = array[1]; if (!int.TryParse(text, out result) || result < 1) { s_messageHelper.MessagePeer(triggeringPeerId, BuildRollUsage(text + " is not a positive integer!")); return; } } string text2 = triggeringPlayer; int num = Random.RandomRangeInt(1, result + 1); string arg = $"{num}"; if (!string.IsNullOrWhiteSpace(Config.ColorHighlight)) { arg = $"<color=\"{Config.ColorHighlight}\">{num}</color>"; text2 = "<color=\"" + Config.ColorHighlight + "\">" + text2 + "</color>"; } string text3 = $"{text2} rolled a {result} sided die and got a {arg}!"; if (!string.IsNullOrWhiteSpace(Config.ColorRoll)) { text3 = "<color=\"" + Config.ColorRoll + "\">" + text3 + "</color>"; } s_messageHelper.Broadcast(text3); } private static void HandleAward(long triggeringPeerId, string triggeringPlayer, string message) { string[] array = message.Split(new char[1] { ' ' }); if (array.Length < 2 || string.IsNullOrEmpty(array[1])) { s_messageHelper.MessagePeer(triggeringPeerId, BuildAwardUsage("Missing list of recipients!")); return; } string[] array2 = (from n in array[1].Split(new char[1] { ',' }) where !string.IsNullOrWhiteSpace(n) select n).ToArray(); string text = string.Join(", ", array2.Take(array2.Length - 1)) + ", or " + array2.Last(); int num = Random.RandomRangeInt(0, array2.Length); string text2 = array2[num] ?? ""; if (!string.IsNullOrWhiteSpace(Config.ColorHighlight)) { text2 = "<color=\"" + Config.ColorHighlight + "\">" + text2 + "</color>"; } string text3 = ""; string text4 = "picks "; if (array.Length > 2) { string text5 = string.Join(" ", array.Skip(2)); if (!string.IsNullOrWhiteSpace(Config.ColorHighlight)) { text5 = "<color=\"" + Config.ColorHighlight + "\">" + text5 + "</color>"; } text3 = " of \"" + text5 + "\""; text4 = "awards \"" + text5 + "\" to "; } string text6 = triggeringPlayer + " asks Odin to decide if " + text + " is worthy" + text3 + "..."; string text7 = "Odin " + text4 + text2 + "!"; string text8 = text6 + "\n" + text7; if (!string.IsNullOrWhiteSpace(Config.ColorAward)) { text8 = "<color=\"" + Config.ColorAward + "\">" + text8 + "</color>"; } s_messageHelper.Broadcast(text8); } private static string BuildRollUsage(string problemDesc) { string text = "Usage: " + Config.CmdPrefix + Config.CmdRoll + " <Die Size (optional)>"; string text2 = problemDesc + "\n" + text; if (!string.IsNullOrWhiteSpace(Config.ColorUsage)) { text2 = "<color=\"" + Config.ColorUsage + "\">" + text2 + "</color>"; } return text2; } private static string BuildAwardUsage(string problemDesc) { string text = "Usage: " + Config.CmdPrefix + Config.CmdAward + " <Person1,Person2,etc (no spaces)> <Name of thing to be awarded (optional)>"; string text2 = problemDesc + "\n" + text; if (!string.IsNullOrWhiteSpace(Config.ColorUsage)) { text2 = "<color=\"" + Config.ColorUsage + "\">" + text2 + "</color>"; } return text2; } } }