Decompiled source of DiscordBot v1.0.0

DiscordBot.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using ServerSync;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyProduct("DiscordBot")]
[assembly: AssemblyCompany("RustyMods")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("DiscordBot")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyConfiguration("")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<1863e386-205e-4925-b386-c4d06fe873e9>Embedded]
	internal sealed class <1863e386-205e-4925-b386-c4d06fe873e9>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[<1863e386-205e-4925-b386-c4d06fe873e9>Embedded]
	[CompilerGenerated]
	internal sealed class <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[<1863e386-205e-4925-b386-c4d06fe873e9>Embedded]
	[CompilerGenerated]
	internal sealed class <2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace DiscordBot
{
	[BepInPlugin("RustyMods.DiscordBot", "DiscordBot", "1.0.0")]
	[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
	[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
	public class DiscordBotPlugin : BaseUnityPlugin
	{
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public enum Webhook
		{
			Notifications,
			Chat,
			Commands
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public enum Channel
		{
			Chat,
			Commands
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public enum ChatDisplay
		{
			Player,
			Bot
		}

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class StringListConfig
		{
			public readonly List<string> list;

			public StringListConfig(List<string> items)
			{
				list = items;
			}

			public StringListConfig(string items)
			{
				list = items.Split(new char[1] { ',' }).ToList();
			}

			public static void Draw(ConfigEntryBase cfg)
			{
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Expected O, but got Unknown
				//IL_0132: Unknown result type (might be due to invalid IL or missing references)
				//IL_0137: Unknown result type (might be due to invalid IL or missing references)
				//IL_014d: Expected O, but got Unknown
				bool valueOrDefault = cfg.Description.Tags.Select([<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : null).FirstOrDefault((bool? v) => v.HasValue).GetValueOrDefault();
				bool flag = false;
				List<string> list = new List<string>();
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				foreach (string item2 in new StringListConfig((string)cfg.BoxedValue).list)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string item = item2;
					string text = GUILayout.TextField(item2, Array.Empty<GUILayoutOption>());
					if (text != item2 && !valueOrDefault)
					{
						flag = true;
						item = text;
					}
					if (GUILayout.Button("x", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault)
					{
						flag = true;
					}
					else
					{
						list.Add(item);
					}
					if (GUILayout.Button("+", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault)
					{
						list.Add("");
						flag = true;
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
				if (flag)
				{
					cfg.BoxedValue = new StringListConfig(list).ToString();
				}
			}

			public override string ToString()
			{
				return string.Join(",", list);
			}
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order = null;

			[UsedImplicitly]
			public bool? Browsable = null;

			[UsedImplicitly]
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)]
			public string Category = null;

			[UsedImplicitly]
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public Action<ConfigEntryBase> CustomDrawer = null;
		}

		internal const string ModName = "DiscordBot";

		internal const string ModVersion = "1.0.0";

		internal const string Author = "RustyMods";

		private const string ModGUID = "RustyMods.DiscordBot";

		private static readonly string ConfigFileName = "RustyMods.DiscordBot.cfg";

		private static readonly string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("RustyMods.DiscordBot");

		public static readonly ManualLogSource DiscordBotLogger;

		private static readonly ConfigSync ConfigSync;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		public static DiscordBotPlugin m_instance;

		public static ConfigEntry<string> m_notificationWebhookURL;

		public static ConfigEntry<Toggle> m_serverStartNotice;

		public static ConfigEntry<Toggle> m_serverStopNotice;

		public static ConfigEntry<Toggle> m_serverSaveNotice;

		public static ConfigEntry<Toggle> m_deathNotice;

		public static ConfigEntry<Toggle> m_loginNotice;

		public static ConfigEntry<Toggle> m_logoutNotice;

		public static ConfigEntry<string> m_chatWebhookURL;

		public static ConfigEntry<string> m_chatChannelID;

		public static ConfigEntry<Toggle> m_chatEnabled;

		public static ConfigEntry<ChatDisplay> m_chatType;

		public static ConfigEntry<string> m_commandWebhookURL;

		public static ConfigEntry<string> m_commandChannelID;

		public static ConfigEntry<int> m_pollInterval;

		public static ConfigEntry<string> m_discordAdmins;

		public static ConfigEntry<Toggle> m_logErrors;

		public static ConfigEntry<string> m_botToken;

		public static string GetWebhookURL(Webhook type)
		{
			if (1 == 0)
			{
			}
			string result = type switch
			{
				Webhook.Chat => m_chatWebhookURL.Value, 
				Webhook.Notifications => m_notificationWebhookURL.Value, 
				Webhook.Commands => m_commandWebhookURL.Value, 
				_ => m_chatWebhookURL.Value, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static string GetChannelID(Channel type)
		{
			if (1 == 0)
			{
			}
			string result = type switch
			{
				Channel.Chat => m_chatChannelID.Value, 
				Channel.Commands => m_commandChannelID.Value, 
				_ => m_chatChannelID.Value, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public void Awake()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Expected O, but got Unknown
			Localizer.Load();
			m_instance = this;
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			m_pollInterval = config("1 - General", "Poll Interval", 5, new ConfigDescription("Set interval between check for messages in discord, in seconds", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 300), Array.Empty<object>()));
			m_logErrors = config("1 - General", "Log Errors", Toggle.Off, "If on, errors will log to console as warnings");
			m_notificationWebhookURL = config("2 - Notifications", "Webhook URL", "", "Set webhook to receive notifications, like server start, stop, save etc...");
			m_serverStartNotice = config("2 - Notifications", "Startup", Toggle.On, "If on, bot will send message when server is starting");
			m_serverStopNotice = config("2 - Notifications", "Shutdown", Toggle.On, "If on, bot will send message when server is shutting down");
			m_serverSaveNotice = config("2 - Notifications", "Saving", Toggle.On, "If on, bot will send message when server is saving");
			m_deathNotice = config("2 - Notifications", "On Death", Toggle.On, "If on, bot will send message when player dies");
			m_loginNotice = config("2 - Notifications", "Login", Toggle.On, "If on, bot will send message when player logs in");
			m_logoutNotice = config("2 - Notifications", "Logout", Toggle.On, "If on, bot will send message when player logs out");
			m_chatWebhookURL = config("3 - Chat", "Webhook URL", "", "Set discord webhook to display chat messages");
			m_chatChannelID = config("3 - Chat", "Channel ID", "", "Set channel ID to monitor for messages");
			m_chatEnabled = config("3 - Chat", "Enabled", Toggle.On, "If on, bot will send message when player shouts and monitor discord for messages");
			m_chatType = config("3 - Chat", "Display As", ChatDisplay.Player, "Set how chat messages appear, if Player, message sent by player, else sent by bot with a prefix that player is saying");
			m_commandWebhookURL = config("4 - Commands", "Webhook URL", "", "Set discord webhook to display feedback messages from commands");
			m_commandChannelID = config("4 - Commands", "Channel ID", "", "Set channel ID to monitor for input commands");
			m_discordAdmins = config("4 - Commands", "Discord Admin", "", new ConfigDescription("List of discord admins, who can run commands", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_botToken = config("5 - Setup", "BOT TOKEN", "", "Add bot token here, server only", synchronizedSetting: false);
			DiscordCommands.Setup();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				DiscordBotLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				DiscordBotLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				DiscordBotLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private ConfigEntry<T> config<[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2);
			syncedConfigEntry.SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		public ConfigEntry<T> config<[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		static DiscordBotPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			DiscordBotLogger = Logger.CreateLogSource("DiscordBot");
			ConfigSync = new ConfigSync("RustyMods.DiscordBot")
			{
				DisplayName = "DiscordBot",
				CurrentVersion = "1.0.0",
				MinimumRequiredVersion = "1.0.0"
			};
			_serverConfigLocked = null;
			m_instance = null;
			m_notificationWebhookURL = null;
			m_serverStartNotice = null;
			m_serverStopNotice = null;
			m_serverSaveNotice = null;
			m_deathNotice = null;
			m_loginNotice = null;
			m_logoutNotice = null;
			m_chatWebhookURL = null;
			m_chatChannelID = null;
			m_chatEnabled = null;
			m_chatType = null;
			m_commandWebhookURL = null;
			m_commandChannelID = null;
			m_pollInterval = null;
			m_discordAdmins = null;
			m_logErrors = null;
			m_botToken = null;
		}
	}
	[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
	[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
	public class ImageHud : MonoBehaviour
	{
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		[HarmonyPatch(typeof(Tutorial), "Awake")]
		private static class Tutorial_Awake_Patch
		{
			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			[UsedImplicitly]
			private static void Postfix(Tutorial __instance)
			{
				if (!m_loaded)
				{
					GameObject val = Object.Instantiate<GameObject>(((Component)((Component)__instance).transform.Find("Tutorial_wnd")).gameObject, ((Component)__instance).transform.parent);
					((Object)val).name = "DiscordImage";
					val.AddComponent<ImageHud>();
					Canvas val2 = val.AddComponent<Canvas>();
					val2.renderMode = (RenderMode)0;
					val.SetActive(true);
					m_loaded = true;
				}
			}
		}

		private static bool m_loaded;

		public static ImageHud instance;

		public RectTransform m_rect;

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(1)]
		public Image m_bkg = null;

		public TMP_Text m_topic;

		public TMP_Text m_text;

		public TMP_Text m_closedText;

		private readonly float m_fadeDuration = 0.5f;

		private bool m_fading = false;

		private Color m_currentColor = Color.clear;

		private Color m_targetColor = Color.clear;

		public void Awake()
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			instance = this;
			m_rect = ((Component)this).GetComponent<RectTransform>();
			m_bkg = ((Component)((Component)this).transform.Find("bkg")).GetComponent<Image>();
			m_topic = ((Component)((Component)this).transform.Find("Topic")).GetComponent<TMP_Text>();
			m_text = ((Component)((Component)this).transform.Find("Text")).GetComponent<TMP_Text>();
			m_closedText = ((Component)((Component)this).transform.Find("CloseText")).GetComponent<TMP_Text>();
			((Component)m_topic).gameObject.SetActive(false);
			((Component)m_text).gameObject.SetActive(false);
			((Component)m_closedText).gameObject.SetActive(false);
			m_bkg.preserveAspect = true;
			m_bkg.type = (Type)0;
			((Graphic)m_bkg).color = Color.clear;
		}

		public void Update()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			if (!m_fading)
			{
				return;
			}
			m_currentColor = Color.Lerp(m_currentColor, m_targetColor, Time.deltaTime / m_fadeDuration);
			((Graphic)m_bkg).color = m_currentColor;
			if (Mathf.Abs(m_currentColor.a - m_targetColor.a) < 0.01f)
			{
				m_currentColor = m_targetColor;
				((Graphic)m_bkg).color = m_targetColor;
				m_targetColor = Color.clear;
				if (m_currentColor == Color.clear)
				{
					m_fading = false;
				}
			}
		}

		public void OnDestroy()
		{
			instance = null;
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
		public void ShowInstant(Sprite image)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			m_bkg.sprite = image;
			m_currentColor = Color.white;
			((Graphic)m_bkg).color = Color.white;
			((MonoBehaviour)this).Invoke("StartFadeOut", 0.5f);
		}

		private void StartFadeOut()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			m_targetColor = Color.clear;
			m_fading = true;
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
		public void Show(Sprite image)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			m_bkg.sprite = image;
			m_targetColor = Color.white;
			m_fading = true;
		}

		public void Hide()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			m_targetColor = Color.clear;
			m_fading = true;
		}
	}
	[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
	[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
	public static class DiscordCommands
	{
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class ZNet_OnNewConnection_Patch
		{
			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			private static void Postfix(ZNetPeer peer)
			{
				peer.m_rpc.Register<ZPackage>("RPC_BotToClient", (Action<ZRpc, ZPackage>)RPC_BotToClient);
			}
		}

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class DiscordCommand
		{
			[Description("Action runs when Discord component receives a new command")]
			private readonly Action<string[]> m_action;

			[Description("Action runs when player receives package from RPC_BotToClient")]
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			private readonly Action<ZPackage> m_reaction;

			[Description("If only discord admins are allowed to run command")]
			private readonly bool m_adminOnly;

			[Description("Register a new discord command")]
			public DiscordCommand(string command, string description, Action<string[]> action, [<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })] Action<ZPackage> reaction = null, bool adminOnly = false, bool isSecret = false, string emoji = "")
			{
				m_action = action;
				m_reaction = reaction;
				m_adminOnly = adminOnly;
				m_commands[command] = this;
				if (!isSecret)
				{
					CommandTooltip commandTooltip = new CommandTooltip(command, description, adminOnly, emoji);
				}
			}

			public bool IsAllowed(string discordUserName)
			{
				return !m_adminOnly || new DiscordBotPlugin.StringListConfig(DiscordBotPlugin.m_discordAdmins.Value).list.Contains(discordUserName);
			}

			public void Run(string[] args)
			{
				m_action(args);
			}

			public void Run(ZPackage pkg)
			{
				m_reaction?.Invoke(pkg);
			}
		}

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class CommandTooltip
		{
			public readonly string m_command;

			public readonly string m_description;

			public readonly bool m_adminOnly;

			public CommandTooltip(string command, string description, bool adminOnly, string emoji)
			{
				m_command = BuildCommandKey(command, emoji);
				m_description = description;
				m_adminOnly = adminOnly;
				m_tooltips.Add(this);
			}

			private static string BuildCommandKey(string command, string emoji)
			{
				string text = (string.IsNullOrEmpty(emoji) ? "" : (EmojiHelper.Emoji(emoji) + " "));
				return text + "`" + command + "`";
			}
		}

		public static readonly Dictionary<string, DiscordCommand> m_commands = new Dictionary<string, DiscordCommand>();

		private static readonly List<CommandTooltip> m_tooltips = new List<CommandTooltip>();

		public static void Setup()
		{
			DiscordCommand discordCommand = new DiscordCommand("!help", "List of commands", delegate
			{
				List<CommandTooltip> list = new List<CommandTooltip>();
				List<CommandTooltip> list2 = new List<CommandTooltip>();
				foreach (CommandTooltip tooltip in m_tooltips)
				{
					if (tooltip.m_adminOnly)
					{
						list.Add(tooltip);
					}
					else
					{
						list2.Add(tooltip);
					}
				}
				if (list.Count > 25)
				{
					int num9 = (int)Math.Ceiling((double)list.Count / 25.0);
					for (int i = 0; i < num9; i++)
					{
						Dictionary<string, string> tableData = list.Skip(i * 25).Take(25).ToDictionary([<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_command, [<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_description);
						string title = ((num9 == 1) ? "List of admin commands" : $"List of admin commands (Part {i + 1} of {num9}");
						Discord.instance.SendTableEmbed(DiscordBotPlugin.Webhook.Commands, title, tableData);
					}
				}
				else
				{
					Discord.instance.SendTableEmbed(DiscordBotPlugin.Webhook.Commands, "List of admin commands", list.ToDictionary([<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_command, [<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_description));
				}
				if (list2.Count > 25)
				{
					int num10 = (int)Math.Ceiling((double)list2.Count / 25.0);
					for (int j = 0; j < num10; j++)
					{
						Dictionary<string, string> tableData2 = list2.Skip(j * 25).Take(25).ToDictionary([<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_command, [<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_description);
						string title2 = ((num10 == 1) ? "List of commands" : $"List of commands (Part {j + 1} of {num10}");
						Discord.instance.SendTableEmbed(DiscordBotPlugin.Webhook.Commands, title2, tableData2);
					}
				}
				else
				{
					Discord.instance.SendTableEmbed(DiscordBotPlugin.Webhook.Commands, "List of commands", list2.ToDictionary([<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_command, [<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (CommandTooltip command) => command.m_description));
				}
			}, null, adminOnly: false, isSecret: false, "question");
			DiscordCommand listAdmins = new DiscordCommand("!listadmins", "List of discord admins registered to plugin", delegate
			{
				StringBuilder stringBuilder13 = new StringBuilder();
				foreach (string item3 in new DiscordBotPlugin.StringListConfig(DiscordBotPlugin.m_discordAdmins.Value).list)
				{
					stringBuilder13.Append("`" + item3 + "`\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "List of discord usernames who can use commands:", stringBuilder13.ToString());
			}, null, adminOnly: false, isSecret: false, "warning");
			DiscordCommand discordCommand2 = new DiscordCommand("!addadmin", "Adds discord username to admin list, to enable using commands, `username`", delegate(string[] args)
			{
				if (args.Length >= 2)
				{
					string item2 = args[1].Trim();
					DiscordBotPlugin.StringListConfig stringListConfig2 = new DiscordBotPlugin.StringListConfig(DiscordBotPlugin.m_discordAdmins.Value)
					{
						list = { item2 }
					};
					DiscordBotPlugin.m_discordAdmins.Value = stringListConfig2.ToString();
					listAdmins.Run(new string[1] { "listadmins" });
				}
			}, null, adminOnly: true, isSecret: false, "key");
			DiscordCommand discordCommand3 = new DiscordCommand("!removeadmin", "Remove discord username from admin list, to disable using commands, `username`", delegate(string[] args)
			{
				string item = args[1].Trim();
				DiscordBotPlugin.StringListConfig stringListConfig = new DiscordBotPlugin.StringListConfig(DiscordBotPlugin.m_discordAdmins.Value);
				stringListConfig.list.Remove(item);
				DiscordBotPlugin.m_discordAdmins.Value = stringListConfig.ToString();
				listAdmins.Run(new string[1] { "listadmins" });
			}, null, adminOnly: true, isSecret: false, "lock");
			DiscordCommand discordCommand4 = new DiscordCommand("!listenv", "List of available environments", delegate
			{
				StringBuilder stringBuilder12 = new StringBuilder();
				foreach (EnvSetup environment in EnvMan.instance.m_environments)
				{
					stringBuilder12.Append("`" + environment.m_name + "`\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "List of available environments:", stringBuilder12.ToString());
			}, null, adminOnly: false, isSecret: false, "tornado");
			DiscordCommand discordCommand5 = new DiscordCommand("!env", "Force environment on all players", delegate(string[] args)
			{
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Expected O, but got Unknown
				if (args.Length >= 2)
				{
					string text28 = args[1].Trim();
					EnvSetup env = EnvMan.instance.GetEnv(text28);
					if (env != null)
					{
						ZPackage val21 = new ZPackage();
						val21.Write("!env");
						val21.Write(text28);
						foreach (ZNetPeer peer in ZNet.instance.GetPeers())
						{
							peer.m_rpc.Invoke("RPC_BotToClient", new object[1] { val21 });
						}
						if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
						{
							EnvMan.instance.m_debugEnv = text28;
						}
					}
					else
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find environment: " + text28);
					}
				}
			}, delegate(ZPackage pkg)
			{
				string debugEnv = pkg.ReadString();
				EnvMan.instance.m_debugEnv = debugEnv;
			}, adminOnly: true, isSecret: false, "sparkle");
			DiscordCommand discordCommand6 = new DiscordCommand("!resetenv", "Reset environment on all players", delegate
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Expected O, but got Unknown
				ZPackage val20 = new ZPackage();
				val20.Write("!resetenv");
				foreach (ZNetPeer peer2 in ZNet.instance.GetPeers())
				{
					peer2.m_rpc.Invoke("RPC_BotToClient", new object[1] { val20 });
				}
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					EnvMan.instance.m_debugEnv = "";
				}
			}, delegate
			{
				EnvMan.instance.m_debugEnv = "";
			}, adminOnly: true, isSecret: false, "sparkle");
			DiscordCommand discordCommand7 = new DiscordCommand("!listplayers", "List of active players", delegate
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				foreach (PlayerInfo player in ZNet.instance.m_players)
				{
					dictionary[player.m_name] = $"Position: `{player.m_position.x} {player.m_position.y} {player.m_position.z}`";
				}
				Discord.instance.SendTableEmbed(DiscordBotPlugin.Webhook.Commands, "List of active players", dictionary);
			}, null, adminOnly: true, isSecret: false, "dragon");
			DiscordCommand discordCommand8 = new DiscordCommand("!kick", "Kicks player from server, `playername`", delegate(string[] args)
			{
				if (args.Length >= 2)
				{
					string text27 = args[1].Trim();
					ZNetPeer peerByPlayerName14 = ZNet.instance.GetPeerByPlayerName(text27);
					if (peerByPlayerName14 == null)
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find " + text27);
					}
					else
					{
						ZNet.instance.Disconnect(peerByPlayerName14);
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Kicked " + text27 + " from server !");
					}
				}
			}, null, adminOnly: true, isSecret: false, "x");
			DiscordCommand discordCommand9 = new DiscordCommand("!give", "Adds item directly into player inventory, `player name` `item name` `amount` `quality?` `variant?`", delegate(string[] args)
			{
				//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Expected O, but got Unknown
				if (args.Length >= 4)
				{
					string text25 = args[1].Trim();
					string text26 = args[2].Trim();
					int result16;
					int num6 = ((!int.TryParse(args[3].Trim(), out result16)) ? 1 : result16);
					int result17;
					int num7 = ((args.Length <= 4) ? 1 : ((!int.TryParse(args[4].Trim(), out result17)) ? 1 : result17));
					int result18;
					int num8 = ((args.Length > 5) ? (int.TryParse(args[5].Trim(), out result18) ? result18 : 0) : 0);
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text25)
					{
						GiveItem(text26, num6, num7, num8);
					}
					else
					{
						ZNetPeer peerByPlayerName13 = ZNet.instance.GetPeerByPlayerName(text25);
						if (peerByPlayerName13 != null)
						{
							ZPackage val19 = new ZPackage();
							val19.Write("!give");
							val19.Write(text26);
							val19.Write(num6);
							val19.Write(num7);
							val19.Write(num8);
							peerByPlayerName13.m_rpc.Invoke("RPC_BotToClient", new object[1] { val19 });
						}
						else
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find " + text25);
						}
					}
				}
			}, delegate(ZPackage pkg)
			{
				string itemName = pkg.ReadString();
				int amount = pkg.ReadInt();
				int quality = pkg.ReadInt();
				int variant = pkg.ReadInt();
				GiveItem(itemName, amount, quality, variant);
			}, adminOnly: true, isSecret: false, "gift");
			DiscordCommand discordCommand10 = new DiscordCommand("!teleportall", "Teleports all players to location, `x` `y` `z`", delegate(string[] args)
			{
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Expected O, but got Unknown
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length == 4)
				{
					if (float.TryParse(args[1].Trim(), out var result13) && float.TryParse(args[2].Trim(), out var result14) && float.TryParse(args[3].Trim(), out var result15))
					{
						Vector3 val17 = default(Vector3);
						((Vector3)(ref val17))..ctor(result13, result14, result15);
						ZPackage val18 = new ZPackage();
						val18.Write("!teleport");
						val18.Write("vector");
						val18.Write(val17);
						foreach (ZNetPeer peer3 in ZNet.instance.GetPeers())
						{
							peer3.m_rpc.Invoke("RPC_BotToClient", new object[1] { val18 });
						}
						if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
						{
							((Character)Player.m_localPlayer).TeleportTo(val17, Quaternion.identity, true);
						}
					}
					else
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Incorrect teleport all command format");
					}
				}
			}, null, adminOnly: true, isSecret: false, "golf");
			DiscordCommand discordCommand11 = new DiscordCommand("!teleport", "Teleport player to location, `player name` `bed` or `other player name` or `x` `y` `z`", delegate(string[] args)
			{
				//IL_012d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0132: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0155: Unknown result type (might be due to invalid IL or missing references)
				//IL_015a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Expected O, but got Unknown
				//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_021e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0225: Expected O, but got Unknown
				//IL_0241: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length >= 5)
				{
					string text23 = args[1].Trim();
					string text24 = args[2].Trim();
					if (text24 == "bed")
					{
						if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text23)
						{
							((Character)Player.m_localPlayer).TeleportTo(Game.instance.GetPlayerProfile().GetCustomSpawnPoint(), Quaternion.identity, true);
						}
						else
						{
							ZNetPeer peerByPlayerName10 = ZNet.instance.GetPeerByPlayerName(text23);
							if (peerByPlayerName10 != null)
							{
								ZPackage val14 = new ZPackage();
								val14.Write("!teleport");
								val14.Write("bed");
								peerByPlayerName10.m_rpc.Invoke("RPC_BotToClient", new object[1] { val14 });
							}
							else
							{
								Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find " + text23);
							}
						}
					}
					else
					{
						Vector3 val15 = default(Vector3);
						if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text24)
						{
							val15 = ((Component)Player.m_localPlayer).transform.position;
						}
						else
						{
							ZNetPeer peerByPlayerName11 = ZNet.instance.GetPeerByPlayerName(text24);
							if (peerByPlayerName11 != null)
							{
								val15 = peerByPlayerName11.m_refPos;
							}
							else
							{
								if (!float.TryParse(args[2].Trim(), out var result10) || !float.TryParse(args[3].Trim(), out var result11) || !float.TryParse(args[4].Trim(), out var result12))
								{
									Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Incorrect teleport command format");
									return;
								}
								((Vector3)(ref val15))..ctor(result10, result11, result12);
							}
						}
						if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text23)
						{
							((Character)Player.m_localPlayer).TeleportTo(val15, Quaternion.identity, true);
						}
						else
						{
							ZNetPeer peerByPlayerName12 = ZNet.instance.GetPeerByPlayerName(text23);
							if (peerByPlayerName12 != null)
							{
								ZPackage val16 = new ZPackage();
								val16.Write("!teleport");
								val16.Write("vector");
								val16.Write(val15);
								peerByPlayerName12.m_rpc.Invoke("RPC_BotToClient", new object[1] { val16 });
							}
							else
							{
								Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find " + text23);
							}
						}
					}
				}
			}, delegate(ZPackage pkg)
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				string text20 = pkg.ReadString();
				string text21 = text20;
				string text22 = text21;
				if (!(text22 == "bed"))
				{
					if (text22 == "vector")
					{
						Vector3 val13 = pkg.ReadVector3();
						((Character)Player.m_localPlayer).TeleportTo(val13, Quaternion.identity, true);
					}
				}
				else
				{
					Vector3 customSpawnPoint = Game.instance.GetPlayerProfile().GetCustomSpawnPoint();
					((Character)Player.m_localPlayer).TeleportTo(customSpawnPoint, Quaternion.identity, true);
				}
			}, adminOnly: true, isSecret: false, "run");
			DiscordCommand discordCommand12 = new DiscordCommand("!spawn", "spawns prefab at location, `prefab name` `level` `player name` or `x` `y` `z`", delegate(string[] args)
			{
				//IL_014b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_0199: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a0: Expected O, but got Unknown
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length >= 4)
				{
					string text18 = args[1].Trim();
					int result6;
					int num5 = ((!int.TryParse(args[2].Trim(), out result6)) ? 1 : result6);
					if (args.Length == 6)
					{
						if (!float.TryParse(args[3].Trim(), out var result7) || !float.TryParse(args[4].Trim(), out var result8) || !float.TryParse(args[5].Trim(), out var result9))
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Incorrect spawn command format");
						}
						else if (!ZoneSystem.instance.IsZoneLoaded(new Vector3(result7, result8, result9)))
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to spawn, location zone is not loaded!");
						}
						else if (!Spawn(text18, num5, new Vector3(result7, result8, result9)))
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to spawn: " + text18);
						}
					}
					else
					{
						string text19 = args[3].Trim();
						if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text19)
						{
							if (!Spawn(text18, num5, ((Component)Player.m_localPlayer).transform.position))
							{
								Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to spawn: " + text18);
							}
						}
						else
						{
							ZNetPeer peerByPlayerName9 = ZNet.instance.GetPeerByPlayerName(text19);
							if (peerByPlayerName9 != null)
							{
								ZPackage val12 = new ZPackage();
								val12.Write("!spawn");
								val12.Write(text18);
								val12.Write(num5);
								peerByPlayerName9.m_rpc.Invoke("RPC_BotToClient", new object[1] { val12 });
							}
							else
							{
								Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find " + text19);
							}
						}
					}
				}
			}, delegate(ZPackage pkg)
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				string prefabName = pkg.ReadString();
				int level = pkg.ReadInt();
				Spawn(prefabName, level, ((Component)Player.m_localPlayer).transform.position);
			}, adminOnly: true, isSecret: false, "exclamation");
			DiscordCommand discordCommand13 = new DiscordCommand("!save", "Save player profiles and world", delegate
			{
				ZNet.instance.Save(true, true, true);
			}, null, adminOnly: true, isSecret: false, "save");
			DiscordCommand discordCommand14 = new DiscordCommand("!message", "Broadcast message to all players which shows up center of screen", delegate(string[] args)
			{
				string text17 = string.Join(" ", args.Skip(1));
				MessageHud.instance.MessageAll((MessageType)2, text17);
			}, null, adminOnly: true, isSecret: false, "smile");
			DiscordCommand discordCommand15 = new DiscordCommand("!image", "Broadcast image to all players which takes over entire screen", delegate(string[] args)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Expected O, but got Unknown
				if (args.Length >= 2)
				{
					string text16 = args[1].Trim();
					ZPackage val11 = new ZPackage();
					val11.Write("!image");
					val11.Write(text16);
					foreach (ZNetPeer peer4 in ZNet.instance.GetPeers())
					{
						peer4.m_rpc.Invoke("RPC_BotToClient", new object[1] { val11 });
					}
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
					{
						Discord.instance.GetImage(text16);
					}
				}
			}, delegate(ZPackage pkg)
			{
				string imageUrl = pkg.ReadString();
				Discord.instance.GetImage(imageUrl);
			}, adminOnly: true, isSecret: false, "paint");
			DiscordCommand discordCommand16 = new DiscordCommand("!sleep", "Forced everyone to sleep", delegate
			{
				if (!EnvMan.instance.IsTimeSkipping() && (EnvMan.IsAfternoon() || EnvMan.IsNight()) && !(ZNet.instance.GetTimeSeconds() - Game.instance.m_lastSleepTime < 10.0))
				{
					EnvMan.instance.SkipToMorning();
					Game.instance.m_sleeping = true;
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "SleepStart", Array.Empty<object>());
				}
			}, null, adminOnly: true, isSecret: false, "moon");
			DiscordCommand discordCommand17 = new DiscordCommand("!listkeys", "List of global keys", delegate
			{
				StringBuilder stringBuilder11 = new StringBuilder();
				foreach (object value in Enum.GetValues(typeof(GlobalKeys)))
				{
					stringBuilder11.Append($"`{value}`\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "Global keys:", stringBuilder11.ToString());
			}, null, adminOnly: false, isSecret: false, "fox");
			DiscordCommand discordCommand18 = new DiscordCommand("!keys", "List of current global keys", delegate
			{
				StringBuilder stringBuilder10 = new StringBuilder();
				foreach (string globalKey in ZoneSystem.instance.GetGlobalKeys())
				{
					stringBuilder10.Append("`" + globalKey + "`\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "Active keys:", stringBuilder10.ToString());
			}, null, adminOnly: false, isSecret: false, "game");
			DiscordCommand discordCommand19 = new DiscordCommand("!setkey", "Set global key", delegate(string[] args)
			{
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length >= 2)
				{
					string text15 = args[1].Trim();
					if (!Enum.TryParse<GlobalKeys>(text15, ignoreCase: true, out GlobalKeys result5))
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find global key: " + text15);
					}
					else
					{
						ZoneSystem.instance.SetGlobalKey(result5);
					}
				}
			}, null, adminOnly: true, isSecret: false, "unicorn");
			DiscordCommand discordCommand20 = new DiscordCommand("!removekey", "Remove global key", delegate(string[] args)
			{
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length >= 2)
				{
					string text14 = args[1].Trim();
					if (!Enum.TryParse<GlobalKeys>(text14, ignoreCase: true, out GlobalKeys result4))
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find global key: " + text14);
					}
					else
					{
						ZoneSystem.instance.RemoveGlobalKey(result4);
					}
				}
			}, null, adminOnly: true, isSecret: false, "pencil");
			DiscordCommand discordCommand21 = new DiscordCommand("!listprefabs", "List of prefabs available to spawn, `filter`", delegate(string[] args)
			{
				string filter = ((args.Length > 1) ? args[1].Trim().ToLower() : "");
				StringBuilder stringBuilder9 = new StringBuilder();
				foreach (GameObject item4 in ZNetScene.instance.m_prefabs.Where([<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)] (GameObject x) => ((Object)x).name.ToLower().Contains(filter)))
				{
					stringBuilder9.Append("`" + ((Object)item4).name + "`\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "Prefab Names:", stringBuilder9.ToString());
			}, null, adminOnly: true, isSecret: false, "fire");
			DiscordCommand discordCommand22 = new DiscordCommand("!listevents", "List of available event names", delegate
			{
				StringBuilder stringBuilder8 = new StringBuilder();
				foreach (RandomEvent event2 in RandEventSystem.instance.m_events)
				{
					stringBuilder8.Append("`" + event2.m_name + "`\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "Available events:", stringBuilder8.ToString());
			}, null, adminOnly: true, isSecret: false, "moon");
			DiscordCommand discordCommand23 = new DiscordCommand("!event", "Starts an event on a player, `event name` `player name`", delegate(string[] args)
			{
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length >= 3)
				{
					string text12 = args[1].Trim();
					string text13 = args[2].Trim();
					Vector3 val10;
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text13)
					{
						val10 = ((Component)Player.m_localPlayer).transform.position;
					}
					else
					{
						ZNetPeer peerByPlayerName8 = ZNet.instance.GetPeerByPlayerName(text13);
						if (peerByPlayerName8 == null)
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find " + text13);
							return;
						}
						val10 = peerByPlayerName8.m_refPos;
					}
					RandomEvent @event = RandEventSystem.instance.GetEvent(text12);
					if (@event == null)
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find event: " + text12);
					}
					else
					{
						RandEventSystem.instance.SetRandomEvent(@event, val10);
					}
				}
			}, null, adminOnly: true, isSecret: false, "star");
			DiscordCommand discordCommand24 = new DiscordCommand("!liststatus", "List of available status effects", delegate
			{
				StringBuilder stringBuilder7 = new StringBuilder();
				foreach (StatusEffect statusEffect3 in ObjectDB.instance.m_StatusEffects)
				{
					stringBuilder7.Append("`" + ((Object)statusEffect3).name + "`\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "Available status effects:", stringBuilder7.ToString());
			}, null, adminOnly: false, isSecret: false, "rocket");
			DiscordCommand discordCommand25 = new DiscordCommand("!addstatus", "Add status effect on player, `player name` `status effect` `duration`", delegate(string[] args)
			{
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Expected O, but got Unknown
				if (args.Length == 4)
				{
					string text10 = args[1].Trim();
					string text11 = args[2].Trim();
					float result3;
					float num4 = (float.TryParse(args[3].Trim(), out result3) ? result3 : 0f);
					StatusEffect statusEffect2 = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode(text11));
					if (statusEffect2 == null)
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find status effect: " + text11);
					}
					else if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text10)
					{
						StatusEffect val8 = ((Character)Player.m_localPlayer).GetSEMan().AddStatusEffect(statusEffect2, false, 0, 0f);
						if (num4 > 0f)
						{
							val8.m_ttl = num4;
						}
					}
					else
					{
						ZNetPeer peerByPlayerName7 = ZNet.instance.GetPeerByPlayerName(text10);
						if (peerByPlayerName7 != null)
						{
							ZPackage val9 = new ZPackage();
							val9.Write("!addstatus");
							val9.Write(text11);
							val9.Write((double)num4);
							peerByPlayerName7.m_rpc.Invoke("RPC_BotToClient", new object[1] { val9 });
						}
						else
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find " + text10);
						}
					}
				}
			}, delegate(ZPackage pkg)
			{
				string text9 = pkg.ReadString();
				float num3 = (float)pkg.ReadDouble();
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode(text9));
				if (statusEffect != null)
				{
					StatusEffect val7 = ((Character)Player.m_localPlayer).GetSEMan().AddStatusEffect(statusEffect, false, 0, 0f);
					if (num3 > 0f)
					{
						val7.m_ttl = num3;
					}
				}
			}, adminOnly: true, isSecret: false, "pizza");
			DiscordCommand discordCommand26 = new DiscordCommand("!heal", "Heals to full health & stamina, `player name`", delegate(string[] args)
			{
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Expected O, but got Unknown
				if (args.Length >= 2)
				{
					string text8 = args[1].Trim();
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text8)
					{
						((Character)Player.m_localPlayer).Heal(((Character)Player.m_localPlayer).GetMaxHealth(), true);
						((Character)Player.m_localPlayer).AddStamina(((Character)Player.m_localPlayer).GetMaxStamina());
						((Character)Player.m_localPlayer).AddEitr(((Character)Player.m_localPlayer).GetMaxEitr());
					}
					else
					{
						ZNetPeer peerByPlayerName6 = ZNet.instance.GetPeerByPlayerName(text8);
						if (peerByPlayerName6 != null)
						{
							ZPackage val6 = new ZPackage();
							val6.Write("!heal");
							peerByPlayerName6.m_rpc.Invoke("RPC_BotToClient", new object[1] { val6 });
						}
						else
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find player: " + text8);
						}
					}
				}
			}, delegate
			{
				((Character)Player.m_localPlayer).Heal(((Character)Player.m_localPlayer).GetMaxHealth(), true);
				((Character)Player.m_localPlayer).AddStamina(((Character)Player.m_localPlayer).GetMaxStamina());
				((Character)Player.m_localPlayer).AddEitr(((Character)Player.m_localPlayer).GetMaxEitr());
			}, adminOnly: true, isSecret: false, "heart");
			DiscordCommand discordCommand27 = new DiscordCommand("!die", "Kills player, `player name`", delegate(string[] args)
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: 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)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Expected O, but got Unknown
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Expected O, but got Unknown
				if (args.Length >= 2)
				{
					string text7 = args[1].Trim();
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text7)
					{
						((Character)Player.m_localPlayer).Damage(new HitData
						{
							m_damage = 
							{
								m_damage = 99999f
							},
							m_hitType = (HitType)14
						});
					}
					else
					{
						ZNetPeer peerByPlayerName5 = ZNet.instance.GetPeerByPlayerName(text7);
						if (peerByPlayerName5 != null)
						{
							ZPackage val5 = new ZPackage();
							val5.Write("!die");
							peerByPlayerName5.m_rpc.Invoke("RPC_BotToClient", new object[1] { val5 });
						}
						else
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find player: " + text7);
						}
					}
				}
			}, delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Expected O, but got Unknown
				((Character)Player.m_localPlayer).Damage(new HitData
				{
					m_damage = 
					{
						m_damage = 99999f
					},
					m_hitType = (HitType)14
				});
			}, adminOnly: true, isSecret: false, "tiger");
			DiscordCommand discordCommand28 = new DiscordCommand("!listskills", "List of available skills", delegate
			{
				StringBuilder stringBuilder6 = new StringBuilder();
				foreach (object value2 in Enum.GetValues(typeof(SkillType)))
				{
					stringBuilder6.Append(Formatting.Format(value2.ToString(), Formatting.TextFormat.InlineCode) + "\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "Available skill types:", stringBuilder6.ToString(), ZNet.instance.GetWorldName());
			}, null, adminOnly: false, isSecret: false, "pray");
			DiscordCommand discordCommand29 = new DiscordCommand("!raiseskill", "Raises skill level, `player name` `stkill type` `amount`", delegate(string[] args)
			{
				//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Expected O, but got Unknown
				if (args.Length >= 3)
				{
					string text5 = args[1].Trim();
					string text6 = args[2].Trim();
					float result;
					float num2 = (float.TryParse(args[3].Trim(), out result) ? result : 1f);
					if (!Enum.TryParse<SkillType>(text6, out SkillType _))
					{
						Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find skill type: " + text6);
					}
					else if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text5)
					{
						((Character)Player.m_localPlayer).GetSkills().CheatRaiseSkill(text6, num2, true);
					}
					else
					{
						ZNetPeer peerByPlayerName4 = ZNet.instance.GetPeerByPlayerName(text5);
						if (peerByPlayerName4 != null)
						{
							ZPackage val4 = new ZPackage();
							val4.Write("!raiseskill");
							val4.Write(text6);
							val4.Write((double)num2);
							peerByPlayerName4.m_rpc.Invoke("RPC_BotToClient", new object[1] { val4 });
						}
						else
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find player: " + text5);
						}
					}
				}
			}, delegate(ZPackage pkg)
			{
				string text4 = pkg.ReadString();
				float num = (float)pkg.ReadDouble();
				((Character)Player.m_localPlayer).GetSkills().CheatRaiseSkill(text4, num, true);
			}, adminOnly: true, isSecret: false, "muscle");
			DiscordCommand discordCommand30 = new DiscordCommand("!pos", "Player position, `player name`", delegate(string[] args)
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: 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)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length >= 2)
				{
					string text3 = args[1].Trim();
					Vector3 val3;
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text3)
					{
						val3 = ((Component)Player.m_localPlayer).transform.position;
					}
					else
					{
						ZNetPeer peerByPlayerName3 = ZNet.instance.GetPeerByPlayerName(text3);
						if (peerByPlayerName3 == null)
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find player: " + text3);
							return;
						}
						val3 = peerByPlayerName3.m_refPos;
					}
					Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", $"{text3} position: {val3.x},{val3.y},{val3.z}");
				}
			}, null, adminOnly: true, isSecret: false, "rose");
			DiscordCommand discordCommand31 = new DiscordCommand("!stats", "Player stats, player must be online, `player name`", delegate(string[] args)
			{
				//IL_0134: Unknown result type (might be due to invalid IL or missing references)
				//IL_013b: Expected O, but got Unknown
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				if (args.Length >= 2)
				{
					string text2 = args[1].Trim();
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text2)
					{
						PlayerProfile playerProfile2 = Game.instance.GetPlayerProfile();
						StringBuilder stringBuilder5 = new StringBuilder();
						foreach (KeyValuePair<PlayerStatType, float> stat in playerProfile2.m_playerStats.m_stats)
						{
							if (stat.Value > 0f)
							{
								PlayerStatType key2 = stat.Key;
								stringBuilder5.Append(Formatting.Format(((object)(PlayerStatType)(ref key2)).ToString(), Formatting.TextFormat.Bold) + ": " + Formatting.Format(stat.Value.ToString("0.0"), Formatting.TextFormat.InlineCode) + "\n");
							}
						}
						Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, text2 + " Stats", stringBuilder5.ToString());
					}
					else
					{
						ZNetPeer peerByPlayerName2 = ZNet.instance.GetPeerByPlayerName(text2);
						if (peerByPlayerName2 != null)
						{
							ZPackage val2 = new ZPackage();
							val2.Write("!stats");
							peerByPlayerName2.m_rpc.Invoke("RPC_BotToClient", new object[1] { val2 });
						}
						else
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find player: " + text2);
						}
					}
				}
			}, delegate
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
				StringBuilder stringBuilder4 = new StringBuilder();
				foreach (KeyValuePair<PlayerStatType, float> stat2 in playerProfile.m_playerStats.m_stats)
				{
					if (stat2.Value > 0f)
					{
						PlayerStatType key = stat2.Key;
						stringBuilder4.Append(Formatting.Format(((object)(PlayerStatType)(ref key)).ToString(), Formatting.TextFormat.Bold) + ": " + Formatting.Format(stat2.Value.ToString("0.0"), Formatting.TextFormat.InlineCode) + "\n");
					}
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, playerProfile.m_playerName + " Stats", stringBuilder4.ToString());
			}, adminOnly: false, isSecret: false, "wine");
			DiscordCommand discordCommand32 = new DiscordCommand("!mods", "List of plugin installed, `player name?`", delegate(string[] args)
			{
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Expected O, but got Unknown
				if (args.Length > 1)
				{
					string text = args[1].Trim();
					if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName() == text)
					{
						StringBuilder stringBuilder2 = new StringBuilder();
						foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
						{
							stringBuilder2.Append($"{pluginInfo.Value.Metadata.Name}-{pluginInfo.Value.Metadata.Version}\n");
						}
						Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, text + " installed plugins", stringBuilder2.ToString());
					}
					else
					{
						ZNetPeer peerByPlayerName = ZNet.instance.GetPeerByPlayerName(text);
						if (peerByPlayerName != null)
						{
							ZPackage val = new ZPackage();
							val.Write("!mods");
							peerByPlayerName.m_rpc.Invoke("RPC_BotToClient", new object[1] { val });
						}
						else
						{
							Discord.instance.SendMessage(DiscordBotPlugin.Webhook.Commands, "", "Failed to find player: " + text);
						}
					}
				}
				else
				{
					StringBuilder stringBuilder3 = new StringBuilder();
					foreach (KeyValuePair<string, PluginInfo> pluginInfo2 in Chainloader.PluginInfos)
					{
						stringBuilder3.Append($"{pluginInfo2.Value.Metadata.Name}-{pluginInfo2.Value.Metadata.Version}\n");
					}
					Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, "Server installed plugins", stringBuilder3.ToString());
				}
			}, delegate
			{
				StringBuilder stringBuilder = new StringBuilder();
				foreach (KeyValuePair<string, PluginInfo> pluginInfo3 in Chainloader.PluginInfos)
				{
					stringBuilder.Append($"{pluginInfo3.Value.Metadata.Name}-{pluginInfo3.Value.Metadata.Version}\n");
				}
				Discord.instance.SendEmbedMessage(DiscordBotPlugin.Webhook.Commands, Game.instance.GetPlayerProfile().m_playerName + " installed plugins", stringBuilder.ToString());
			}, adminOnly: false, isSecret: false, "guitar");
		}

		public static bool Spawn(string prefabName, int level, Vector3 pos)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return false;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(prefabName);
			if (prefab == null)
			{
				return false;
			}
			Vector3 val = Random.insideUnitSphere * 5f;
			val.y = 0f;
			Vector3 val2 = val;
			Vector3 val3 = pos + val2;
			GameObject val4 = Object.Instantiate<GameObject>(prefab, val3, Quaternion.identity);
			Character val5 = default(Character);
			if (val4.TryGetComponent<Character>(ref val5))
			{
				val5.SetLevel(level);
			}
			return true;
		}

		public static bool GiveItem(string itemName, int amount, int quality, int variant)
		{
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return false;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemName);
			ItemDrop val = default(ItemDrop);
			if (itemPrefab == null || !itemPrefab.TryGetComponent<ItemDrop>(ref val))
			{
				return false;
			}
			ItemData val2 = val.m_itemData.Clone();
			val2.m_dropPrefab = itemPrefab;
			val2.m_stack = amount;
			val2.m_quality = quality;
			val2.m_variant = variant;
			((Humanoid)Player.m_localPlayer).GetInventory().AddItem(val2);
			return true;
		}

		public static void RPC_BotToClient(ZRpc rpc, ZPackage pkg)
		{
			string key = pkg.ReadString();
			if (m_commands.TryGetValue(key, out var value))
			{
				value.Run(pkg);
			}
		}
	}
	[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
	[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
	public class Discord : MonoBehaviour
	{
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		[HarmonyPatch(typeof(ZNet), "Awake")]
		private static class ZNet_Awake_Patch
		{
			[UsedImplicitly]
			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			private static void Postfix(ZNet __instance)
			{
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				((Component)DiscordBotPlugin.m_instance).gameObject.AddComponent<Discord>();
				if (__instance.IsServer() && DiscordBotPlugin.m_serverStartNotice.Value != 0)
				{
					instance.SendStatus(DiscordBotPlugin.Webhook.Notifications, "$msg_server_start", __instance.GetWorldName(), "$status_launch", new Color(0.4f, 0.98f, 0.24f));
				}
			}
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class ZNet_OnNewConnection_Patch
		{
			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			private static void Postfix(ZNetPeer peer)
			{
				peer.m_rpc.Register<string, string>("RPC_ClientBotMessage", (Action<ZRpc, string, string>)RPC_ClientBotMessage);
			}
		}

		[Serializable]
		[Description("Discord webhook json object")]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class DiscordWebhookData
		{
			public string content;

			public bool tts;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public Embed[] embeds;

			public string username;

			public string avatar_url;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public DiscordWebhookData(string username, string content)
			{
				if (!string.IsNullOrEmpty(username))
				{
					this.username = username;
				}
				this.content = Localization.instance.Localize(content);
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public DiscordWebhookData(string username, params Embed[] embeds)
			{
				if (!string.IsNullOrEmpty(username))
				{
					this.username = username;
				}
				this.embeds = embeds;
			}
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public enum DiscordMessageFlags
		{
			CrossPosted = 0,
			Is_CrossPost = 1,
			Suppress_Embeds = 2,
			Source_Message_Deleted = 3,
			Urgent = 4,
			Has_Thread = 5,
			Ephemeral = 6,
			Loading = 7,
			Failed_To_Mention_Some_Roles_In_Thread = 8,
			Suppress_Notifications = 12,
			Is_Voice_Message = 13,
			Has_Snapshot = 14,
			Is_Components_V2 = 15
		}

		[Serializable]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		public class DiscordWebhookComponents
		{
			public string username;

			public string avatar_url;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public EmbedComponent[] components;

			public int flags = 15;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public DiscordWebhookComponents(string username, params EmbedComponent[] components)
			{
				if (!string.IsNullOrEmpty(username))
				{
					this.username = username;
				}
				this.components = components;
			}
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public class EmbedComponent
		{
			public int type;

			public int id;
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public class ActionRow : EmbedComponent
		{
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public EmbedComponent[] components;

			public ActionRow()
			{
				type = 1;
			}
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class Button : EmbedComponent
		{
			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
			public enum ButtonStyle
			{
				Primary = 1,
				Secondary,
				Success,
				Danger,
				Link,
				Premium
			}

			public int style;

			public string label;

			public string custom_id;

			public string url;

			public bool disabled;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public Button(ButtonStyle style, string label)
			{
				this.label = label;
				this.style = (int)style;
				type = 2;
			}
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class StringSelect : EmbedComponent
		{
			public string custom_id;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public EmbedOption[] options;

			public string placeholder;

			public int min_values;

			public int max_values;

			public bool disabled;

			public StringSelect()
			{
				type = 3;
			}
		}

		[Serializable]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		public class TextInput : EmbedComponent
		{
			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
			public enum TextInputStyle
			{
				Short = 1,
				Paragraph
			}

			public string custom_id;

			public int style;

			public string label;

			public int min_length;

			public int max_length;

			public bool required;

			public string value;

			public string placeholder;

			public TextInput(TextInputStyle style)
			{
				this.style = (int)style;
				type = 4;
			}
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class UserSelect : EmbedComponent
		{
			public string custom_id;

			public string placeholder;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public object[] default_values;

			public int min_values;

			public int max_values;

			public bool disabled;

			public UserSelect()
			{
				type = 5;
			}
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public class Section : EmbedComponent
		{
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public EmbedComponent[] components;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)]
			public EmbedComponent accessory;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public Section(params EmbedComponent[] components)
			{
				this.components = components;
				type = 9;
			}

			public Section()
			{
				type = 9;
			}
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public class TextDisplay : EmbedComponent
		{
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)]
			public string content;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public TextDisplay(string content)
			{
				this.content = content;
				type = 10;
			}
		}

		[Serializable]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		public class EmbedOption
		{
			public string label;

			public string value;

			public string description;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1, 1 })]
			public Dictionary<string, string> emoji;
		}

		[Serializable]
		[Description("Discord embed json object")]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		public class Embed
		{
			public string title;

			public string description;

			public string url;

			public string timestamp;

			public int? color;

			public Footer footer;

			public EmbedImage image;

			public EmbedImage thumbnail;

			public EmbedVideo video;

			public EmbedProvider provider;

			public EmbedAuthor author;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public EmbedField[] fields;

			public Embed()
			{
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public Embed(string title, string description)
			{
				this.title = Localization.instance.Localize(title);
				this.description = Localization.instance.Localize(description);
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public Embed(string title, params EmbedField[] fields)
			{
				this.title = title;
				this.fields = fields;
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public Embed(string description)
			{
				this.description = Localization.instance.Localize(description);
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public Embed(string title, List<EmbedField> fields)
				: this(title, fields.ToArray())
			{
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public void AddImage(string imageUrl)
			{
				if (!string.IsNullOrEmpty(imageUrl))
				{
					image = new EmbedImage(imageUrl);
				}
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public void AddThumbnail(string thumbnailUrl)
			{
				if (!string.IsNullOrEmpty(thumbnailUrl))
				{
					thumbnail = new EmbedImage(thumbnailUrl);
				}
			}

			public void SetColor(Color Color)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				color = ColorToInt(Color);
			}
		}

		[Serializable]
		[Description("Discord image json object")]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public class EmbedImage
		{
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)]
			public string url;

			public int width;

			public int height;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public EmbedImage(string url, int width = 256, int height = 256)
			{
				this.url = url;
				this.width = width;
				this.height = height;
			}
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(0)]
		public class EmbedVideo
		{
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)]
			public string url;

			public int height;

			public int width;
		}

		[Serializable]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		public class EmbedProvider
		{
			public string name;

			public string url;
		}

		[Serializable]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[Description("Discord author json object")]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class EmbedAuthor
		{
			public string name;

			public string icon_url;
		}

		[Serializable]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[Description("Discord embed json object")]
		public class EmbedField
		{
			public string name;

			public string value;

			public bool inline;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public EmbedField(string name, string value, bool inline = true)
			{
				this.name = Localization.instance.Localize(name);
				this.value = Localization.instance.Localize(value);
				this.inline = inline;
			}
		}

		[Serializable]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		[Description("Discord footer json object")]
		public class Footer
		{
			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)]
			public string text;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(2)]
			public string icon_url;

			public Footer(string text)
			{
				this.text = Localization.instance.Localize(text);
			}

			public void AddIcon(string url)
			{
				if (!string.IsNullOrEmpty(url))
				{
					icon_url = url;
				}
			}
		}

		[Serializable]
		[Description("Discord message json object")]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class Message
		{
			public string id;

			public string channel_id;

			public User author;

			public string content;

			public string timestamp;

			public string edited_timestamp;

			public bool tts;

			public bool mention_everyone;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public User[] mentions;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public User[] mention_roles;

			public int type;

			[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
			public Embed[] embeds;
		}

		[Serializable]
		[Description("Discord user json object")]
		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(2)]
		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
		public class User
		{
			public string id;

			public string username;

			public string global_name;

			public string discriminator;

			public bool bot;

			public string avatar;

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public string GetDisplayName()
			{
				return ((!string.IsNullOrEmpty(global_name)) ? global_name : username) ?? string.Empty;
			}

			[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
			public string GetFullUsername()
			{
				return (!string.IsNullOrEmpty(discriminator) && discriminator != "0") ? (username + "#" + discriminator) : (username ?? string.Empty);
			}
		}

		public static Discord instance;

		private string m_lastMessageID = "";

		private string m_lastCommandID = "";

		private bool m_isPollingChatter;

		private bool m_isPollingCommands;

		private bool m_isDownloadingImage;

		private bool m_isDownloadingSound;

		private DateTime m_timeLoaded;

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[method: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[field: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		public event Action<Message> OnMessageReceived;

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[method: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[field: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		public event Action<Message> OnCommandReceived;

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[method: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[field: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		public event Action<Sprite> OnImageDownloaded;

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[method: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[field: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		public event Action<AudioClip> OnAudioDownloaded;

		[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[method: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		[field: <0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(new byte[] { 2, 1 })]
		public event Action<string> OnError;

		public void Awake()
		{
			instance = this;
			m_timeLoaded = DateTime.UtcNow;
			if (ZNet.m_isServer)
			{
				OnMessageReceived += HandleChatMessage;
				OnCommandReceived += HandleCommands;
				OnImageDownloaded += HandleImage;
				OnError += HandleError;
			}
		}

		private void Start()
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.m_isServer)
			{
				return;
			}
			if (string.IsNullOrEmpty(DiscordBotPlugin.m_botToken.Value))
			{
				DiscordBotPlugin.DiscordBotLogger.LogWarning((object)"Bot token not set");
				return;
			}
			if (!string.IsNullOrEmpty(DiscordBotPlugin.m_chatChannelID.Value) && DiscordBotPlugin.m_chatEnabled.Value == DiscordBotPlugin.Toggle.On)
			{
				StartPollingChatter();
			}
			if (!string.IsNullOrEmpty(DiscordBotPlugin.m_commandChannelID.Value))
			{
				StartPollingCommands();
			}
			SendMessage(DiscordBotPlugin.Webhook.Commands, ZNet.instance.GetWorldName(), EmojiHelper.Emoji("question") + " type `!help` to find list of available commands");
		}

		private void OnDestroy()
		{
			StopPolling();
		}

		private static void HandleError(string message)
		{
			if (DiscordBotPlugin.m_logErrors.Value != 0)
			{
				DiscordBotPlugin.DiscordBotLogger.LogWarning((object)message);
			}
		}

		private void HandleChatMessage(Message message)
		{
			BroadcastMessage(message.author?.GetDisplayName() ?? "", message?.content ?? "");
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				DisplayChatMessage(message?.author?.GetDisplayName() ?? "", message?.content ?? "");
			}
		}

		private void HandleCommands(Message message)
		{
			if (message.content != null)
			{
				string[] array = message.content.Split(new char[1] { ' ' });
				string text = array[0].Trim();
				if (!DiscordCommands.m_commands.TryGetValue(text, out var value))
				{
					SendMessage(DiscordBotPlugin.Webhook.Commands, ZNet.instance.GetWorldName(), "Failed to find command: " + text);
				}
				else if (!value.IsAllowed(message.author?.GetFullUsername() ?? ""))
				{
					SendMessage(DiscordBotPlugin.Webhook.Commands, ZNet.instance.GetWorldName(), message.author?.GetFullUsername() + " not allowed to use command: " + text);
				}
				else
				{
					value.Run(array);
				}
			}
		}

		private static void HandleImage(Sprite sprite)
		{
			if (ImageHud.instance != null)
			{
				ImageHud.instance.Show(sprite);
			}
		}

		public void GetImage(string imageUrl)
		{
			if (!m_isDownloadingImage)
			{
				m_isDownloadingImage = true;
				((MonoBehaviour)this).StartCoroutine(DownloadImage(imageUrl));
			}
		}

		private IEnumerator DownloadImage(string imageUrl)
		{
			UnityWebRequest request = UnityWebRequestTexture.GetTexture(imageUrl);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					string message = "Failed to download image from " + imageUrl + ": " + request.error;
					this.OnError?.Invoke(message);
				}
				else
				{
					Texture2D texture = DownloadHandlerTexture.GetContent(request);
					Sprite sprite = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f));
					this.OnImageDownloaded?.Invoke(sprite);
				}
				m_isDownloadingImage = false;
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public void GetSound(string url, AudioType type)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!m_isDownloadingSound)
			{
				m_isDownloadingSound = true;
				((MonoBehaviour)this).StartCoroutine(DownloadSound(url, type));
			}
		}

		private IEnumerator DownloadSound(string url, AudioType type)
		{
			//IL_0015: 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)
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(url, type);
			try
			{
				((DownloadHandlerAudioClip)request.downloadHandler).streamAudio = true;
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					this.OnError?.Invoke("Failed to download audio: " + request.error);
				}
				else
				{
					AudioClip clip = DownloadHandlerAudioClip.GetContent(request);
					this.OnAudioDownloaded?.Invoke(clip);
				}
				m_isDownloadingSound = false;
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public void BroadcastMessage(string username, string message)
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.m_isServer)
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				peer.m_rpc.Invoke("RPC_ClientBotMessage", new object[2] { username, message });
			}
		}

		public static void RPC_ClientBotMessage(ZRpc rpc, string username, string message)
		{
			DisplayChatMessage(username, message);
		}

		private static void DisplayChatMessage(string userName, string message)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			string text = "<color=#" + ColorUtility.ToHtmlStringRGB(new Color(0f, 0.5f, 0.5f, 1f)) + ">[Discord]</color><color=orange>" + userName + "</color>: " + message;
			((Terminal)Chat.instance).AddString(text);
		}

		public void SendComponentMessage(DiscordBotPlugin.Webhook webhook, string username = "", params EmbedComponent[] components)
		{
			DiscordWebhookComponents data = new DiscordWebhookComponents(username, components);
			((MonoBehaviour)this).StartCoroutine(SendLayoutMessage(data, DiscordBotPlugin.GetWebhookURL(webhook)));
		}

		public void SendMessage(DiscordBotPlugin.Webhook webhook, string username = "", string message = "")
		{
			DiscordWebhookData data = new DiscordWebhookData(username, message);
			((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, DiscordBotPlugin.GetWebhookURL(webhook)));
		}

		public void SendEmbedMessage(DiscordBotPlugin.Webhook webhook, string title, string content, string username = "", string thumbnail = "")
		{
			Embed embed = new Embed(title, content);
			embed.AddThumbnail(thumbnail);
			DiscordWebhookData data = new DiscordWebhookData(username, embed);
			((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, DiscordBotPlugin.GetWebhookURL(webhook)));
		}

		public void SendTableEmbed(DiscordBotPlugin.Webhook webhook, string title, Dictionary<string, string> tableData, string username = "", string thumbnail = "")
		{
			if (tableData.Count <= 0)
			{
				this.OnError?.Invoke("Table data is empty");
			}
			List<EmbedField> list = new List<EmbedField>();
			foreach (KeyValuePair<string, string> tableDatum in tableData)
			{
				list.Add(new EmbedField(tableDatum.Key, tableDatum.Value));
			}
			Embed embed = new Embed(title, list);
			embed.AddThumbnail(thumbnail);
			DiscordWebhookData data = new DiscordWebhookData(username, embed);
			((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, DiscordBotPlugin.GetWebhookURL(webhook)));
		}

		public void SendStatus(DiscordBotPlugin.Webhook webhook, string content, string worldName, string status, Color color, string username = "", string thumbnail = "")
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Embed embed = new Embed(content);
			embed.SetColor(color);
			List<EmbedField> list = new List<EmbedField>();
			list.Add(new EmbedField("$label_worldname", worldName));
			list.Add(new EmbedField("$label_status", status));
			embed.fields = list.ToArray();
			embed.AddThumbnail(thumbnail);
			DiscordWebhookData data = new DiscordWebhookData(username, embed);
			((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, DiscordBotPlugin.GetWebhookURL(webhook)));
		}

		private IEnumerator SendWebhookMessage(DiscordWebhookData data, string webhookURL)
		{
			if (string.IsNullOrEmpty(webhookURL))
			{
				this.OnError?.Invoke("Webhook URL is not set!");
				yield break;
			}
			string jsonData = JsonConvert.SerializeObject((object)data);
			byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData);
			UnityWebRequest request = new UnityWebRequest(webhookURL, "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					string error = "Failed to send message: " + request.error + " - " + request.downloadHandler.text;
					this.OnError?.Invoke(error);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator SendLayoutMessage(DiscordWebhookComponents data, string webhookURL)
		{
			if (string.IsNullOrEmpty(webhookURL))
			{
				this.OnError?.Invoke("Webhook URL is not set!");
				yield break;
			}
			string jsonData = JsonConvert.SerializeObject((object)data);
			byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData);
			UnityWebRequest request = new UnityWebRequest(webhookURL + "?with_components=true", "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					string error = "Failed to send message: " + request.error + " - " + request.downloadHandler.text;
					this.OnError?.Invoke(error);
					this.OnError?.Invoke(jsonData);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public void StartPollingChatter()
		{
			if (!m_isPollingChatter && !string.IsNullOrEmpty(DiscordBotPlugin.m_botToken.Value) && !string.IsNullOrEmpty(DiscordBotPlugin.m_chatChannelID.Value))
			{
				m_isPollingChatter = true;
				((MonoBehaviour)this).StartCoroutine(PollForMessages());
			}
		}

		public void StartPollingCommands()
		{
			if (!m_isPollingCommands && !string.IsNullOrEmpty(DiscordBotPlugin.m_botToken.Value) && !string.IsNullOrEmpty(DiscordBotPlugin.m_commandChannelID.Value))
			{
				m_isPollingCommands = true;
				((MonoBehaviour)this).StartCoroutine(PollForCommands());
			}
		}

		public void StopPolling()
		{
			m_isPollingChatter = false;
			m_isPollingCommands = false;
		}

		private IEnumerator PollForMessages()
		{
			while (m_isPollingChatter)
			{
				yield return ((MonoBehaviour)this).StartCoroutine(GetChannelMessages());
				yield return (object)new WaitForSeconds((float)DiscordBotPlugin.m_pollInterval.Value);
			}
		}

		private IEnumerator PollForCommands()
		{
			while (m_isPollingCommands)
			{
				yield return ((MonoBehaviour)this).StartCoroutine(GetChannelCommands());
				yield return (object)new WaitForSeconds((float)DiscordBotPlugin.m_pollInterval.Value);
			}
		}

		private IEnumerator GetChannelCommands()
		{
			string url = "https://discord.com/api/v10/channels/" + DiscordBotPlugin.GetChannelID(DiscordBotPlugin.Channel.Commands) + "/messages?limit=1";
			UnityWebRequest request = UnityWebRequest.Get(url);
			try
			{
				request.SetRequestHeader("Authorization", "Bot " + DiscordBotPlugin.m_botToken.Value);
				request.SetRequestHeader("Content-Type", "application/json");
				yield return request.SendWebRequest();
				if ((int)request.result == 1)
				{
					try
					{
						Message[] messages = JsonConvert.DeserializeObject<Message[]>(request.downloadHandler.text);
						if (messages != null && messages.Length > 0)
						{
							Message message = messages[0];
							if (!(message.author?.bot ?? true))
							{
								DateTime timeStamp = DateTime.Parse(message.timestamp).ToUniversalTime();
								if (!(m_timeLoaded > timeStamp) && message.id != null && !(message.id == m_lastCommandID))
								{
									m_lastCommandID = message.id;
									this.OnCommandReceived?.Invoke(message);
								}
							}
						}
						yield break;
					}
					catch (Exception e)
					{
						this.OnError?.Invoke("Failed to parse message: " + e.Message);
						yield break;
					}
				}
				this.OnError?.Invoke("Failed to get message: " + request.error);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator GetChannelMessages()
		{
			string url = "https://discord.com/api/v10/channels/" + DiscordBotPlugin.GetChannelID(DiscordBotPlugin.Channel.Chat) + "/messages?limit=10";
			if (!string.IsNullOrEmpty(m_lastMessageID))
			{
				url = url + "&after=" + m_lastMessageID;
			}
			UnityWebRequest request = UnityWebRequest.Get(url);
			try
			{
				request.SetRequestHeader("Authorization", "Bot " + DiscordBotPlugin.m_botToken.Value);
				request.SetRequestHeader("Content-Type", "application/json");
				yield return request.SendWebRequest();
				if ((int)request.result == 1)
				{
					try
					{
						Message[] messages = JsonConvert.DeserializeObject<Message[]>(request.downloadHandler.text);
						if (messages != null)
						{
							for (int i = messages.Length - 1; i >= 0; i--)
							{
								Message message = messages[i];
								if (!(message.author?.bot ?? true) && message.id != null)
								{
									if (string.IsNullOrEmpty(m_lastMessageID) || ulong.Parse(message.id) > ulong.Parse(m_lastMessageID))
									{
										m_lastMessageID = message.id;
									}
									if (!string.IsNullOrEmpty(m_lastMessageID))
									{
										this.OnMessageReceived?.Invoke(message);
									}
								}
							}
						}
						yield break;
					}
					catch (Exception e)
					{
						this.OnError?.Invoke("Failed to parse messages: " + e.Message);
						yield break;
					}
				}
				this.OnError?.Invoke("Failed to get messages: " + request.error);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		[Description("Color utility to format into int for discord")]
		public static int ColorToInt(Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.RoundToInt(color.r * 255f);
			int num2 = Mathf.RoundToInt(color.g * 255f);
			int num3 = Mathf.RoundToInt(color.b * 255f);
			return (num << 16) + (num2 << 8) + num3;
		}
	}
	[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
	[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
	public static class EmojiHelper
	{
		private static readonly Dictionary<string, string> Emojis = new Dictionary<string, string>
		{
			{ "smile", "\ud83d\ude0a" },
			{ "grin", "\ud83d\ude01" },
			{ "laugh", "\ud83d\ude02" },
			{ "wink", "\ud83d\ude09" },
			{ "wave", "\ud83d\udc4b" },
			{ "clap", "\ud83d\udc4f" },
			{ "thumbsup", "\ud83d\udc4d" },
			{ "thumbsdown", "\ud83d\udc4e" },
			{ "ok", "\ud83d\udc4c" },
			{ "pray", "\ud83d\ude4f" },
			{ "muscle", "\ud83d\udcaa" },
			{ "facepalm", "\ud83e\udd26" },
			{ "dog", "\ud83d\udc36" },
			{ "cat", "\ud83d\udc31" },
			{ "mouse", "\ud83d\udc2d" },
			{ "fox", "\ud83e\udd8a" },
			{ "bear", "\ud83d\udc3b" },
			{ "panda", "\ud83d\udc3c" },
			{ "koala", "\ud83d\udc28" },
			{ "lion", "\ud83e\udd81" },
			{ "tiger", "\ud83d\udc2f" },
			{ "monkey", "\ud83d\udc35" },
			{ "unicorn", "\ud83e\udd84" },
			{ "dragon", "\ud83d\udc09" },
			{ "tree", "\ud83c\udf33" },
			{ "palm", "\ud83c\udf34" },
			{ "flower", "\ud83c\udf38" },
			{ "rose", "\ud83c\udf39" },
			{ "sun", "☀\ufe0f" },
			{ "moon", "\ud83c\udf19" },
			{ "star", "⭐" },
			{ "rain", "\ud83c\udf27\ufe0f" },
			{ "snow", "❄\ufe0f" },
			{ "fire", "\ud83d\udd25" },
			{ "lightning", "⚡" },
			{ "pizza", "\ud83c\udf55" },
			{ "burger", "\ud83c\udf54" },
			{ "fries", "\ud83c\udf5f" },
			{ "taco", "\ud83c\udf2e" },
			{ "cake", "\ud83c\udf70" },
			{ "donut", "\ud83c\udf69" },
			{ "coffee", "☕" },
			{ "tea", "\ud83c\udf75" },
			{ "beer", "\ud83c\udf7a" },
			{ "wine", "\ud83c\udf77" },
			{ "rocket", "\ud83d\ude80" },
			{ "car", "\ud83d\ude97" },
			{ "bike", "\ud83d\udeb2" },
			{ "airplane", "✈\ufe0f" },
			{ "train", "\ud83d\ude86" },
			{ "bus", "\ud83d\ude8c" },
			{ "ship", "\ud83d\udea2" },
			{ "book", "\ud83d\udcd6" },
			{ "pencil", "✏\ufe0f" },
			{ "pen", "\ud83d\udd8a\ufe0f" },
			{ "paint", "\ud83c\udfa8" },
			{ "camera", "\ud83d\udcf7" },
			{ "phone", "\ud83d\udcf1" },
			{ "computer", "\ud83d\udcbb" },
			{ "gift", "\ud83c\udf81" },
			{ "balloon", "\ud83c\udf88" },
			{ "key", "\ud83d\udd11" },
			{ "lock", "\ud83d\udd12" },
			{ "soccer", "⚽" },
			{ "basketball", "\ud83c\udfc0" },
			{ "football", "\ud83c\udfc8" },
			{ "tennis", "\ud83c\udfbe" },
			{ "golf", "⛳" },
			{ "run", "\ud83c\udfc3" },
			{ "swim", "\ud83c\udfca" },
			{ "ski", "⛷\ufe0f" },
			{ "game", "\ud83c\udfae" },
			{ "music", "\ud83c\udfb5" },
			{ "guitar", "\ud83c\udfb8" },
			{ "drum", "\ud83e\udd41" },
			{ "check", "✅" },
			{ "x", "❌" },
			{ "warning", "⚠\ufe0f" },
			{ "question", "❓" },
			{ "exclamation", "❗" },
			{ "infinity", "♾\ufe0f" },
			{ "heart", "❤\ufe0f" },
			{ "brokenheart", "\ud83d\udc94" },
			{ "sparkle", "✨" },
			{ "starstruck", "\ud83e\udd29" },
			{ "plus", "✚" },
			{ "minus", "━" },
			{ "tornado", "\ud83c\udf2a\ufe0f" },
			{ "storm", "⛈\ufe0f" },
			{ "save", "\ud83d\udcbe" },
			{ "stop", "\ud83d\udd34" }
		};

		public static string Emoji(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return string.Empty;
			}
			string value;
			return Emojis.TryGetValue(name, out value) ? value : name;
		}
	}
	public static class Formatting
	{
		public enum TextFormat
		{
			Bold,
			Italic,
			BoldItalic,
			Strikethrough,
			InlineCode,
			None
		}

		[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
		public static string Format(string text, TextFormat format)
		{
			if (1 == 0)
			{
			}
			string result = format switch
			{
				TextFormat.Bold => "**" + text + "**", 
				TextFormat.Italic => "*" + text + "*", 
				TextFormat.BoldItalic => "***" + text + "***", 
				TextFormat.Strikethrough => "~~" + text + "~~", 
				TextFormat.InlineCode => "`" + text + "`", 
				_ => text, 
			};
			if (1 == 0)
			{
			}
			return result;
		}
	}
	[<2cb2fe35-caa6-4066-8b30-a5790440185e>NullableContext(1)]
	[<0c5813c0-7a3b-4e69-af6d-a50bfcc1c2c8>Nullable(0)]
	public static class Links
	{
		public static readonly Dictionary<string, string> CreatureLinks = new Dictionary<string, string>
		{
			["Boar"] = "https://valheim.fandom.com/wiki/Special:FilePath/Boar_trophy.png",
			["Deer"] = "https://valheim.fandom.com/wiki/Special:FilePath/Deer_trophy.png",
			["Neck"] = "https://valheim.fandom.com/wiki/Special:FilePath/Neck_trophy.png",
			["Greyling"] = "https://valheim.fandom.com/wiki/Special:FilePath/Greyling_0S.png",
			["Greydwarf"] = "https://valheim.fandom.com/wiki/Special:FilePath/Greydwarf_trophy.png",
			["Greydwarf_Elite"] = "https://valheim.fandom.com/wiki/Special:FilePath/Greydwarf_Brute_trophy.png",
			["Greydwarf_Shaman"] = "https://valheim.fandom.com/wiki/Special:FilePath/Greydwarf_Shaman_trophy.png",
			["Troll"] = "https://valheim.fandom.com/wiki/Special:FilePath/Troll_trophy.png",
			["Skeleton"] = "https://valheim.fandom.com/wiki/Special:FilePath/Skeleton_trophy.png",
			["Skeleton_Poison"] = "https://valheim.fandom.com/wiki/Special:FilePath/Rancid_Remains_trophy.png",
			["Ghost"] = "https://valheim.fandom.com/wiki/Special:FilePath/Ghost_0star.png",
			["Draugr"] = "https://valheim.fandom.com/wiki/Special:FilePath/Draugr_trophy.png",
			["Draugr_Elite"] = "https://valheim.fandom.com/wiki/Special:FilePath/Draugr_Elite_trophy.png",
			["Draugr_Ranged"] = "https://valheim.fandom.com/wiki/Special:FilePath/Draugr_Ranged_trophy.png",
			["Blob"] = "https://valheim.fandom.com/wiki/Special:FilePath/Blob_trophy.png",
			["Leech"] = "https://valheim.fandom.com/wiki/Special:FilePath/Leech_trophy.png",
			["Abomination