Decompiled source of DiscordConnector v3.1.0

DiscordConnector.dll

Decompiled 3 weeks ago
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Security.AccessControl;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Xml;
using System.Xml.Linq;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DiscordConnector.Common;
using DiscordConnector.Config;
using DiscordConnector.Leaderboards;
using DiscordConnector.RPC;
using DiscordConnector.Records;
using FxResources.System.Buffers;
using HarmonyLib;
using LiteDB;
using LiteDB.Engine;
using LiteDB.Utils;
using LiteDB.Utils.Extensions;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
using UnityEngine;
using UnityEngine.Device;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("DiscordConnector")]
[assembly: AssemblyDescription("Enhances Valheim by sending messages to a Discord Webhook")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("nwesterhausen")]
[assembly: AssemblyProduct("DiscordConnector")]
[assembly: AssemblyCopyright("© 2025 nwesterhausen")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4D35EB3F-E4D0-4FD9-9258-9066A85F1BFE")]
[assembly: AssemblyFileVersion("3.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DiscordConnector
{
	internal class PluginConfig
	{
		private const string ConfigJsonFilename = "config-dump.json";

		internal static string[] ConfigExtensions = new string[6] { "messages", "variables", "leaderBoard", "toggles", "extraWebhooks", "main" };

		public readonly string configPath;

		private readonly ExtraWebhookConfig extraWebhookConfig;

		private readonly LeaderBoardConfig leaderBoardConfig;

		private readonly MainConfig mainConfig;

		private readonly MessagesConfig messagesConfig;

		private readonly TogglesConfig togglesConfig;

		private readonly VariableConfig variableConfig;

		public bool LaunchMessageEnabled => togglesConfig.LaunchMessageEnabled;

		public bool LoadedMessageEnabled => togglesConfig.LoadedMessageEnabled;

		public bool StopMessageEnabled => togglesConfig.StopMessageEnabled;

		public bool ShutdownMessageEnabled => togglesConfig.ShutdownMessageEnabled;

		public bool WorldSaveMessageEnabled => togglesConfig.WorldSaveMessageEnabled;

		public bool ChatShoutEnabled => togglesConfig.ChatShoutEnabled;

		public bool ChatPingEnabled => togglesConfig.ChatPingEnabled;

		public bool PlayerJoinMessageEnabled => togglesConfig.PlayerJoinMessageEnabled;

		public bool PlayerDeathMessageEnabled => togglesConfig.PlayerDeathMessageEnabled;

		public bool PlayerLeaveMessageEnabled => togglesConfig.PlayerLeaveMessageEnabled;

		public bool EventStartMessageEnabled => togglesConfig.EventStartMessageEnabled;

		public bool EventStopMessageEnabled => togglesConfig.EventStopMessageEnabled;

		public bool EventPausedMessageEnabled => togglesConfig.EventPausedMessageEnabled;

		public bool EventResumedMessageEnabled => togglesConfig.EventResumedMessageEnabled;

		public bool ChatShoutAllCaps => togglesConfig.ChatShoutAllCaps;

		public bool NewDayNumberEnabled => togglesConfig.NewDayNumberEnabled;

		public bool StatsDeathEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsDeathEnabled;
				}
				return false;
			}
		}

		public bool StatsJoinEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsJoinEnabled;
				}
				return false;
			}
		}

		public bool StatsLeaveEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsLeaveEnabled;
				}
				return false;
			}
		}

		public bool StatsPingEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsPingEnabled;
				}
				return false;
			}
		}

		public bool StatsShoutEnabled
		{
			get
			{
				if (mainConfig.CollectStatsEnabled)
				{
					return togglesConfig.StatsShoutEnabled;
				}
				return false;
			}
		}

		public bool ChatPingPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.ChatPingPosEnabled;
				}
				return false;
			}
		}

		public bool ChatShoutPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.ChatShoutPosEnabled;
				}
				return false;
			}
		}

		public bool PlayerJoinPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.PlayerJoinPosEnabled;
				}
				return false;
			}
		}

		public bool PlayerDeathPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.PlayerDeathPosEnabled;
				}
				return false;
			}
		}

		public bool PlayerLeavePosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.PlayerLeavePosEnabled;
				}
				return false;
			}
		}

		public bool EventStartPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventStartPosEnabled;
				}
				return false;
			}
		}

		public bool EventStopPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventStopPosEnabled;
				}
				return false;
			}
		}

		public bool EventPausedPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventPausedPosEnabled;
				}
				return false;
			}
		}

		public bool EventResumedPosEnabled
		{
			get
			{
				if (mainConfig.SendPositionsEnabled)
				{
					return togglesConfig.EventResumedPosEnabled;
				}
				return false;
			}
		}

		public string DefaultWebhookUsernameOverride => mainConfig.DefaultWebhookUsernameOverride;

		public WebhookEntry PrimaryWebhook => mainConfig.PrimaryWebhook;

		public WebhookEntry SecondaryWebhook => mainConfig.SecondaryWebhook;

		public bool CollectStatsEnabled => mainConfig.CollectStatsEnabled;

		public bool DiscordEmbedsEnabled => mainConfig.DiscordEmbedsEnabled;

		public bool SendPositionsEnabled => mainConfig.SendPositionsEnabled;

		public bool ShowPlayerIds => mainConfig.ShowPlayerIds;

		public bool AnnouncePlayerFirsts => mainConfig.AnnouncePlayerFirsts;

		public bool EmbedTitleEnabled => mainConfig.EmbedTitleEnabled;

		public bool EmbedDescriptionEnabled => mainConfig.EmbedDescriptionEnabled;

		public bool EmbedAuthorEnabled => mainConfig.EmbedAuthorEnabled;

		public bool EmbedThumbnailEnabled => mainConfig.EmbedThumbnailEnabled;

		public bool EmbedFooterEnabled => mainConfig.EmbedFooterEnabled;

		public bool EmbedTimestampEnabled => mainConfig.EmbedTimestampEnabled;

		public string EmbedDefaultColor => mainConfig.EmbedDefaultColor;

		public string EmbedServerStartColor => mainConfig.EmbedServerStartColor;

		public string EmbedServerStopColor => mainConfig.EmbedServerStopColor;

		public string EmbedPlayerJoinColor => mainConfig.EmbedPlayerJoinColor;

		public string EmbedPlayerLeaveColor => mainConfig.EmbedPlayerLeaveColor;

		public string EmbedDeathEventColor => mainConfig.EmbedDeathEventColor;

		public string EmbedShoutMessageColor => mainConfig.EmbedShoutMessageColor;

		public string EmbedOtherEventColor => mainConfig.EmbedOtherEventColor;

		public string EmbedWorldEventColor => mainConfig.EmbedWorldEventColor;

		public string EmbedNewDayColor => mainConfig.EmbedNewDayColor;

		public string EmbedServerSaveColor => mainConfig.EmbedServerSaveColor;

		public string EmbedPositionMessageColor => mainConfig.EmbedPositionMessageColor;

		public string EmbedActivePlayersColor => mainConfig.EmbedActivePlayersColor;

		public string EmbedLeaderboardEmbedColor => mainConfig.EmbedLeaderboardEmbedColor;

		public string EmbedFooterText => mainConfig.EmbedFooterText;

		public List<string> EmbedFieldDisplayOrder => mainConfig.EmbedFieldDisplayOrderList;

		public string EmbedUrlTemplate => mainConfig.EmbedUrlTemplate;

		public string EmbedAuthorIconUrl => mainConfig.EmbedAuthorIconUrl;

		public string EmbedThumbnailUrl => mainConfig.EmbedThumbnailUrl;

		public string ServerName => "Valheim";

		public MainConfig.RetrievalDiscernmentMethods RecordRetrievalDiscernmentMethod => mainConfig.RecordRetrievalDiscernmentMethod;

		public List<string> MutedPlayers => mainConfig.MutedPlayers;

		public Regex MutedPlayersRegex => mainConfig.MutedPlayersRegex;

		public bool AllowNonPlayerShoutLogging => mainConfig.AllowNonPlayerShoutLogging;

		public bool AllowMentionsHereEveryone => mainConfig.AllowMentionsHereEveryone;

		public bool AllowMentionsAnyRole => mainConfig.AllowMentionsAnyRole;

		public bool AllowMentionsAnyUser => mainConfig.AllowMentionsAnyUser;

		public List<string> AllowedRoleMentions => mainConfig.AllowedRoleMentions;

		public List<string> AllowedUserMentions => mainConfig.AllowedUserMentions;

		public string LaunchMessage => messagesConfig.LaunchMessage;

		public string LoadedMessage => messagesConfig.LoadedMessage;

		public string StopMessage => messagesConfig.StopMessage;

		public string ShutdownMessage => messagesConfig.ShutdownMessage;

		public string SaveMessage => messagesConfig.SaveMessage;

		public string NewDayMessage => messagesConfig.NewDayMessage;

		public string JoinMessage => messagesConfig.JoinMessage;

		public string LeaveMessage => messagesConfig.LeaveMessage;

		public string DeathMessage => messagesConfig.DeathMessage;

		public string PingMessage => messagesConfig.PingMessage;

		public string ShoutMessage => messagesConfig.ShoutMessage;

		public string PlayerFirstDeathMessage => messagesConfig.PlayerFirstDeathMessage;

		public string PlayerFirstJoinMessage => messagesConfig.PlayerFirstJoinMessage;

		public string PlayerFirstLeaveMessage => messagesConfig.PlayerFirstLeaveMessage;

		public string PlayerFirstPingMessage => messagesConfig.PlayerFirstPingMessage;

		public string PlayerFirstShoutMessage => messagesConfig.PlayerFirstShoutMessage;

		public bool AnnouncePlayerFirstDeathEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstDeathEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstJoinEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstJoinEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstLeaveEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstLeaveEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstPingEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstPingEnabled;
				}
				return false;
			}
		}

		public bool AnnouncePlayerFirstShoutEnabled
		{
			get
			{
				if (mainConfig.AnnouncePlayerFirsts)
				{
					return togglesConfig.AnnouncePlayerFirstShoutEnabled;
				}
				return false;
			}
		}

		public string EventStartMessage => messagesConfig.EventStartMessage;

		public string EventStopMessage => messagesConfig.EventStopMessage;

		public string EventPausedMessage => messagesConfig.EventPausedMessage;

		public string EventResumedMessage => messagesConfig.EventResumedMessage;

		public string UserVariable => variableConfig.UserVariable;

		public string UserVariable1 => variableConfig.UserVariable1;

		public string UserVariable2 => variableConfig.UserVariable2;

		public string UserVariable3 => variableConfig.UserVariable3;

		public string UserVariable4 => variableConfig.UserVariable4;

		public string UserVariable5 => variableConfig.UserVariable5;

		public string UserVariable6 => variableConfig.UserVariable6;

		public string UserVariable7 => variableConfig.UserVariable7;

		public string UserVariable8 => variableConfig.UserVariable8;

		public string UserVariable9 => variableConfig.UserVariable9;

		public string PosVarFormat => variableConfig.PosVarFormat;

		public string AppendedPosFormat => variableConfig.AppendedPosFormat;

		public bool DebugEveryPlayerPosCheck => togglesConfig.DebugEveryPlayerPosCheck;

		public bool DebugEveryEventCheck => togglesConfig.DebugEveryEventCheck;

		public bool DebugEveryEventChange => togglesConfig.DebugEveryEventChange;

		public bool DebugHttpRequestResponse => togglesConfig.DebugHttpRequestResponse;

		public bool DebugDatabaseMethods => togglesConfig.DebugDatabaseMethods;

		public bool DebugLeaderboardOperations => togglesConfig.DebugLeaderboardOperations;

		public string LeaderBoardTopPlayerHeading => messagesConfig.LeaderBoardTopPlayerHeading;

		public string LeaderBoardBottomPlayersHeading => messagesConfig.LeaderBoardBottomPlayersHeading;

		public string LeaderBoardHighestHeading => messagesConfig.LeaderBoardHighestHeading;

		public string LeaderBoardLowestHeading => messagesConfig.LeaderBoardLowestHeading;

		public LeaderBoardConfigReference[] LeaderBoards => leaderBoardConfig.LeaderBoards;

		public ActivePlayersAnnouncementConfigValues ActivePlayersAnnouncement => leaderBoardConfig.ActivePlayersAnnouncement;

		public List<WebhookEntry> ExtraWebhooks => extraWebhookConfig.GetWebhookEntries();

		public PluginConfig(ConfigFile config)
		{
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			configPath = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector");
			migrateConfigIfNeeded();
			string path = "discordconnector.cfg";
			string path2 = "discordconnector-messages.cfg";
			string path3 = "discordconnector-toggles.cfg";
			string path4 = "discordconnector-variables.cfg";
			string path5 = "discordconnector-leaderBoards.cfg";
			string path6 = "discordconnector-" + ExtraWebhookConfig.ConfigExtension + ".cfg";
			string text = Path.Combine(configPath, path);
			string text2 = Path.Combine(configPath, path2);
			string text3 = Path.Combine(configPath, path3);
			string text4 = Path.Combine(configPath, path4);
			string text5 = Path.Combine(configPath, path5);
			string text6 = Path.Combine(configPath, path6);
			DiscordConnectorPlugin.StaticLogger.LogDebug("Main config: " + text);
			DiscordConnectorPlugin.StaticLogger.LogDebug("Messages config: " + text2);
			DiscordConnectorPlugin.StaticLogger.LogDebug("Toggles config: " + text3);
			DiscordConnectorPlugin.StaticLogger.LogDebug("Variable config: " + text4);
			DiscordConnectorPlugin.StaticLogger.LogDebug("Leader board config: " + text5);
			DiscordConnectorPlugin.StaticLogger.LogDebug("Extra Webhook config: " + text6);
			mainConfig = new MainConfig(new ConfigFile(text, true));
			messagesConfig = new MessagesConfig(new ConfigFile(text2, true));
			togglesConfig = new TogglesConfig(new ConfigFile(text3, true));
			variableConfig = new VariableConfig(new ConfigFile(text4, true));
			leaderBoardConfig = new LeaderBoardConfig(new ConfigFile(text5, true));
			extraWebhookConfig = new ExtraWebhookConfig(new ConfigFile(text6, true));
			DiscordConnectorPlugin.StaticLogger.LogDebug("Configuration Loaded");
			DiscordConnectorPlugin.StaticLogger.LogDebug($"Muted Players Regex pattern ('a^' is default for no matches): {mainConfig.MutedPlayersRegex}");
			DumpConfigAsJson();
		}

		internal void migrateConfigIfNeeded()
		{
			if (!Directory.Exists(configPath))
			{
				Directory.CreateDirectory(configPath);
			}
			string[] configExtensions = ConfigExtensions;
			foreach (string text in configExtensions)
			{
				string text2 = Path.Combine(Paths.ConfigPath, "discordconnector-" + text + ".cfg");
				string text3 = Path.Combine(configPath, "discordconnector-" + text + ".cfg");
				if (text.Equals("main"))
				{
					text2 = Path.Combine(Paths.ConfigPath, "discordconnector.cfg");
					text3 = Path.Combine(configPath, "discordconnector.cfg");
				}
				if (File.Exists(text2))
				{
					if (File.Exists(text3))
					{
						DiscordConnectorPlugin.StaticLogger.LogWarning("Expected to be moving " + text + " config from pre-2.1.0 location to new config location, but already exists!");
					}
					else
					{
						File.Move(text2, text3);
					}
				}
			}
		}

		public void DumpConfigAsJson()
		{
			string jsonString = "{";
			jsonString = jsonString + "\"Config.Main\":" + mainConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.Messages\":" + messagesConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.Toggles\":" + togglesConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.Variables\":" + variableConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.LeaderBoard\":" + leaderBoardConfig.ConfigAsJson() + ",";
			jsonString = jsonString + "\"Config.ExtraWebhooks\":" + extraWebhookConfig.ConfigAsJson();
			jsonString += "}";
			Task.Run(delegate
			{
				File.WriteAllText(Path.Combine(configPath, "config-dump.json"), jsonString);
				DiscordConnectorPlugin.StaticLogger.LogDebug("Dumped configuration files to config-dump.json");
			});
		}
	}
	internal class DiscordApi
	{
		public static void SendMessage(Webhook.Event ev, string message, Vector3 pos)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled)
				{
					try
					{
						string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
						EmbedBuilder embedBuilder = MessageTransformer.CreatePositionEmbed(message, serverName, pos, ev);
						SendEmbed(ev, embedBuilder);
						return;
					}
					catch (Exception ex)
					{
						DiscordConnectorPlugin.StaticLogger.LogError("Failed to create position embed: " + ex.Message);
						DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace);
						SendMessage(ev, message + " " + MessageTransformer.FormatAppendedPos(pos));
						return;
					}
				}
				SendMessage(ev, message + " " + MessageTransformer.FormatAppendedPos(pos));
			}
			catch (Exception ex2)
			{
				DiscordConnectorPlugin.StaticLogger.LogError("Error sending message with position: " + ex2.Message);
				DiscordConnectorPlugin.StaticLogger.LogDebug(ex2.StackTrace);
			}
		}

		public static void SendMessage(Webhook.Event ev, string message)
		{
			try
			{
				if (string.IsNullOrEmpty(message))
				{
					DiscordConnectorPlugin.StaticLogger.LogWarning("Attempted to send empty message");
					message = "[Empty Message]";
				}
				if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled)
				{
					try
					{
						EmbedBuilder embedBuilder = MessageTransformer.CreateServerMessageEmbed(message, ev);
						SendEmbed(ev, embedBuilder);
						return;
					}
					catch (Exception ex)
					{
						DiscordConnectorPlugin.StaticLogger.LogError("Failed to create server message embed: " + ex.Message);
						DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace);
						DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook();
						discordExecuteWebhook.content = message;
						discordExecuteWebhook.SendFor(ev);
						return;
					}
				}
				DiscordExecuteWebhook discordExecuteWebhook2 = new DiscordExecuteWebhook();
				discordExecuteWebhook2.content = message;
				discordExecuteWebhook2.SendFor(ev);
			}
			catch (Exception ex2)
			{
				DiscordConnectorPlugin.StaticLogger.LogError("Error sending message: " + ex2.Message);
				DiscordConnectorPlugin.StaticLogger.LogDebug(ex2.StackTrace);
			}
		}

		public static void SendMessageWithFields(Webhook.Event ev, string? content = null, List<Tuple<string, string>>? fields = null)
		{
			try
			{
				if (string.IsNullOrEmpty(content) && (fields == null || fields.Count == 0))
				{
					content = "Uh-oh! An unexpectedly empty message was sent!";
					DiscordConnectorPlugin.StaticLogger.LogWarning("Attempted to send message with neither content nor fields");
				}
				if (fields != null)
				{
					fields = fields.Where((Tuple<string, string> f) => f != null && !string.IsNullOrEmpty(f.Item1) && !string.IsNullOrEmpty(f.Item2)).ToList();
					if (fields.Count == 0)
					{
						fields = null;
					}
				}
				if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled)
				{
					try
					{
						EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(ev).SetDescription(content).SetTimestamp();
						if (fields != null && fields.Count > 0)
						{
							try
							{
								if (fields.Count <= 3)
								{
									embedBuilder.AddInlineFields(fields);
								}
								else
								{
									embedBuilder.AddFields(fields);
								}
							}
							catch (Exception ex)
							{
								DiscordConnectorPlugin.StaticLogger.LogError("Error processing fields for embed: " + ex.Message);
								DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace);
							}
						}
						SendEmbed(ev, embedBuilder);
						return;
					}
					catch (Exception ex2)
					{
						DiscordConnectorPlugin.StaticLogger.LogError("Failed to create embed with fields: " + ex2.Message);
						DiscordConnectorPlugin.StaticLogger.LogDebug(ex2.StackTrace);
						FallbackToLegacyFormat(ev, content, fields);
						return;
					}
				}
				FallbackToLegacyFormat(ev, content, fields);
			}
			catch (Exception ex3)
			{
				DiscordConnectorPlugin.StaticLogger.LogError("Unexpected error in SendMessageWithFields: " + ex3.Message);
				DiscordConnectorPlugin.StaticLogger.LogDebug(ex3.StackTrace);
				try
				{
					DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook();
					discordExecuteWebhook.content = "Error processing message with fields. See logs for details.";
					discordExecuteWebhook.SendFor(ev);
				}
				catch
				{
					DiscordConnectorPlugin.StaticLogger.LogError("Failed to send fallback error message");
				}
			}
		}

		private static void FallbackToLegacyFormat(Webhook.Event ev, string? content, List<Tuple<string, string>>? fields)
		{
			try
			{
				DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook
				{
					content = content
				};
				if (fields != null && fields.Count > 0)
				{
					discordExecuteWebhook.embeds = new List<DiscordEmbed>();
					List<DiscordField> list = new List<DiscordField>();
					foreach (Tuple<string, string> field in fields)
					{
						if (field != null && !string.IsNullOrEmpty(field.Item1) && !string.IsNullOrEmpty(field.Item2))
						{
							list.Add(new DiscordField
							{
								name = field.Item1,
								value = field.Item2
							});
						}
					}
					if (list.Count > 0)
					{
						discordExecuteWebhook.embeds.Add(new DiscordEmbed
						{
							fields = list
						});
					}
				}
				discordExecuteWebhook.SendFor(ev);
			}
			catch (Exception ex)
			{
				DiscordConnectorPlugin.StaticLogger.LogError("Error in fallback message format: " + ex.Message);
				DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace);
				try
				{
					DiscordExecuteWebhook discordExecuteWebhook2 = new DiscordExecuteWebhook();
					discordExecuteWebhook2.content = content ?? "Error processing message";
					discordExecuteWebhook2.SendFor(ev);
				}
				catch
				{
					DiscordConnectorPlugin.StaticLogger.LogError("Failed to send simple fallback message");
				}
			}
		}

		public static void SendEmbed(Webhook.Event ev, EmbedBuilder embedBuilder)
		{
			if (embedBuilder == null)
			{
				LogDiscordError("Null EmbedBuilder provided to SendEmbed", null, ev);
				DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook();
				discordExecuteWebhook.content = "Error: Cannot create embed with null builder.";
				discordExecuteWebhook.SendFor(ev);
				return;
			}
			try
			{
				DiscordEmbed discordEmbed;
				try
				{
					discordEmbed = embedBuilder.Build();
					if (discordEmbed == null)
					{
						throw new InvalidOperationException("Built embed was null");
					}
				}
				catch (Exception ex)
				{
					LogDiscordError("Error building embed", ex, ev);
					string content = "Error creating embed message. Please check logs.";
					try
					{
						string descriptionForFallback = embedBuilder.GetDescriptionForFallback();
						if (!string.IsNullOrEmpty(descriptionForFallback))
						{
							content = descriptionForFallback;
						}
					}
					catch (Exception ex2)
					{
						LogDiscordError("Failed to extract fallback description", ex2, ev, logStackTrace: false);
					}
					DiscordExecuteWebhook discordExecuteWebhook2 = new DiscordExecuteWebhook();
					discordExecuteWebhook2.content = content;
					discordExecuteWebhook2.SendFor(ev);
					return;
				}
				try
				{
					bool flag = true;
					if (string.IsNullOrEmpty(discordEmbed.title) && string.IsNullOrEmpty(discordEmbed.description) && (discordEmbed.fields == null || discordEmbed.fields.Count <= 0) && (discordEmbed.footer == null || string.IsNullOrEmpty(discordEmbed.footer.text)) && (discordEmbed.author == null || string.IsNullOrEmpty(discordEmbed.author.name)) && (discordEmbed.image == null || string.IsNullOrEmpty(discordEmbed.image.url)) && (discordEmbed.thumbnail == null || string.IsNullOrEmpty(discordEmbed.thumbnail.url)))
					{
						DiscordConnectorPlugin.StaticLogger.LogWarning("Embed has no visible content and may not display correctly");
						flag = false;
					}
					if (!flag)
					{
						DiscordConnectorPlugin.StaticLogger.LogWarning("Embed validation failed");
						string text = embedBuilder.GetDescriptionForFallback() ?? string.Empty;
						if (string.IsNullOrEmpty(text))
						{
							text = "Message could not be sent to Discord due to validation issues. Check logs for details.";
						}
						DiscordConnectorPlugin.StaticLogger.LogInfo("Sending plain text fallback message instead of invalid embed");
						DiscordExecuteWebhook discordExecuteWebhook3 = new DiscordExecuteWebhook();
						discordExecuteWebhook3.content = text;
						discordExecuteWebhook3.SendFor(ev);
					}
					else
					{
						DiscordExecuteWebhook discordExecuteWebhook4 = new DiscordExecuteWebhook();
						discordExecuteWebhook4.embeds = new List<DiscordEmbed>(1) { discordEmbed };
						discordExecuteWebhook4.SendFor(ev);
					}
				}
				catch (Exception ex3)
				{
					LogDiscordError("Error sending embed payload", ex3, ev);
					throw new Exception("Error sending embed payload: " + ex3.Message, ex3);
				}
			}
			catch (Exception ex4)
			{
				LogDiscordError("Failed to send embed", ex4, ev);
				try
				{
					DiscordExecuteWebhook discordExecuteWebhook5 = new DiscordExecuteWebhook();
					discordExecuteWebhook5.content = "Error sending Discord message. Please check logs.";
					discordExecuteWebhook5.SendFor(ev);
				}
				catch (Exception ex5)
				{
					LogDiscordError("Complete failure sending Discord message - even fallback failed", ex5, ev, logStackTrace: false);
				}
			}
		}

		private static void LogDiscordError(string message, Exception? ex = null, Webhook.Event? eventType = null, bool logStackTrace = true)
		{
			try
			{
				string text = (eventType.HasValue ? $" for event {eventType}" : string.Empty);
				if (ex != null)
				{
					DiscordConnectorPlugin.StaticLogger.LogError(message + text + ": " + ex.Message);
					if (logStackTrace && ex.StackTrace != null)
					{
						DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace);
					}
					if (ex.InnerException != null)
					{
						DiscordConnectorPlugin.StaticLogger.LogError("Inner exception: " + ex.InnerException.Message);
					}
				}
				else
				{
					DiscordConnectorPlugin.StaticLogger.LogError(message + text);
				}
			}
			catch
			{
				try
				{
					DiscordConnectorPlugin.StaticLogger.LogError("Failed to log Discord error details due to exception in logging");
				}
				catch
				{
				}
			}
		}

		public static void SendSerializedJson(Webhook.Event ev, string serializedJson)
		{
			DiscordConnectorPlugin.StaticLogger.LogDebug($"Finding webhooks for event: (event: {ev})");
			if (ev == Webhook.Event.Other)
			{
				DiscordConnectorPlugin.StaticLogger.LogInfo("Dispatching webhook for 3rd party plugin (configured as 'Other' in WebHook config)");
			}
			if ((string.IsNullOrEmpty(DiscordConnectorPlugin.StaticConfig.PrimaryWebhook.Url) && string.IsNullOrEmpty(DiscordConnectorPlugin.StaticConfig.SecondaryWebhook.Url)) || string.IsNullOrEmpty(serializedJson))
			{
				return;
			}
			byte[] bytes = Encoding.UTF8.GetBytes(serializedJson);
			if (DiscordConnectorPlugin.StaticConfig.PrimaryWebhook.HasEvent(ev))
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook");
				DispatchRequest(DiscordConnectorPlugin.StaticConfig.PrimaryWebhook, bytes);
			}
			if (DiscordConnectorPlugin.StaticConfig.SecondaryWebhook.HasEvent(ev))
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook");
				DispatchRequest(DiscordConnectorPlugin.StaticConfig.SecondaryWebhook, bytes);
			}
			foreach (WebhookEntry extraWebhook in DiscordConnectorPlugin.StaticConfig.ExtraWebhooks)
			{
				if (extraWebhook.HasEvent(ev))
				{
					DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Extra Webhook: {extraWebhook.Url}");
					DispatchRequest(extraWebhook, bytes);
				}
			}
		}

		public static void SendSerializedJson(WebhookEntry webhook, string serializedJson)
		{
			DiscordConnectorPlugin.StaticLogger.LogDebug("Trying webhook with payload: " + serializedJson);
			if (!string.IsNullOrEmpty(webhook.Url) && !string.IsNullOrEmpty(serializedJson))
			{
				byte[] bytes = Encoding.UTF8.GetBytes(serializedJson);
				DispatchRequest(webhook, bytes);
			}
		}

		private static void DispatchRequest(WebhookEntry webhook, byte[] byteArray)
		{
			byte[] byteArray2 = byteArray;
			if (string.IsNullOrEmpty(webhook.Url))
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug("Dispatch attempted with empty webhook - ignoring");
				return;
			}
			string requestId = GuidHelper.GenerateShortHexGuid();
			DiscordConnectorPlugin.StaticLogger.LogDebug($"DispatchRequest.{requestId}: sending {byteArray2.Length} bytes to Discord");
			WebRequest request = WebRequest.Create(webhook.Url);
			request.Method = "POST";
			request.ContentType = "application/json";
			request.ContentLength = byteArray2.Length;
			Task.Run(delegate
			{
				try
				{
					using (Stream stream = request.GetRequestStream())
					{
						stream.Write(byteArray2, 0, byteArray2.Length);
					}
					bool flag = true;
					WebResponse response;
					try
					{
						response = request.GetResponse();
						if (DiscordConnectorPlugin.StaticConfig.DebugHttpRequestResponse)
						{
							if (response is HttpWebResponse httpWebResponse)
							{
								if (httpWebResponse.StatusCode == HttpStatusCode.NoContent)
								{
									flag = false;
								}
								DiscordConnectorPlugin.StaticLogger.LogDebug($"DispatchRequest.{requestId}: Response Code: {httpWebResponse.StatusCode}");
							}
							else
							{
								DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Response was not an HttpWebResponse");
							}
						}
					}
					catch (WebException arg)
					{
						DiscordConnectorPlugin.StaticLogger.LogError($"DispatchRequest.{requestId}: Error getting web response: {arg}");
						return;
					}
					if (flag)
					{
						using Stream stream2 = response.GetResponseStream();
						if (stream2 == null)
						{
							DiscordConnectorPlugin.StaticLogger.LogError("DispatchRequest." + requestId + ": Response stream is null");
							return;
						}
						using StreamReader streamReader = new StreamReader(stream2);
						string text = streamReader.ReadToEnd();
						if (DiscordConnectorPlugin.StaticConfig.DebugHttpRequestResponse)
						{
							if (text.Length > 0)
							{
								DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Response from server: " + text);
							}
							else
							{
								DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Empty response from server (normal)");
							}
						}
					}
					response.Close();
				}
				catch (Exception arg2)
				{
					DiscordConnectorPlugin.StaticLogger.LogWarning($"Error dispatching webhook: {arg2}");
				}
			}).ConfigureAwait(continueOnCapturedContext: false);
		}

		public static void SendMessage(string message, Vector3 pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			SendMessage(Webhook.Event.Other, message, pos);
		}

		public static void SendMessage(string message)
		{
			SendMessage(Webhook.Event.Other, message);
		}

		public static void SendMessageWithFields(string? content = null, List<Tuple<string, string>>? fields = null)
		{
			SendMessageWithFields(Webhook.Event.Other, content, fields);
		}

		private static void SendSerializedJson(string serializedJson)
		{
			SendSerializedJson(Webhook.Event.Other, serializedJson);
		}
	}
	internal class DiscordExecuteWebhook
	{
		public string? content { get; set; }

		public string? username { get; set; }

		public string? avatar_url { get; set; }

		public List<DiscordEmbed>? embeds { get; set; }

		public AllowedMentions? allowed_mentions { get; set; }

		public DiscordExecuteWebhook()
		{
			allowed_mentions = new AllowedMentions();
			ResetOverrides();
		}

		public void SetUsername(string name)
		{
			username = name;
		}

		public void SetAvatarUrl(string url)
		{
			avatar_url = url;
		}

		public bool IsValid()
		{
			if (string.IsNullOrEmpty(content))
			{
				return embeds != null;
			}
			return true;
		}

		public void ResetOverrides()
		{
			username = null;
			avatar_url = null;
			if (!string.IsNullOrEmpty(DiscordConnectorPlugin.StaticConfig.DefaultWebhookUsernameOverride))
			{
				SetUsername(DiscordConnectorPlugin.StaticConfig.DefaultWebhookUsernameOverride);
			}
		}

		public void SendFor(Webhook.Event ev)
		{
			if (!IsValid())
			{
				DiscordConnectorPlugin.StaticLogger.LogWarning($"Attempted to send an invalid DiscordExecuteWebhook object:\n{this}");
				return;
			}
			try
			{
				if (DiscordConnectorPlugin.StaticConfig.PrimaryWebhook.HasEvent(ev))
				{
					DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook");
					WebhookEntry primaryWebhook = DiscordConnectorPlugin.StaticConfig.PrimaryWebhook;
					ResetOverrides();
					if (primaryWebhook.HasUsernameOverride())
					{
						SetUsername(primaryWebhook.UsernameOverride);
					}
					if (primaryWebhook.HasAvatarOverride())
					{
						SetAvatarUrl(primaryWebhook.AvatarOverride);
					}
					DiscordApi.SendSerializedJson(primaryWebhook, JsonConvert.SerializeObject(this));
				}
				if (DiscordConnectorPlugin.StaticConfig.SecondaryWebhook.HasEvent(ev))
				{
					DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook");
					WebhookEntry secondaryWebhook = DiscordConnectorPlugin.StaticConfig.SecondaryWebhook;
					ResetOverrides();
					if (secondaryWebhook.HasUsernameOverride())
					{
						SetUsername(secondaryWebhook.UsernameOverride);
					}
					if (secondaryWebhook.HasAvatarOverride())
					{
						SetAvatarUrl(secondaryWebhook.AvatarOverride);
					}
					DiscordApi.SendSerializedJson(secondaryWebhook, JsonConvert.SerializeObject(this));
				}
				foreach (WebhookEntry extraWebhook in DiscordConnectorPlugin.StaticConfig.ExtraWebhooks)
				{
					if (extraWebhook.HasEvent(ev))
					{
						DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to an Extra Webhook");
						ResetOverrides();
						if (extraWebhook.HasUsernameOverride())
						{
							SetUsername(extraWebhook.UsernameOverride);
						}
						if (extraWebhook.HasAvatarOverride())
						{
							SetAvatarUrl(extraWebhook.AvatarOverride);
						}
						DiscordApi.SendSerializedJson(extraWebhook, JsonConvert.SerializeObject(this));
					}
				}
			}
			catch (Exception arg)
			{
				DiscordConnectorPlugin.StaticLogger.LogWarning($"Error serializing payload: {arg}");
			}
		}
	}
	internal class AllowedMentions
	{
		public List<string> parse { get; set; }

		public List<string> roles { get; set; }

		public List<string> users { get; set; }

		public bool replied_user { get; set; }

		public AllowedMentions()
		{
			parse = new List<string>();
			roles = new List<string>();
			users = new List<string>();
			replied_user = false;
			if (DiscordConnectorPlugin.StaticConfig.AllowMentionsHereEveryone)
			{
				AllowEveryone();
			}
			if (DiscordConnectorPlugin.StaticConfig.AllowMentionsAnyRole)
			{
				AllowAnyRoles();
			}
			if (DiscordConnectorPlugin.StaticConfig.AllowMentionsAnyUser)
			{
				AllowAnyUsers();
			}
			if (DiscordConnectorPlugin.StaticConfig.AllowedRoleMentions.Count > 0)
			{
				AllowRoles(DiscordConnectorPlugin.StaticConfig.AllowedRoleMentions);
			}
			if (DiscordConnectorPlugin.StaticConfig.AllowedUserMentions.Count > 0)
			{
				AllowUsers(DiscordConnectorPlugin.StaticConfig.AllowedUserMentions);
			}
		}

		public void AllowEveryone()
		{
			if (!parse.Contains("everyone"))
			{
				parse.Add("everyone");
			}
		}

		public void AllowHere()
		{
			if (!parse.Contains("everyone"))
			{
				parse.Add("everyone");
			}
		}

		public void AllowRole(string role_id)
		{
			if (!roles.Contains(role_id))
			{
				roles.Add(role_id);
			}
		}

		public void AllowRoles(List<string> role_ids)
		{
			foreach (string role_id in role_ids)
			{
				AllowRole(role_id);
			}
		}

		public void DisallowRole(string role_id)
		{
			if (roles.Contains(role_id))
			{
				roles.Remove(role_id);
			}
		}

		public void AllowUser(string user_id)
		{
			if (!users.Contains(user_id))
			{
				users.Add(user_id);
			}
		}

		public void AllowUsers(List<string> user_ids)
		{
			foreach (string user_id in user_ids)
			{
				AllowUser(user_id);
			}
		}

		public void DisallowUser(string user_id)
		{
			if (users.Contains(user_id))
			{
				users.Remove(user_id);
			}
		}

		public void AllowAnyRoles()
		{
			if (!parse.Contains("roles"))
			{
				parse.Add("roles");
			}
		}

		public void AllowAnyUsers()
		{
			if (!parse.Contains("users"))
			{
				parse.Add("users");
			}
		}

		public void DisallowAnyRoles()
		{
			if (parse.Contains("roles"))
			{
				parse.Remove("roles");
			}
		}

		public void DisallowAnyUsers()
		{
			if (parse.Contains("users"))
			{
				parse.Remove("users");
			}
		}
	}
	internal class DiscordEmbed
	{
		public string? title { get; set; }

		public string? description { get; set; }

		public string? url { get; set; }

		public string? timestamp { get; set; }

		public int? color { get; set; }

		public DiscordEmbedAuthor? author { get; set; }

		public DiscordEmbedFooter? footer { get; set; }

		public DiscordEmbedThumbnail? thumbnail { get; set; }

		public DiscordEmbedImage? image { get; set; }

		public List<DiscordField>? fields { get; set; }
	}
	internal class DiscordField
	{
		public string? name { get; set; }

		public string? value { get; set; }

		public bool? inline { get; set; }
	}
	internal class DiscordEmbedAuthor
	{
		public string? name { get; set; }

		public string? url { get; set; }

		public string? icon_url { get; set; }
	}
	internal class DiscordEmbedFooter
	{
		public string? text { get; set; }

		public string? icon_url { get; set; }
	}
	internal class DiscordEmbedThumbnail
	{
		public string url { get; set; } = "";


		public string? proxy_url { get; set; }

		public int? height { get; set; }

		public int? width { get; set; }
	}
	internal class DiscordEmbedImage
	{
		public string url { get; set; } = "";


		public string? proxy_url { get; set; }

		public int? height { get; set; }

		public int? width { get; set; }
	}
	internal class EmbedBuilder
	{
		private const int MAX_FIELDS_PER_ROW = 3;

		public const int MAX_FIELDS_COUNT = 25;

		public const string DEFAULT_COLOR = "#7289DA";

		public const string DEFAULT_SERVER_START_COLOR = "#43B581";

		public const string DEFAULT_SERVER_STOP_COLOR = "#F04747";

		public const string DEFAULT_PLAYER_JOIN_COLOR = "#43B581";

		public const string DEFAULT_PLAYER_LEAVE_COLOR = "#FAA61A";

		public const string DEFAULT_DEATH_EVENT_COLOR = "#F04747";

		public const string DEFAULT_SHOUT_MESSAGE_COLOR = "#7289DA";

		public const string DEFAULT_POSITION_MESSAGE_COLOR = "#7289DA";

		public const string DEFAULT_OTHER_EVENT_COLOR = "#747F8D";

		private readonly PluginConfig _config;

		private readonly DiscordEmbed _embed;

		private readonly List<DiscordField> _fields;

		private int _currentRowFieldCount;

		public EmbedBuilder()
		{
			_embed = new DiscordEmbed();
			_fields = new List<DiscordField>();
			_currentRowFieldCount = 0;
			_config = DiscordConnectorPlugin.StaticConfig;
		}

		public EmbedBuilder SetTitle(string? title)
		{
			if (_config.EmbedTitleEnabled)
			{
				_embed.title = title;
			}
			return this;
		}

		public EmbedBuilder SetDescription(string? description)
		{
			if (_config.EmbedDescriptionEnabled)
			{
				_embed.description = description;
			}
			return this;
		}

		public EmbedBuilder SetUrl(string? url)
		{
			_embed.url = url;
			return this;
		}

		public EmbedBuilder SetUrlFromTemplate(Dictionary<string, string>? variables = null)
		{
			if (string.IsNullOrEmpty(_config.EmbedUrlTemplate))
			{
				return this;
			}
			string text = _config.EmbedUrlTemplate;
			if (variables != null)
			{
				foreach (KeyValuePair<string, string> variable in variables)
				{
					text = text.Replace("{" + variable.Key + "}", variable.Value ?? string.Empty);
				}
			}
			return SetUrl(text);
		}

		public EmbedBuilder SetColor(int color)
		{
			_embed.color = Math.Max(0, Math.Min(color, 16777215));
			return this;
		}

		public EmbedBuilder SetColor(string hexColor)
		{
			_embed.color = HexColorToDecimal(hexColor);
			return this;
		}

		private int HexColorToDecimal(string hexColor)
		{
			if (string.IsNullOrEmpty(hexColor))
			{
				hexColor = "#7289DA";
			}
			if (!hexColor.StartsWith("#"))
			{
				hexColor = "#" + hexColor;
			}
			try
			{
				string text = hexColor.TrimStart(new char[1] { '#' });
				if (text.Length != 6)
				{
					text = "#7289DA".TrimStart(new char[1] { '#' });
				}
				return Convert.ToInt32(text, 16);
			}
			catch
			{
				return Convert.ToInt32("#7289DA".TrimStart(new char[1] { '#' }), 16);
			}
		}

		public EmbedBuilder SetColorForEvent(Webhook.Event eventType)
		{
			string text = "#7289DA";
			text = ((!Webhook.ServerLaunchEvents.Contains(eventType) && !Webhook.ServerStartEvents.Contains(eventType)) ? ((Webhook.ServerStopEvents.Contains(eventType) || Webhook.ServerShutdownEvents.Contains(eventType)) ? _config.EmbedServerStopColor : (Webhook.ServerSaveEvents.Contains(eventType) ? _config.EmbedServerStartColor : (Webhook.PlayerJoinEvents.Contains(eventType) ? _config.EmbedPlayerJoinColor : (Webhook.PlayerLeaveEvents.Contains(eventType) ? _config.EmbedPlayerLeaveColor : (Webhook.PlayerDeathEvents.Contains(eventType) ? _config.EmbedDeathEventColor : (Webhook.PlayerShoutEvents.Contains(eventType) ? _config.EmbedShoutMessageColor : (Webhook.PlayerPingEvents.Contains(eventType) ? _config.EmbedPositionMessageColor : ((!Webhook.WorldEvents.Contains(eventType)) ? _config.EmbedOtherEventColor : _config.EmbedWorldEventColor)))))))) : _config.EmbedServerStartColor);
			return SetColor(text);
		}

		public EmbedBuilder SetAuthor(string? name, string? url = null, string? iconUrl = null)
		{
			if (_config.EmbedAuthorEnabled)
			{
				_embed.author = new DiscordEmbedAuthor
				{
					name = name,
					url = url,
					icon_url = iconUrl
				};
			}
			return this;
		}

		public EmbedBuilder SetThumbnail(string? url)
		{
			if (_config.EmbedThumbnailEnabled && !string.IsNullOrEmpty(url))
			{
				_embed.thumbnail = new DiscordEmbedThumbnail
				{
					url = url
				};
			}
			return this;
		}

		public EmbedBuilder SetImage(string? url)
		{
			if (!string.IsNullOrEmpty(url))
			{
				_embed.image = new DiscordEmbedImage
				{
					url = url
				};
			}
			return this;
		}

		public EmbedBuilder SetFooter(string? text, string? iconUrl = null)
		{
			if (_config.EmbedFooterEnabled)
			{
				_embed.footer = new DiscordEmbedFooter
				{
					text = text,
					icon_url = iconUrl
				};
			}
			return this;
		}

		public EmbedBuilder SetFooterFromTemplate(Dictionary<string, string>? variables = null, string? iconUrl = null)
		{
			if (!_config.EmbedFooterEnabled || string.IsNullOrEmpty(_config.EmbedFooterText))
			{
				return this;
			}
			string text = _config.EmbedFooterText;
			if (variables != null)
			{
				foreach (KeyValuePair<string, string> variable in variables)
				{
					text = text.Replace("{" + variable.Key + "}", variable.Value);
				}
			}
			return SetFooter(text, iconUrl);
		}

		public EmbedBuilder SetTimestamp(DateTimeOffset? timestamp = null)
		{
			if (_config.EmbedTimestampEnabled)
			{
				_embed.timestamp = (timestamp ?? DateTimeOffset.UtcNow).ToString("o");
			}
			return this;
		}

		public EmbedBuilder AddField(string? name, string? value, bool inline = false)
		{
			if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value))
			{
				return this;
			}
			if (_fields.Count >= 25)
			{
				DiscordConnectorPlugin.StaticLogger.LogWarning($"Cannot add more than {25} fields to a Discord embed.");
				return this;
			}
			_fields.Add(new DiscordField
			{
				name = name,
				value = value,
				inline = inline
			});
			if (inline)
			{
				_currentRowFieldCount++;
				if (_currentRowFieldCount >= 3)
				{
					_currentRowFieldCount = 0;
				}
			}
			else
			{
				_currentRowFieldCount = 0;
			}
			return this;
		}

		public EmbedBuilder AddInlineField(string? name, string? value)
		{
			return AddField(name, value, inline: true);
		}

		public EmbedBuilder AddPositionField(Vector3 position, bool inline = true)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			string value = MessageTransformer.FormatVector3AsPos(position);
			return AddField("Position", value, inline);
		}

		public EmbedBuilder AddRowBreak()
		{
			if (_currentRowFieldCount > 0)
			{
				_fields.Add(new DiscordField
				{
					name = "\u200b",
					value = "\u200b",
					inline = false
				});
				_currentRowFieldCount = 0;
			}
			return this;
		}

		public EmbedBuilder AddFields(List<Tuple<string, string>> fields, bool inline = false)
		{
			if (fields == null || fields.Count == 0)
			{
				return this;
			}
			foreach (Tuple<string, string> field in fields)
			{
				AddField(field.Item1, field.Item2, inline);
			}
			return this;
		}

		public EmbedBuilder AddInlineFields(List<Tuple<string, string>> fields)
		{
			return AddFields(fields, inline: true);
		}

		public EmbedBuilder AddPositionField(Vector3 position)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (_config.SendPositionsEnabled)
			{
				string value = MessageTransformer.FormatVector3AsPos(position);
				AddField("Coordinates", value);
			}
			return this;
		}

		public EmbedBuilder OrganizeFields()
		{
			if (_fields.Count == 0)
			{
				return this;
			}
			if (_config.EmbedFieldDisplayOrder == null || _config.EmbedFieldDisplayOrder.Count == 0)
			{
				return this;
			}
			_ = _config.EmbedFieldDisplayOrder.Count;
			return this;
		}

		public DiscordEmbed Build()
		{
			if (_fields.Count > 0)
			{
				_embed.fields = _fields;
			}
			if (!IsWithinCharacterLimit())
			{
				DiscordConnectorPlugin.StaticLogger.LogWarning("Embed exceeds Discord's character limit and will be truncated.");
				TruncateToFitCharacterLimit();
			}
			return _embed;
		}

		private bool IsWithinCharacterLimit()
		{
			int num = 0;
			num += _embed.title?.Length ?? 0;
			num += _embed.description?.Length ?? 0;
			num += (_embed.footer?.text?.Length).GetValueOrDefault();
			num += (_embed.author?.name?.Length).GetValueOrDefault();
			if (_fields != null && _fields.Count > 0)
			{
				foreach (DiscordField field in _fields)
				{
					num += field.name?.Length ?? 0;
					num += field.value?.Length ?? 0;
				}
			}
			return num <= 6000;
		}

		private void TruncateToFitCharacterLimit()
		{
			if (!string.IsNullOrEmpty(_embed.description))
			{
				string? description = _embed.description;
				if (description != null && description.Length > 1000)
				{
					_embed.description = _embed.description.Substring(0, 1000) + "...";
				}
			}
			if (_fields.Count > 0)
			{
				foreach (DiscordField field in _fields)
				{
					if (!string.IsNullOrEmpty(field.value))
					{
						string? value = field.value;
						if (value != null && value.Length > 500)
						{
							field.value = field.value.Substring(0, 500) + "...";
						}
					}
				}
			}
			while (_fields.Count > 1 && !IsWithinCharacterLimit())
			{
				_fields.RemoveAt(_fields.Count - 1);
			}
		}

		public string? GetDescriptionForFallback()
		{
			try
			{
				if (!string.IsNullOrEmpty(_embed.description))
				{
					return _embed.description;
				}
				if (!string.IsNullOrEmpty(_embed.title))
				{
					return _embed.title;
				}
				if (_embed.author != null && !string.IsNullOrEmpty(_embed.author.name))
				{
					return _embed.author.name;
				}
				if (_fields.Count > 0)
				{
					List<string> list = new List<string>();
					int num = Math.Min(_fields.Count, 3);
					for (int i = 0; i < num; i++)
					{
						if (!string.IsNullOrEmpty(_fields[i].name) && !string.IsNullOrEmpty(_fields[i].value))
						{
							string text = _fields[i].name + ": " + _fields[i].value;
							if (text != null && text.Length > 100)
							{
								text = text.Substring(0, 100) + "...";
							}
							if (text != null)
							{
								list.Add(text);
							}
						}
					}
					if (list.Count > 0)
					{
						return string.Join(" | ", list);
					}
				}
				return null;
			}
			catch (Exception ex)
			{
				DiscordConnectorPlugin.StaticLogger.LogError("Error extracting fallback content: " + ex.Message);
				return null;
			}
		}
	}
	internal static class EmbedTemplates
	{
		public static EmbedBuilder ServerLifecycle(Webhook.Event eventType, string message, string worldName, string serverName)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "worldName", worldName },
				{ "serverName", serverName },
				{
					"timestamp",
					DateTime.UtcNow.ToString("s")
				}
			};
			EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp();
			if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
			{
				embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
			}
			if (Webhook.ServerLaunchEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\ude80 Server Launching");
			}
			else if (Webhook.ServerStartEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("✅ Server Started");
			}
			else if (Webhook.ServerStopEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\uded1 Server Stopping");
			}
			else if (Webhook.ServerShutdownEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("⛔ Server Shutdown");
			}
			else if (Webhook.ServerSaveEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\udcbe World Saved");
			}
			embedBuilder.SetDescription(message);
			embedBuilder.AddInlineField("World", worldName);
			embedBuilder.AddInlineField("Status", GetStatusForEvent(eventType));
			embedBuilder.SetFooterFromTemplate(dictionary);
			embedBuilder.SetUrlFromTemplate(dictionary);
			return embedBuilder;
		}

		public static EmbedBuilder PlayerEvent(Webhook.Event eventType, string message, string playerName, Vector3? position = null, string worldName = "", string playerHostName = "")
		{
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "worldName", worldName },
				{ "playerName", playerName },
				{
					"timestamp",
					DateTime.UtcNow.ToString("s")
				}
			};
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp();
			if (Webhook.PlayerJoinEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\udc4b Player Joined");
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			else if (Webhook.PlayerLeaveEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\udeb6 Player Left");
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			else if (Webhook.PlayerDeathEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\udc80 Player Death");
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			else if (Webhook.PlayerPingEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\udccd Player Pings");
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			embedBuilder.SetDescription(message);
			embedBuilder.AddInlineField("Player", playerName);
			if (DiscordConnectorPlugin.StaticConfig.ShowPlayerIds && !string.IsNullOrEmpty(playerHostName))
			{
				embedBuilder.AddInlineField("Player ID", playerHostName);
			}
			if (position.HasValue)
			{
				embedBuilder.AddPositionField(position.Value);
			}
			embedBuilder.SetFooterFromTemplate(dictionary);
			embedBuilder.SetUrlFromTemplate(dictionary);
			return embedBuilder;
		}

		public static EmbedBuilder WorldEvent(Webhook.Event eventType, string message, string eventName, string worldName)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "worldName", worldName },
				{ "eventName", eventName },
				{
					"timestamp",
					DateTime.UtcNow.ToString("s")
				}
			};
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp();
			if (Webhook.Event.EventStart == eventType)
			{
				embedBuilder.SetTitle("\ud83c\udf29\ufe0f Event Started: " + eventName);
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor);
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			else if (Webhook.Event.EventStop == eventType)
			{
				embedBuilder.SetTitle("☀\ufe0f Event Ended: " + eventName);
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor);
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			else if (Webhook.Event.NewDayNumber == eventType)
			{
				embedBuilder.SetTitle("\ud83c\udf05 New Day: " + eventName);
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedNewDayColor);
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			else if (Webhook.Event.ServerSave == eventType)
			{
				embedBuilder.SetTitle("\ud83d\udcbe World Saved");
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedServerSaveColor);
			}
			embedBuilder.SetDescription(message);
			embedBuilder.SetFooterFromTemplate(dictionary);
			embedBuilder.SetUrlFromTemplate(dictionary);
			return embedBuilder;
		}

		public static EmbedBuilder ChatMessage(Webhook.Event eventType, string message, string playerName, Vector3? position = null, string worldName = "")
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "worldName", worldName },
				{ "playerName", playerName },
				{
					"timestamp",
					DateTime.UtcNow.ToString("s")
				}
			};
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp();
			embedBuilder.AddInlineField("Player", playerName);
			if (Webhook.PlayerShoutEvents.Contains(eventType))
			{
				embedBuilder.SetTitle("\ud83d\udce3 Shout Message");
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			else
			{
				embedBuilder.SetTitle("\ud83d\udcac Chat Message");
				if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
				{
					embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
				}
			}
			embedBuilder.SetDescription("> " + message);
			if (position.HasValue)
			{
				embedBuilder.AddPositionField(position.Value);
			}
			embedBuilder.SetFooterFromTemplate(dictionary);
			embedBuilder.SetUrlFromTemplate(dictionary);
			return embedBuilder;
		}

		public static EmbedBuilder PositionMessage(Webhook.Event eventType, string message, string playerName, Vector3 position, string worldName = "")
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "worldName", worldName },
				{ "playerName", playerName },
				{
					"timestamp",
					DateTime.UtcNow.ToString("s")
				}
			};
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			EmbedBuilder embedBuilder = new EmbedBuilder().SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp();
			if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
			{
				embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
			}
			if (Webhook.Event.EventStop == eventType)
			{
				embedBuilder.SetTitle("☀\ufe0f Event Stopped");
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor);
			}
			else if (Webhook.Event.EventStart == eventType)
			{
				embedBuilder.SetTitle("\ud83c\udf29\ufe0f Event Started");
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor);
			}
			else if (Webhook.Event.EventPaused == eventType)
			{
				embedBuilder.SetTitle("⏸\ufe0f Event Paused");
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor);
			}
			else if (Webhook.Event.EventResumed == eventType)
			{
				embedBuilder.SetTitle("▶\ufe0f Event Resumed");
				embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor);
			}
			else
			{
				embedBuilder.SetTitle("Event Update");
			}
			embedBuilder.SetDescription(message);
			embedBuilder.AddField("Coordinates", MessageTransformer.FormatVector3AsPos(position));
			embedBuilder.SetFooterFromTemplate(dictionary);
			embedBuilder.SetUrlFromTemplate(dictionary);
			return embedBuilder;
		}

		public static EmbedBuilder ActivePlayersAnnouncement(string message, string worldName = "")
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "worldName", worldName },
				{
					"timestamp",
					DateTime.UtcNow.ToString("s")
				}
			};
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			EmbedBuilder embedBuilder = new EmbedBuilder().SetColor(DiscordConnectorPlugin.StaticConfig.EmbedActivePlayersColor).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTitle("\ud83d\udc65 Active Players")
				.SetDescription(message)
				.SetTimestamp();
			if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
			{
				embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
			}
			embedBuilder.SetFooterFromTemplate(dictionary);
			embedBuilder.SetUrlFromTemplate(dictionary);
			return embedBuilder;
		}

		public static EmbedBuilder LeaderboardEmbed(string title, List<Tuple<string, string>> fields, string worldName = "")
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "worldName", worldName },
				{
					"timestamp",
					DateTime.UtcNow.ToString("s")
				}
			};
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			EmbedBuilder embedBuilder = new EmbedBuilder().SetColor(DiscordConnectorPlugin.StaticConfig.EmbedLeaderboardEmbedColor).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTitle("\ud83c\udfc6 " + title)
				.SetTimestamp();
			if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
			{
				embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
			}
			foreach (Tuple<string, string> field in fields)
			{
				embedBuilder.AddField(field.Item1, MessageTransformer.FormatFieldContent(field.Item2));
			}
			embedBuilder.SetFooterFromTemplate(dictionary);
			embedBuilder.SetUrlFromTemplate(dictionary);
			return embedBuilder;
		}

		private static string GetStatusForEvent(Webhook.Event eventType)
		{
			if (Webhook.ServerLaunchEvents.Contains(eventType))
			{
				return "Launching";
			}
			if (Webhook.ServerStartEvents.Contains(eventType))
			{
				return "Online";
			}
			if (Webhook.ServerStopEvents.Contains(eventType))
			{
				return "Stopping";
			}
			if (Webhook.ServerShutdownEvents.Contains(eventType))
			{
				return "Offline";
			}
			return eventType switch
			{
				Webhook.Event.ServerSave => "Online", 
				Webhook.Event.NewDayNumber => "Online", 
				_ => "Unknown", 
			};
		}
	}
	internal class EventWatcher
	{
		private static class Status
		{
			public static bool HaveActiveEvent => RandEventSystem.HaveActiveEvent();

			public static RandomEvent? Event
			{
				get
				{
					if (!HaveActiveEvent)
					{
						return null;
					}
					return RandEventSystem.instance.GetCurrentRandomEvent();
				}
			}

			public static string Name
			{
				get
				{
					if (!HaveActiveEvent || Event == null)
					{
						return "";
					}
					return Event.m_name;
				}
			}

			public static float Duration
			{
				get
				{
					if (!HaveActiveEvent || Event == null)
					{
						return 0f;
					}
					return Event.m_duration;
				}
			}

			public static float Elapsed
			{
				get
				{
					if (!HaveActiveEvent || Event == null)
					{
						return 0f;
					}
					return Event.m_time;
				}
			}

			public static bool IsRunning
			{
				get
				{
					if (HaveActiveEvent)
					{
						return RandEventSystem.instance.IsAnyPlayerInEventArea(Event);
					}
					return false;
				}
			}

			public static Vector3 Pos
			{
				get
				{
					//IL_001d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0028: Unknown result type (might be due to invalid IL or missing references)
					if (!HaveActiveEvent || Event == null)
					{
						return new Vector3(0f, 0f, 0f);
					}
					return Event.m_pos;
				}
			}

			public static string EndMessage
			{
				get
				{
					if (!HaveActiveEvent || Event == null)
					{
						return "";
					}
					return Localization.instance.Localize(Event.m_endMessage);
				}
			}

			public static string StartMessage
			{
				get
				{
					if (!HaveActiveEvent || Event == null)
					{
						return "";
					}
					return Localization.instance.Localize(Event.m_startMessage);
				}
			}

			public static string[] InvolvedPlayersList()
			{
				//IL_002b: 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_0031: 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_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: 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_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
				List<string> list = new List<string>();
				if (!HaveActiveEvent)
				{
					return list.ToArray();
				}
				foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
				{
					if (!player.m_publicPosition)
					{
						if (DiscordConnectorPlugin.StaticConfig.DebugEveryPlayerPosCheck)
						{
							DiscordConnectorPlugin.StaticLogger.LogDebug("Unable to check location for " + player.m_name + " because their location is not public.");
						}
					}
					else if (RandEventSystem.instance.IsInsideRandomEventArea(Event, player.m_position))
					{
						list.Add(player.m_name);
						if (DiscordConnectorPlugin.StaticConfig.DebugEveryPlayerPosCheck)
						{
							DiscordConnectorPlugin.StaticLogger.LogDebug($"{player.m_name} is at {player.m_position}");
						}
					}
				}
				return list.ToArray();
			}
		}

		private readonly System.Timers.Timer randEventTimer;

		private float PreviousElapsed;

		private Vector3 PreviousEventPos;

		private string PreviousEventStartMessage;

		private string PreviousEventEndMessage;

		private bool WasRunning;

		private bool HadActiveEvent;

		public EventWatcher()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			WasRunning = false;
			HadActiveEvent = false;
			PreviousElapsed = 0f;
			PreviousEventStartMessage = "";
			PreviousEventEndMessage = "";
			PreviousEventPos = default(Vector3);
			randEventTimer = new System.Timers.Timer();
			randEventTimer.Elapsed += CheckRandomEvent;
			randEventTimer.Interval = 1000.0;
		}

		public void Activate()
		{
			randEventTimer.Start();
		}

		public void Dispose()
		{
			randEventTimer.Stop();
		}

		public void CheckRandomEvent(object sender, ElapsedEventArgs elapsedEventArgs)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			if (Status.HaveActiveEvent)
			{
				string message = $"Currently an event: {Status.HaveActiveEvent}. {Status.StartMessage} | {Status.EndMessage}" + Environment.NewLine + $"Event: {Status.Name} at {Status.Pos}. Status.IsRunning: {Status.IsRunning}. {Status.Elapsed} of {Status.Duration} seconds completed." + Environment.NewLine + $"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Involved Players: " + string.Join(",", Status.InvolvedPlayersList());
				if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventCheck)
				{
					DiscordConnectorPlugin.StaticLogger.LogDebug(message);
				}
				if (Status.IsRunning)
				{
					if (!HadActiveEvent)
					{
						TriggerEventStart();
						if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange)
						{
							DiscordConnectorPlugin.StaticLogger.LogDebug(message);
						}
					}
					if (HadActiveEvent && !WasRunning)
					{
						TriggerEventResumed();
						if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange)
						{
							DiscordConnectorPlugin.StaticLogger.LogDebug(message);
						}
					}
				}
				else if (!HadActiveEvent || (HadActiveEvent && WasRunning))
				{
					TriggerEventPaused();
					if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange)
					{
						DiscordConnectorPlugin.StaticLogger.LogDebug(message);
					}
				}
				if (Status.Pos != Vector3.zero)
				{
					PreviousEventStartMessage = Status.StartMessage;
					PreviousEventEndMessage = Status.EndMessage;
					PreviousEventPos = Status.Pos;
				}
			}
			else
			{
				if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventCheck)
				{
					DiscordConnectorPlugin.StaticLogger.LogDebug($"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Event check ran, no current events (or world isn't loaded yet).");
				}
				if (HadActiveEvent)
				{
					TriggerEventStop();
					if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange)
					{
						DiscordConnectorPlugin.StaticLogger.LogDebug("Event stopped!");
					}
				}
			}
			HadActiveEvent = Status.HaveActiveEvent;
			WasRunning = Status.IsRunning;
			PreviousElapsed = Status.Elapsed;
		}

		internal void TriggerEventStart()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (DiscordConnectorPlugin.StaticConfig.EventStartMessageEnabled)
			{
				string text = MessageTransformer.FormatEventStartMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage);
				if (!DiscordConnectorPlugin.StaticConfig.EventStartPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventStart, text);
					return;
				}
				if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventStart, text, Status.Pos);
					return;
				}
				text = MessageTransformer.FormatEventStartMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.EndMessage, Status.StartMessage, Status.Pos);
				DiscordApi.SendMessage(Webhook.Event.EventStart, text);
			}
		}

		internal void TriggerEventPaused()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (DiscordConnectorPlugin.StaticConfig.EventPausedMessageEnabled)
			{
				string text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage);
				if (!DiscordConnectorPlugin.StaticConfig.EventPausedPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventPaused, text);
					return;
				}
				if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventPaused, text, Status.Pos);
					return;
				}
				text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage, Status.Pos);
				DiscordApi.SendMessage(Webhook.Event.EventPaused, text);
			}
		}

		internal void TriggerEventResumed()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (DiscordConnectorPlugin.StaticConfig.EventResumedMessageEnabled)
			{
				string text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage);
				if (!DiscordConnectorPlugin.StaticConfig.EventResumedPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventResumed, text);
					return;
				}
				if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventResumed, text, Status.Pos);
					return;
				}
				text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage, Status.Pos);
				DiscordApi.SendMessage(Webhook.Event.EventResumed, text);
			}
		}

		internal void TriggerEventStop()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (DiscordConnectorPlugin.StaticConfig.EventStopMessageEnabled)
			{
				string text = MessageTransformer.FormatEventEndMessage(DiscordConnectorPlugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage);
				if (!DiscordConnectorPlugin.StaticConfig.EventStopPosEnabled)
				{
					DiscordApi.SendMessage(Webhook.Event.EventStop, text);
					return;
				}
				if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))
				{
					DiscordApi.SendMessage(Webhook.Event.EventStop, text, PreviousEventPos);
					return;
				}
				text = MessageTransformer.FormatEventEndMessage(DiscordConnectorPlugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage, PreviousEventPos);
				DiscordApi.SendMessage(Webhook.Event.EventStop, text);
			}
		}
	}
	internal static class Handlers
	{
		public static HashSet<string> joinedPlayers = new HashSet<string>();

		public static void Join(ZNetPeer peer)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Join - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerJoin;
			string text = peer.m_socket.GetHostName() ?? "";
			if (!joinedPlayers.Add(text))
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug(text + " already exists in list of joined players.");
				if (((ZDOID)(ref peer.m_characterID)).ID != 0)
				{
					Death(peer);
				}
				return;
			}
			DiscordConnectorPlugin.StaticLogger.LogDebug($"Added player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) to joined player list.");
			string text2 = "";
			if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstJoinEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("join", peer.m_playerName) == 0)
			{
				text2 = DiscordConnectorPlugin.StaticConfig.PlayerFirstJoinMessage;
				ev = Webhook.Event.PlayerFirstJoin;
			}
			else if (DiscordConnectorPlugin.StaticConfig.PlayerJoinMessageEnabled)
			{
				text2 = DiscordConnectorPlugin.StaticConfig.JoinMessage;
			}
			if (DiscordConnectorPlugin.StaticConfig.StatsJoinEnabled)
			{
				DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("join", peer.m_playerName, text, peer.m_refPos);
			}
			if (!string.IsNullOrEmpty(text2))
			{
				FinalizeFormattingAndSend(peer, text, text2, DiscordConnectorPlugin.StaticConfig.PlayerJoinPosEnabled, ev);
			}
		}

		public static void Leave(ZNetPeer peer)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Leave - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerLeave;
			string text = peer.m_socket.GetHostName() ?? "";
			if (!joinedPlayers.Remove(text))
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug(text + " did not exist in the list of joined players!");
				return;
			}
			DiscordConnectorPlugin.StaticLogger.LogDebug($"Removed player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) from joined player list.");
			string text2 = "";
			if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstLeaveEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("leave", peer.m_playerName) == 0)
			{
				text2 = DiscordConnectorPlugin.StaticConfig.PlayerFirstLeaveMessage;
				ev = Webhook.Event.PlayerFirstLeave;
			}
			else if (DiscordConnectorPlugin.StaticConfig.PlayerLeaveMessageEnabled)
			{
				text2 = DiscordConnectorPlugin.StaticConfig.LeaveMessage;
			}
			if (DiscordConnectorPlugin.StaticConfig.StatsLeaveEnabled)
			{
				DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("leave", peer.m_playerName, text, peer.m_refPos);
			}
			if (!string.IsNullOrEmpty(text2))
			{
				FinalizeFormattingAndSend(peer, text, text2, DiscordConnectorPlugin.StaticConfig.PlayerLeavePosEnabled, ev);
			}
		}

		public static void Death(ZNetPeer peer)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Death - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerDeath;
			string playerHostName = peer.m_socket.GetHostName() ?? "";
			string text = "";
			if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstDeathEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("death", peer.m_playerName) == 0)
			{
				text = DiscordConnectorPlugin.StaticConfig.PlayerFirstDeathMessage;
				ev = Webhook.Event.PlayerFirstDeath;
			}
			else if (DiscordConnectorPlugin.StaticConfig.PlayerDeathMessageEnabled)
			{
				text = DiscordConnectorPlugin.StaticConfig.DeathMessage;
			}
			if (DiscordConnectorPlugin.StaticConfig.StatsDeathEnabled)
			{
				DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("death", peer.m_playerName, playerHostName, peer.m_refPos);
			}
			if (!string.IsNullOrEmpty(text))
			{
				FinalizeFormattingAndSend(peer, playerHostName, text, DiscordConnectorPlugin.StaticConfig.PlayerDeathPosEnabled, ev);
			}
		}

		public static void Ping(ZNetPeer peer, Vector3 pos)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Ping - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerPing;
			string playerHostName = peer.m_socket.GetHostName() ?? "";
			string text = "";
			if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstPingEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("ping", peer.m_playerName) == 0)
			{
				text = DiscordConnectorPlugin.StaticConfig.PlayerFirstPingMessage;
				ev = Webhook.Event.PlayerFirstPing;
			}
			else if (DiscordConnectorPlugin.StaticConfig.ChatPingEnabled)
			{
				text = DiscordConnectorPlugin.StaticConfig.PingMessage;
			}
			if (DiscordConnectorPlugin.StaticConfig.StatsPingEnabled)
			{
				DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("ping", peer.m_playerName, playerHostName, pos);
			}
			if (!string.IsNullOrEmpty(text))
			{
				FinalizeFormattingAndSend(peer, playerHostName, text, DiscordConnectorPlugin.StaticConfig.ChatPingPosEnabled, pos, ev);
			}
		}

		public static void Shout(ZNetPeer peer, Vector3 pos, string text)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (peer == null)
			{
				DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Shout - Guarded against null peer");
				return;
			}
			Webhook.Event ev = Webhook.Event.PlayerShout;
			string playerHostName = peer.m_socket.GetHostName() ?? "";
			string text2 = "";
			if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstShoutEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("shout", peer.m_playerName) == 0)
			{
				text2 = DiscordConnectorPlugin.StaticConfig.PlayerFirstShoutMessage;
				ev = Webhook.Event.PlayerFirstShout;
			}
			else if (DiscordConnectorPlugin.StaticConfig.ChatShoutEnabled)
			{
				text2 = DiscordConnectorPlugin.StaticConfig.ShoutMessage;
			}
			if (DiscordConnectorPlugin.StaticConfig.StatsShoutEnabled)
			{
				DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("shout", peer.m_playerName, playerHostName, pos);
			}
			if (!string.IsNullOrEmpty(text2))
			{
				if (DiscordConnectorPlugin.StaticConfig.ChatShoutAllCaps)
				{
					text = text.ToUpper();
				}
				FinalizeFormattingAndSend(peer, playerHostName, text2, DiscordConnectorPlugin.StaticConfig.ChatShoutPosEnabled, pos, text, ev);
			}
		}

		private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Webhook.Event ev)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			FinalizeFormattingAndSend(peer, playerHostName, preFormattedMessage, posEnabled, peer.m_refPos, ev);
		}

		private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, Webhook.Event ev)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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)
			bool subtractOne = ev == Webhook.Event.PlayerLeave || ev == Webhook.Event.PlayerFirstLeave;
			string text;
			if (preFormattedMessage.Contains("%POS%"))
			{
				if (!posEnabled)
				{
					preFormattedMessage = preFormattedMessage.Replace("%POS%", "");
				}
				text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, pos, subtractOne);
			}
			else
			{
				text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, subtractOne);
			}
			if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled)
			{
				EmbedBuilder embedBuilder = (Webhook.PlayerDeathEvents.Contains(ev) ? MessageTransformer.CreateDeathEmbed(peer, text, ev) : ((!posEnabled) ? MessageTransformer.CreatePlayerMessageEmbed(text, ev, peer.m_playerName, playerHostName, subtractOne) : MessageTransformer.CreatePlayerMessageEmbed(text, ev, peer.m_playerName, playerHostName, pos, subtractOne)));
				DiscordApi.SendEmbed(ev, embedBuilder);
			}
			else if (posEnabled)
			{
				DiscordApi.SendMessage(ev, text, pos);
			}
			else
			{
				DiscordApi.SendMessage(ev, text);
			}
		}

		private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, string text, Webhook.Event ev)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (preFormattedMessage.Contains("%SHOUT%") && string.IsNullOrEmpty(text))
			{
				preFormattedMessage = preFormattedMessage.Replace("%SHOUT%", "");
			}
			string text2;
			if (preFormattedMessage.Contains("%POS%"))
			{
				if (!posEnabled)
				{
					preFormattedMessage = preFormattedMessage.Replace("%POS%", "");
				}
				text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text, pos);
			}
			else
			{
				text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text);
			}
			if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled)
			{
				EmbedBuilder embedBuilder;
				if (!Webhook.PlayerShoutEvents.Contains(ev))
				{
					embedBuilder = ((!posEnabled) ? MessageTransformer.CreatePlayerMessageEmbed(text2, ev, peer.m_playerName, playerHostName) : MessageTransformer.CreatePlayerMessageEmbed(text2, ev, peer.m_playerName, playerHostName, pos));
				}
				else
				{
					embedBuilder = MessageTransformer.CreateShoutMessageEmbed(text2, ev, peer.m_playerName, playerHostName, text);
					if (posEnabled)
					{
						embedBuilder.AddField("Position", MessageTransformer.FormatVector3AsPos(pos), inline: true);
					}
				}
				DiscordApi.SendEmbed(ev, embedBuilder);
			}
			else if (posEnabled)
			{
				DiscordApi.SendMessage(ev, text2, pos);
			}
			else
			{
				DiscordApi.SendMessage(ev, text2);
			}
		}

		internal static void NonPlayerChat(Type type, string user, string text)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if (DiscordConnectorPlugin.StaticConfig.AllowNonPlayerShoutLogging)
			{
				if ((int)type != 2)
				{
					DiscordConnectorPlugin.StaticLogger.LogDebug("Ignored ping/join/leave from non-player " + user);
					return;
				}
				string playerId = "";
				DiscordConnectorPlugin.StaticLogger.LogDebug("Sending shout from '" + user + "' to discord: '" + text + "'");
				if (DiscordConnectorPlugin.StaticConfig.ChatShoutEnabled)
				{
					string playerName = MessageTransformer.CleanCaretFormatting(user);
					string text2 = MessageTransformer.FormatPlayerMessage(DiscordConnectorPlugin.StaticConfig.ShoutMessage, playerName, playerId, text);
					if (text2.Contains("%POS%"))
					{
						text2.Replace("%POS%", "");
					}
					DiscordApi.SendMessage(Webhook.Event.PlayerShout, text2);
				}
			}
			else
			{
				DiscordConnectorPlugin.StaticLogger.LogInfo("Ignored shout from " + user + " because they aren't a real player");
			}
		}
	}
	internal class LeaderbBoard
	{
		public static readonly int MAX_LEADER_BOARD_SIZE = 16;

		public Base LeaderBoard1 { get; }

		public Base LeaderBoard2 { get; }

		public Base LeaderBoard3 { get; }

		public Base LeaderBoard4 { get; }

		public Base LeaderBoard5 { get; }

		public LeaderbBoard()
		{
			LeaderBoard1 = new Composer(0);
			LeaderBoard2 = new Composer(1);
			LeaderBoard3 = new Composer(2);
			LeaderBoard4 = new Composer(3);
			LeaderBoard5 = new Composer(4);
		}

		public static string RankedCountResultToString(List<CountResult> rankings)
		{
			string text = "";
			for (int i = 0; i < rankings.Count; i++)
			{
				text += $"{i + 1}: {rankings[i].Name}: {rankings[i].Count}{Environment.NewLine}";
			}
			return text;
		}

		private static string ToReadableString(TimeSpan span)
		{
			string text = string.Format("{0}{1}{2}{3}", (span.Duration().Days > 0) ? string.Format("{0:0} day{1}, ", span.Days, (span.Days == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Hours > 0) ? string.Format("{0:0} hour{1}, ", span.Hours, (span.Hours == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Minutes > 0) ? string.Format("{0:0} minute{1}, ", span.Minutes, (span.Minutes == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Seconds > 0) ? string.Format("{0:0} second{1}", span.Seconds, (span.Seconds == 1) ? string.Empty : "s") : string.Empty);
			if (text.EndsWith(", "))
			{
				text = text.Substring(0, text.Length - 2);
			}
			if (string.IsNullOrEmpty(text))
			{
				text = "0 seconds";
			}
			return text;
		}

		public static string RankedSecondsToString(List<CountResult> rankings)
		{
			string text = "";
			for (int i = 0; i < rankings.Count; i++)
			{
				string text2 = ToReadableString(TimeSpan.FromSeconds(rankings[i].Count));
				text += $"{i + 1}: {rankings[i].Name}: {text2}{Environment.NewLine}";
			}
			return text;
		}
	}
	internal static class MessageTransformer
	{
		private const string PUBLIC_IP = "%PUBLICIP%";

		private const string VAR = "%VAR1%";

		private const string VAR_1 = "%VAR2%";

		private const string VAR_2 = "%VAR3%";

		private const string VAR_3 = "%VAR4%";

		private const string VAR_4 = "%VAR5%";

		private const string VAR_5 = "%VAR6%";

		private const string VAR_6 = "%VAR7%";

		private const string VAR_7 = "%VAR8%";

		private const string VAR_8 = "%VAR9%";

		private const string VAR_9 = "%VAR10%";

		private const string PLAYER_NAME = "%PLAYER_NAME%";

		private const string PLAYER_STEAMID = "%PLAYER_STEAMID%";

		private const string PLAYER_ID = "%PLAYER_ID%";

		private const string SHOUT = "%SHOUT%";

		private const string POS = "%POS%";

		private const string EVENT_START_MSG = "%EVENT_START_MSG%";

		private const string EVENT_END_MSG = "%EVENT_END_MSG%";

		private const string EVENT_MSG = "%EVENT_MSG%";

		private const string EVENT_PLAYERS = "%PLAYERS%";

		private const string N = "%N%";

		private const string WORLD_NAME = "%WORLD_NAME%";

		private const string DAY_NUMBER = "%DAY_NUMBER%";

		private const string NUM_PLAYERS = "%NUM_PLAYERS%";

		private const string JOIN_CODE = "%JOIN_CODE%";

		private const string TIMESTAMP = "%TIMESTAMP%";

		private const string TIMESINCE = "%TIMESINCE%";

		private const string UNIX_TIMESTAMP = "%UNIX_TIMESTAMP%";

		private static readonly Regex OpenCaretRegex = new Regex("<[\\w=]+>");

		private static readonly Regex CloseCaretRegex = new Regex("</[\\w]+>");

		private static string ReplaceVariables(string rawMessage, bool subtractOne = false)
		{
			return ReplaceDynamicVariables(rawMessage.Replace("%VAR1%", DiscordConnectorPlugin.StaticConfig.UserVariable).Replace("%VAR2%", DiscordConnectorPlugin.StaticConfig.UserVariable1).Replace("%VAR3%", DiscordConnectorPlugin.StaticConfig.UserVariable2)
				.Replace("%VAR4%", DiscordConnectorPlugin.StaticConfig.UserVariable3)
				.Replace("%VAR5%", DiscordConnectorPlugin.StaticConfig.UserVariable4)
				.Replace("%VAR6%", DiscordConnectorPlugin.StaticConfig.UserVariable5)
				.Replace("%VAR7%", DiscordConnectorPlugin.StaticConfig.UserVariable6)
				.Replace("%VAR8%", DiscordConnectorPlugin.StaticConfig.UserVariable7)
				.Replace("%VAR9%", DiscordConnectorPlugin.StaticConfig.UserVariable8)
				.Replace("%VAR10%", DiscordConnectorPlugin.StaticConfig.UserVariable9), subtractOne);
		}

		private static string ReplaceDynamicVariables(string rawMessage, bool subtractOne = false)
		{
			return ReplaceUnixTimestamp(ReplaceTimesince(ReplaceTimestamp(ReplaceJoinCode(ReplaceNumPlayers(ReplaceDayNumber(ReplaceWorldName(ReplacePublicIp(rawMessage))), subtractOne)))));
		}

		private static string ReplaceTimestamp(string rawMessage)
		{
			return rawMessage.Replace("%TIMESTAMP%", $"<t:{(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds}>");
		}

		private static string ReplaceTimesince(string rawMessage)
		{
			return rawMessage.Replace("%TIMESINCE%", $"<t:{(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds}:R>");
		}

		private static string ReplaceUnixTimestamp(string rawMessage)
		{
			return rawMessage.Replace("%UNIX_TIMESTAMP%", ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString());
		}

		private static string ReplaceJoinCode(string rawMessage)
		{
			return rawMessage.Replace("%JOIN_CODE%", ZPlayFabMatchmaking.JoinCode);
		}

		private static string ReplaceDayNumber(string rawMessage)
		{
			return rawMessage.Replace("%DAY_NUMBER%", ((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetCurrentDay().ToString() : "%DAY_NUMBER%");
		}

		private static string ReplaceNumPlayers(string rawMessage, bool subtractOne = false)
		{
			if (subtractOne)
			{
				return rawMessage.Replace("%NUM_PLAYERS%", ((Object)(object)ZNet.instance != (Object)null) ? (ZNet.instance.GetNrOfPlayers() - 1).ToString() : "%NUM_PLAYERS%");
			}
			return rawMessage.Replace("%NUM_PLAYERS%", ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetNrOfPlayers().ToString() : "%NUM_PLAYERS%");
		}

		private static string ReplacePublicIp(string rawMessage)
		{
			return rawMessage.Replace("%PUBLICIP%", DiscordConnectorPlugin.PublicIpAddress);
		}

		private static string ReplaceWorldName(string rawMessage)
		{
			return rawMessage.Replace("%WORLD_NAME%", ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "%WORLD_NAME%");
		}

		public static string FormatServerMessage(string rawMessage)
		{
			return ReplaceVariables(rawMessage);
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, bool subtractOne = false)
		{
			return ReplaceVariables(rawMessage, subtractOne).Replace("%PLAYER_STEAMID%", playerId).Replace("%PLAYER_ID%", playerId).Replace("%PLAYER_NAME%", playerName);
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, Vector3 pos, bool subtractOne = false)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			return FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne).Replace("%POS%", $"{pos}");
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, string shout, bool subtractOne = false)
		{
			return FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne).Replace("%SHOUT%", shout);
		}

		public static string FormatPlayerMessage(string rawMessage, string playerName, string playerSteamId, string shout, Vector3 pos, bool subtractOne = false)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return FormatPlayerMessage(rawMessage, playerName, playerSteamId, pos, subtractOne).Replace("%SHOUT%", shout);
		}

		public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg)
		{
			return ReplaceVariables(rawMessage).Replace("%EVENT_START_MSG%", eventStartMsg).Replace("%EVENT_END_MSG%", eventEndMsg);
		}

		public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%POS%", $"{pos}");
		}

		public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg)
		{
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventStartMsg);
		}

		public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg)
		{
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventEndMsg);
		}

		public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventStartMsg);
		}

		public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventEndMsg);
		}

		public static string FormatLeaderBoardHeader(string rawMessage)
		{
			return ReplaceVariables(rawMessage);
		}

		public static string FormatLeaderBoardHeader(string rawMessage, int n)
		{
			return ReplaceVariables(rawMessage).Replace("%N%", n.ToString());
		}

		public static string CleanCaretFormatting(string str)
		{
			string input = OpenCaretRegex.Replace(str, "", 1);
			return CloseCaretRegex.Replace(input, "", 1);
		}

		public static string FormatVector3AsPos(Vector3 vec3)
		{
			return DiscordConnectorPlugin.StaticConfig.PosVarFormat.Replace("%X%", vec3.x.ToString("F1")).Replace("%Y%", vec3.y.ToString("F1")).Replace("%Z%", vec3.z.ToString("F1"));
		}

		public static string FormatAppendedPos(Vector3 vec3)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			string newValue = FormatVector3AsPos(vec3);
			return DiscordConnectorPlugin.StaticConfig.AppendedPosFormat.Replace("%POS%", newValue);
		}

		public static EmbedBuilder CreateServerMessageEmbed(string rawMessage, Webhook.Event eventType)
		{
			string message = FormatServerMessage(rawMessage);
			string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World");
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			return EmbedTemplates.ServerLifecycle(eventType, message, worldName, serverName);
		}

		public static EmbedBuilder CreateDeathEmbed(ZNetPeer peer, string message, Webhook.Event eventType)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			string playerName = peer.m_playerName;
			string hostName = peer.m_socket.GetHostName();
			Vector3 refPos = peer.m_refPos;
			string arg = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World");
			string serverName = DiscordConnectorPlugin.StaticConfig.ServerName;
			EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetDescription(message).SetTimestamp()
				.SetTitle("\ud83d\udc80 Player Death")
				.SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl)
				.SetFooter($"World: {arg} • Today at {DateTime.Now:HH:mm}");
			if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled)
			{
				embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl);
			}
			if (DiscordConnectorPlugin.StaticConfig.PlayerDeathPosEnabled)
			{
				embedBuilder.AddField("Death Location", FormatVector3AsPos(refPos), inline: true);
			}
			if (DiscordConnectorPlugin.StaticConfig.ShowPlayerIds)
			{
				embedBuilder.AddField("Player ID", hostName, inline: true);
			}
			embedBuilder.AddField("Player", playerName, inline: true);
			return embedBuilder;
		}

		public static EmbedBuilder CreateShoutEmbed(ZNetPeer peer, string text, Webhook.Event eventType)
		{
			string playerName = peer.m_playerName;
			peer.m_socket.GetHostName();
			string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World");
			string message = (DiscordConnectorPlugin.StaticConfig.ChatShoutAllCaps ? text.ToUpper() : text);
			return EmbedTemplates.ChatMessage(eventType, message, playerName, null, worldName);
		}

		public static EmbedBuilder CreatePlayerMessageEmbed(string rawMessage, Webhook.Event eventType, string playerName, string playerId, bool subtractOne = false)
		{
			string message = FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne);
			string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWor