Decompiled source of ServerDiceRoll v1.0.1

bbar.Mods.ServerDiceRoll.dll

Decompiled 10 months ago
using 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;
		}
	}
}