AndrewLin.Fomo.dll

Decompiled 4 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Fomo.Core;
using Fomo.Core.Commands;
using Fomo.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PurrNet;
using UnityEngine;
using UnityEngine.EventSystems;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AndrewLin.Fomo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("FOMO: A mod for On-Together to allow users to keep more messages in their chat and also in chat log files text file.")]
[assembly: AssemblyFileVersion("0.0.6.0")]
[assembly: AssemblyInformationalVersion("0.0.6+4eb3da84fdcdcfb428a7f208f828efe5d3b7f3dc")]
[assembly: AssemblyProduct("AndrewLin.Fomo")]
[assembly: AssemblyTitle("AndrewLin.Fomo")]
[assembly: AssemblyVersion("0.0.6.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
public static class ChatUtils
{
	private static readonly Regex CommonTMPTagRegex = new Regex("<\\/?(color(=#[0-9a-fA-F]{3,8})?|#[0-9a-fA-F]{3,8}|b|i|u|s|sup|sub|size(=[\\d.]+%?)?|alpha=#[0-9a-fA-F]{2}|mark(=#[0-9a-fA-F]{3,8})?|uppercase|lowercase|smallcaps|font|voffset|nobr|noparse|sprite(=\\d+)?|link(=[^>]*)?)>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

	public static void AddGlobalNotification(string text)
	{
		NetworkSingleton<TextChannelManager>.I.AddNotification(text);
	}

	public static string GetUserName()
	{
		return NetworkSingleton<TextChannelManager>.I.UserName;
	}

	public static void SendMessageAsync(string userName, string text, bool Islocal = false)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
		Transform mainPlayer = i.MainPlayer;
		byte[] bytes = Encoding.Unicode.GetBytes(text.Substring(0, Math.Min(text.Length, 250)));
		byte[] bytes2 = Encoding.Unicode.GetBytes(userName);
		string text2 = Traverse.Create((object)i).Field<string>("_playerId").Value ?? "0";
		i.SendMessageAsync(bytes, bytes2, Islocal, mainPlayer.position, text2, default(RPCInfo));
	}

	public static void CleanCommand()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		LockState lockState = (LockState)(NetworkSingleton<MusicManager>.I.IsActive ? 5 : 0);
		MonoSingleton<TaskManager>.I.SetLockState(lockState);
		EventSystem.current.SetSelectedGameObject((GameObject)null);
		if (MonoSingleton<UIManager>.I.MessageInput.text != "/help")
		{
			MonoSingleton<UIManager>.I.MessageInput.text = "";
		}
	}

	public static string CleanTMPTags(string input)
	{
		return CommonTMPTagRegex.Replace(input, string.Empty);
	}
}
namespace Fomo
{
	public static class BuildInfo
	{
		public const string Version = "0.0.6";
	}
	[BepInPlugin("com.andrewlin.ontogether.fomo", "Fomo", "0.0.6")]
	public class Plugin : BaseUnityPlugin
	{
		public static readonly int OriginalNotificationLimit = 99;

		public static readonly int DefaultNotificationLimit = 300;

		public static readonly int MaxNotificationLimit = 999;

		private static readonly string DefaultChatLogPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "on-together/fomo/on_together_chat_log.txt");

		public static readonly int DefaultChatLogLocalRange = 5;

		public static readonly int DefaultGlobalChatMessageLimit = 50;

		public static readonly int DefaultLocalChatMessageLimit = 25;

		public const string ModGUID = "com.andrewlin.ontogether.fomo";

		public const string ModName = "Fomo";

		public const string ModVersion = "0.0.6";

		public static ConfigEntry<bool>? EnableFeature { get; private set; }

		public static ConfigEntry<bool>? ShowCommand { get; private set; }

		public static ConfigEntry<bool>? EnableChatFileLogging { get; private set; }

		private static ConfigEntry<string>? ChatLogPath { get; set; }

		public static ConfigEntry<int>? GlobalMessageLimitCount { get; private set; }

		public static ConfigEntry<int>? LocalMessageLimitCount { get; private set; }

		public static ConfigEntry<int>? ChatLogLocalRange { get; private set; }

		public static ConfigEntry<bool>? CleanChatLogTags { get; private set; }

		public static string? PlayerId { get; private set; }

		public static CommandManager? CommandProcessor { get; private set; }

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Fomo v0.0.6 is loaded!");
			InitConfig();
			Harmony val = new Harmony("com.andrewlin.ontogether.fomo");
			val.PatchAll(typeof(TextChannelManagerPatch));
			val.PatchAll(typeof(GameSettingsPatch));
			InitializeChatLog();
			CommandProcessor = new CommandManager();
		}

		private void InitializeChatLog()
		{
			string chatLogPath = getChatLogPath();
			string text = Path.GetDirectoryName(chatLogPath) ?? string.Empty;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Creating chat log directory if it doesn't exist: " + text));
			Directory.CreateDirectory(text);
			ConfigEntry<bool>? enableChatFileLogging = EnableChatFileLogging;
			if (enableChatFileLogging == null || !enableChatFileLogging.Value)
			{
				return;
			}
			if (File.Exists(chatLogPath))
			{
				if (File.GetLastWriteTime(chatLogPath).Date < DateTime.Now.Date)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Clearing chat log file from previous day: " + chatLogPath));
					File.WriteAllText(chatLogPath, string.Empty);
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Creating new chat log file: " + chatLogPath));
				File.Create(chatLogPath).Dispose();
			}
		}

		public static string getChatLogPath()
		{
			string name = ChatLogPath?.Value ?? DefaultChatLogPath;
			name = Environment.ExpandEnvironmentVariables(name);
			if (name.StartsWith("~"))
			{
				string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
				string text = name;
				name = Path.Combine(folderPath, text.Substring(1, text.Length - 1));
			}
			return name;
		}

		public static void setChatLogPath(string newPath)
		{
			if (ChatLogPath != null)
			{
				ChatLogPath.Value = newPath;
			}
		}

		private void InitConfig()
		{
			EnableFeature = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableFeature", true, "Enable or disable the mod feature.");
			ShowCommand = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowCommand", false, "Show the command in chat when used.");
			EnableChatFileLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableChatFileLogging", true, "Enable or disable chat file logging.");
			ChatLogPath = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ChatLogPath", DefaultChatLogPath, "Path to the chat log file.");
			CleanChatLogTags = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CleanChatLogTags", false, "Clean TMP tags from chat content e.g. remove <#ff0000> in the chat log.");
			GlobalMessageLimitCount = ((BaseUnityPlugin)this).Config.Bind<int>("Chat", "GlobalMessageLimitCount", DefaultGlobalChatMessageLimit, "Max number of messages shown in the global chat window. Game default is 50.");
			LocalMessageLimitCount = ((BaseUnityPlugin)this).Config.Bind<int>("Chat", "LocalMessageLimitCount", DefaultLocalChatMessageLimit, "Max number of messages shown in the local chat window. Game default is 25.");
			ChatLogLocalRange = ((BaseUnityPlugin)this).Config.Bind<int>("Chat", "ChatLogLocalRange", DefaultChatLogLocalRange, "Local range for chat log messages.");
		}
	}
}
namespace Fomo.Patches
{
	[HarmonyPatch(typeof(GameSettings))]
	public class GameSettingsPatch
	{
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		public static void GlobalMessageLimitCountPostfix(ref int __result)
		{
			int num = Plugin.GlobalMessageLimitCount?.Value ?? __result;
			if (num > 0)
			{
				__result = num;
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		public static void LocalMessageLimitCountPostfix(ref int __result)
		{
			int num = Plugin.LocalMessageLimitCount?.Value ?? __result;
			if (num > 0)
			{
				__result = num;
			}
		}
	}
	[HarmonyPatch(typeof(TextChannelManager))]
	public class TextChannelManagerPatch
	{
		private static ManualLogSource Logger = Logger.CreateLogSource("Fomo.TextChannelManagerPatch");

		private static readonly int ChatLogWarnLimit = 7;

		private static int ChatLogWarnCount = 0;

		[HarmonyPatch("OnChannelMessageReceived", new Type[]
		{
			typeof(string),
			typeof(string),
			typeof(Vector3),
			typeof(bool),
			typeof(int),
			typeof(string)
		})]
		[HarmonyPostfix]
		public static void OnChannelMessageReceivedPostfix(string userName, string message, Vector3 senderPosition, bool isLocal, int senderIndex, string playerID)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<bool>? enableChatFileLogging = Plugin.EnableChatFileLogging;
			if (enableChatFileLogging == null || !enableChatFileLogging.Value || MonoSingleton<DataManager>.I.BanData.IgnorePlayers.Contains(playerID) || MonoSingleton<DataManager>.I.BanData.MutedPlayers.Contains(playerID))
			{
				return;
			}
			string text;
			if (isLocal)
			{
				float num = Vector3.Distance(senderPosition, NetworkSingleton<TextChannelManager>.I.MainPlayer.position);
				int num2 = Plugin.ChatLogLocalRange?.Value ?? Plugin.DefaultChatLogLocalRange;
				if (num > (float)num2)
				{
					return;
				}
				text = "Local:" + num.ToString("0");
			}
			else
			{
				text = "Global";
			}
			try
			{
				string text2 = ChatUtils.CleanTMPTags(userName);
				ConfigEntry<bool>? cleanChatLogTags = Plugin.CleanChatLogTags;
				string text4;
				if (cleanChatLogTags != null && cleanChatLogTags.Value)
				{
					string text3 = ChatUtils.CleanTMPTags(message);
					text4 = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{text}] {text2}: {text3}";
				}
				else
				{
					text4 = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{text}] {text2}: {message}";
				}
				File.AppendAllTextAsync(Plugin.getChatLogPath(), text4 + Environment.NewLine);
			}
			catch (Exception ex)
			{
				LogWriterIssue(ex);
			}
		}

		private static void LogWriterIssue(Exception ex)
		{
			ChatLogWarnCount++;
			if (ChatLogWarnCount <= ChatLogWarnLimit)
			{
				Logger.LogWarning((object)("Failed to write chat log: " + ex.Message));
			}
			else if (ChatLogWarnCount == ChatLogWarnLimit + 1)
			{
				Logger.LogWarning((object)"Further warnings about chat log writing will be suppressed.");
			}
		}

		[HarmonyPatch("OnEnterPressed")]
		[HarmonyPrefix]
		public static void OnEnterPressedPrefix()
		{
			string text = MonoSingleton<UIManager>.I.MessageInput.text;
			if (!string.IsNullOrEmpty(text) && text.StartsWith('/') && Plugin.EnableFeature != null && (Plugin.EnableFeature.Value || text.Contains("fomotoggle")))
			{
				bool flag = Plugin.CommandProcessor?.ProcessInput(text) ?? false;
				ConfigEntry<bool>? showCommand = Plugin.ShowCommand;
				if (showCommand != null && !showCommand.Value && flag)
				{
					ChatUtils.CleanCommand();
				}
			}
		}
	}
}
namespace Fomo.Core
{
	public class CommandArgs
	{
		public static readonly CommandArgs EMPTY = new CommandArgs("", new string[0]);

		public string Name { get; }

		public string[] Args { get; }

		public CommandArgs(string name, string[] args)
		{
			Name = name;
			Args = args;
		}

		public static bool TryParse(string input, out CommandArgs result)
		{
			if (string.IsNullOrWhiteSpace(input) || !input.StartsWith('/'))
			{
				result = EMPTY;
				return false;
			}
			string text = input.Trim();
			string[] array = text.Substring(1, text.Length - 1).Split(' ', StringSplitOptions.RemoveEmptyEntries);
			string name = array[0].ToLower();
			string[] args = array.Skip(1).ToArray();
			result = new CommandArgs(name, args);
			return true;
		}

		public override string ToString()
		{
			return "/" + Name + " " + string.Join(' ', Args);
		}
	}
	public class CommandManager
	{
		private readonly ManualLogSource log = Logger.CreateLogSource("Fomo");

		private readonly Dictionary<string, IChatCommand> commands;

		public CommandManager()
		{
			IEnumerable<Type> enumerable = from t in Assembly.GetExecutingAssembly().GetTypes()
				where typeof(IChatCommand).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract
				select t;
			commands = new Dictionary<string, IChatCommand>();
			foreach (Type item in enumerable)
			{
				if (Activator.CreateInstance(item) is IChatCommand chatCommand)
				{
					commands[chatCommand.Name] = chatCommand;
					commands[chatCommand.ShortName] = chatCommand;
					log.LogInfo((object)("Loaded /" + chatCommand.Name + " (/" + chatCommand.ShortName + ")"));
				}
			}
			InitializeHelpCommand(commands);
		}

		private static void InitializeHelpCommand(Dictionary<string, IChatCommand> commands)
		{
			if (commands.TryGetValue("fomohelp", out IChatCommand value))
			{
				(value as FomoHelpCommand)?.Initialize(commands.Values);
			}
			if (commands.TryGetValue("help", out IChatCommand value2))
			{
				(value2 as HelpCommand)?.Initialize(commands.Values);
			}
		}

		public bool ProcessInput(string input)
		{
			if (!CommandArgs.TryParse(input, out CommandArgs result))
			{
				return false;
			}
			if (commands.TryGetValue(result.Name, out IChatCommand value))
			{
				try
				{
					value.Execute(result.Args);
				}
				catch (Exception ex)
				{
					ChatUtils.AddGlobalNotification($"Error executing '{result}': {ex.Message}");
				}
				return true;
			}
			return false;
		}
	}
}
namespace Fomo.Core.Commands
{
	public class FomoCleanChatLogTagsCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomocleanchatlogtags";

		public string Name => "fomocleanchatlogtags";

		public string ShortName => "fcclt";

		public string Description
		{
			get
			{
				ConfigEntry<bool>? cleanChatLogTags = Plugin.CleanChatLogTags;
				return "Toggle cleaning TMP tags in the chat log e.g. <noparse><#ff0000></noparse>. Currently: " + ((cleanChatLogTags != null && cleanChatLogTags.Value) ? "enabled" : "disabled") + ". Usage: /fomocleanchatlogtags";
			}
		}

		public void Execute(string[] args)
		{
			if (Plugin.CleanChatLogTags != null)
			{
				Plugin.CleanChatLogTags.Value = !Plugin.CleanChatLogTags.Value;
				ChatUtils.AddGlobalNotification("Cleaning TMP tags in chat log is now " + (Plugin.CleanChatLogTags.Value ? "enabled" : "disabled") + ".");
			}
		}
	}
	public class FomoGetChatLogLocalRangeCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomogetchatloglocalrange";

		public string Name => "fomogetchatloglocalrange";

		public string ShortName => "fgcllr";

		public string Description => "Get the local range for the chat log.";

		public void Execute(string[] args)
		{
			if (Plugin.ChatLogLocalRange == null)
			{
				ChatUtils.AddGlobalNotification($"Chat log local range is currently set to {Plugin.DefaultChatLogLocalRange}.");
			}
			else
			{
				ChatUtils.AddGlobalNotification($"Chat log local range is currently set to {Plugin.ChatLogLocalRange.Value}.");
			}
		}
	}
	public class FomoGetChatLogPathCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomogetchatlogpath";

		public string Name => "fomogetchatlogpath";

		public string ShortName => "fgclp";

		public string Description => "Get the path for the chat log file.";

		public void Execute(string[] args)
		{
			ChatUtils.AddGlobalNotification("Chat log path: " + Plugin.getChatLogPath());
		}
	}
	public class FomoHelpCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomohelp";

		private SortedSet<IChatCommand>? commands;

		public string Name => "fomohelp";

		public string ShortName => "fh";

		public string Description => "Lists all available commands.";

		public void Initialize(IEnumerable<IChatCommand> values)
		{
			commands = new SortedSet<IChatCommand>(values);
		}

		public void Execute(string[] args)
		{
			if (commands == null)
			{
				ChatUtils.AddGlobalNotification("No commands available!");
				return;
			}
			ChatUtils.AddGlobalNotification("Fomo Version (0.0.6).");
			ChatUtils.AddGlobalNotification("Available commands:");
			foreach (IChatCommand command in commands)
			{
				ChatUtils.AddGlobalNotification("/" + command.Name + " (/" + command.ShortName + ") :: " + command.Description);
			}
		}
	}
	public class FomoSetChatLogLocalRangeCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomosetchatloglocalrange";

		public string Name => "fomosetchatloglocalrange";

		public string ShortName => "fscllr";

		public string Description => "Set local range for the chat log. Current: " + (Plugin.ChatLogLocalRange?.Value ?? Plugin.DefaultChatLogLocalRange);

		public void Execute(string[] args)
		{
			int result;
			if (Plugin.ChatLogLocalRange == null)
			{
				ChatUtils.AddGlobalNotification("Chat log local range config is not initialized yet.");
			}
			else if (args.Length < 1)
			{
				Plugin.ChatLogLocalRange.Value = Plugin.DefaultChatLogLocalRange;
				ChatUtils.AddGlobalNotification($"Chat log local range is now set to default: {Plugin.DefaultChatLogLocalRange}.");
			}
			else if (!int.TryParse(args[0], out result) || result <= 0)
			{
				ChatUtils.AddGlobalNotification("Please enter a valid local range value.");
			}
			else
			{
				Plugin.ChatLogLocalRange.Value = result;
				ChatUtils.AddGlobalNotification($"Chat log local range is now set to {result}.");
			}
		}
	}
	public class FomoSetChatLogPathCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomosetchatlogpath";

		public string Name => "fomosetchatlogpath";

		public string ShortName => "fsclp";

		public string Description => "Set the path for the chat log file. Current: " + Plugin.getChatLogPath() + ". Usage: /fomosetchatlogpath <path>. Example: /fomosetchatlogpath C:\\Logs\\chat.log";

		public void Execute(string[] args)
		{
			if (args.Length < 1)
			{
				ChatUtils.AddGlobalNotification("Usage: /fomosetchatlogpath <path>. Example: /fomosetchatlogpath C:\\Logs\\chat.log");
				return;
			}
			string text = args[0];
			if (string.IsNullOrWhiteSpace(text))
			{
				ChatUtils.AddGlobalNotification("Please enter a valid path.");
				return;
			}
			Plugin.setChatLogPath(text);
			try
			{
				string text2 = Path.GetDirectoryName(text) ?? string.Empty;
				if (!string.IsNullOrEmpty(text2) && !Directory.Exists(text2))
				{
					Directory.CreateDirectory(text2);
				}
			}
			catch (Exception ex)
			{
				ChatUtils.AddGlobalNotification("Failed to create directory for the new chat log path: " + ex.Message);
				return;
			}
			ChatUtils.AddGlobalNotification("Chat log path is now set to " + text + ". This change applies next restart.");
		}
	}
	public class FomoSetMessageLimitCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomosetmessagelimit";

		public string Name => "fomosetmessagelimit";

		public string ShortName => "fsml";

		public string Description => "Set the global or local chat message window size. Usage: /fomosetmessagelimit [global|local] [number]. " + $"Current: global={Plugin.GlobalMessageLimitCount?.Value}, local={Plugin.LocalMessageLimitCount?.Value}";

		public void Execute(string[] args)
		{
			if (Plugin.GlobalMessageLimitCount == null || Plugin.LocalMessageLimitCount == null)
			{
				return;
			}
			if (args.Length != 2)
			{
				ChatUtils.AddGlobalNotification("Usage: /fomosetmessagelimit [global|local] [number]");
				return;
			}
			string text = args[0].ToLower();
			if (!int.TryParse(args[1], out var result) || result <= 0)
			{
				ChatUtils.AddGlobalNotification("Invalid number. Please enter a positive integer.");
			}
			else if (text == "global")
			{
				Plugin.GlobalMessageLimitCount.Value = result;
				ChatUtils.AddGlobalNotification($"Global message limit set to {result}.");
			}
			else if (text == "local")
			{
				Plugin.LocalMessageLimitCount.Value = result;
				ChatUtils.AddGlobalNotification($"Local message limit set to {result}.");
			}
			else
			{
				ChatUtils.AddGlobalNotification("Unknown type '" + text + "'. Use 'global' or 'local'.");
			}
		}
	}
	public class ShowFomoCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomoshowcommand";

		public string Name => "fomoshowcommand";

		public string ShortName => "fsc";

		public string Description
		{
			get
			{
				ConfigEntry<bool>? showCommand = Plugin.ShowCommand;
				return "Toggle Fomo show/hide Fomo command in chat.If enabled, user command such as '/roll' will be shown in chat. Current: " + ((showCommand != null && showCommand.Value) ? "shown" : "hidden");
			}
		}

		public void Execute(string[] args)
		{
			if (Plugin.ShowCommand != null)
			{
				Plugin.ShowCommand.Value = !Plugin.ShowCommand.Value;
				ChatUtils.AddGlobalNotification("Fomo user command is now " + (Plugin.ShowCommand.Value ? "shown" : "hidden") + ".");
			}
		}
	}
	public class FomoToggleCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomotoggle";

		public string Name => "fomotoggle";

		public string ShortName => "ft";

		public string Description => "Toggle Fomo feature on/off. ";

		public void Execute(string[] args)
		{
			if (Plugin.EnableFeature != null)
			{
				Plugin.EnableFeature.Value = !Plugin.EnableFeature.Value;
				ChatUtils.AddGlobalNotification("Fomo feature is now " + (Plugin.EnableFeature.Value ? "enabled" : "disabled") + ".");
			}
		}
	}
	public class FomoUseChatLogCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomousechatlog";

		public string Name => "fomousechatlog";

		public string ShortName => "fucl";

		public string Description
		{
			get
			{
				ConfigEntry<bool>? enableChatFileLogging = Plugin.EnableChatFileLogging;
				return "Toggle Fomo chat log on/off. Currently: " + ((enableChatFileLogging != null && enableChatFileLogging.Value) ? "enabled" : "disabled") + ". Usage: /fomousechatlog";
			}
		}

		public void Execute(string[] args)
		{
			if (Plugin.EnableChatFileLogging != null)
			{
				Plugin.EnableChatFileLogging.Value = !Plugin.EnableChatFileLogging.Value;
				ChatUtils.AddGlobalNotification("Fomo chat log is now " + (Plugin.EnableChatFileLogging.Value ? "enabled" : "disabled") + ".");
			}
		}
	}
	public class HelpCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "help";

		private SortedSet<IChatCommand>? commands;

		public string Name => "help";

		public string ShortName => "h";

		public string Description => "Lists all available commands.";

		public void Initialize(IEnumerable<IChatCommand> values)
		{
			commands = new SortedSet<IChatCommand>(values);
		}

		public void Execute(string[] args)
		{
			if (args.Length == 0)
			{
				ChatUtils.AddGlobalNotification("/help fomo for Fomo commands");
			}
			else
			{
				if (!(args[0] == "fomo"))
				{
					return;
				}
				if (commands != null)
				{
					ChatUtils.AddGlobalNotification("Fomo Version (0.0.6).");
					ChatUtils.AddGlobalNotification("Available commands:");
					{
						foreach (IChatCommand command in commands)
						{
							ChatUtils.AddGlobalNotification("/" + command.Name + " (/" + command.ShortName + ") :: " + command.Description);
						}
						return;
					}
				}
				ChatUtils.AddGlobalNotification("No commands available!");
			}
		}
	}
	public interface IChatCommand : IComparable<IChatCommand>
	{
		string Name { get; }

		string ShortName => "";

		string Description { get; }

		void Execute(string[] args);

		new string ToString()
		{
			return Name;
		}

		int IComparable<IChatCommand>.CompareTo(IChatCommand? other)
		{
			if (other == null)
			{
				return 1;
			}
			return string.Compare(Name, other.Name, StringComparison.Ordinal);
		}
	}
}