Decompiled source of DiscordRcon v1.0.1

BepInEx\plugins\DiscordRcon.dll

Decompiled a day ago
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
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.Dynamic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Sockets;
using System.Net.WebSockets;
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.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using DSharpPlus;
using DSharpPlus.AsyncEvents;
using DSharpPlus.Entities;
using DSharpPlus.EventArgs;
using DSharpPlus.Exceptions;
using DSharpPlus.Net;
using DSharpPlus.Net.Abstractions;
using DSharpPlus.Net.Models;
using DSharpPlus.Net.Serialization;
using DSharpPlus.Net.Udp;
using DSharpPlus.Net.WebSocket;
using DiscordRcon.Config;
using DiscordRcon.Models;
using DiscordRcon.Services;
using FxResources.Microsoft.Extensions.Logging.Abstractions;
using FxResources.System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
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;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DiscordRcon")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+287a44b2b33c54b3377ff5808d24403da1499be1")]
[assembly: AssemblyProduct("DiscordRcon")]
[assembly: AssemblyTitle("DiscordRcon")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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 DiscordRcon
{
	internal static class Core
	{
		public static ManualLogSource Log => Plugin.LogInstance;

		public static ConfigService ConfigService { get; private set; }

		public static RconService RconService { get; private set; }

		public static DiscordBotService DiscordBotService { get; private set; }

		public static CommandDiscoveryService CommandDiscoveryService { get; private set; }

		public static void Initialize()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			ConfigService = new ConfigService();
			try
			{
				ConfigService.Initialize();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(52, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Config failed to load: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(". DiscordRcon will not start.");
				}
				log.LogError(val);
				return;
			}
			RconService = new RconService();
			DiscordBotService = new DiscordBotService();
			CommandDiscoveryService = new CommandDiscoveryService();
			if (ConfigService.IsFirstRun)
			{
				LogFirstRunSetup();
				return;
			}
			DiscordBotService.Initialize();
			LogStartupStatus();
		}

		private static void LogFirstRunSetup()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			Log.LogWarning((object)"========================================");
			Log.LogWarning((object)"DiscordRcon - First Run Setup Required");
			Log.LogWarning((object)"========================================");
			Log.LogWarning((object)"This mod needs configuration before it can start.");
			Log.LogWarning((object)"");
			Log.LogWarning((object)"1. Edit the BepInEx config file:");
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(30, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("   ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Paths.ConfigPath);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\\io.vrising.DiscordRcon.cfg");
			}
			log.LogWarning(val);
			Log.LogWarning((object)"   - Set Discord.BotToken to your bot token");
			Log.LogWarning((object)"   - Set Discord.GuildId to your Discord server ID");
			Log.LogWarning((object)"   - Set RCON.Password to your RCON password");
			Log.LogWarning((object)"");
			Log.LogWarning((object)"2. Edit the role config file:");
			ManualLogSource log2 = Log;
			val = new BepInExWarningLogInterpolatedStringHandler(3, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("   ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ConfigService.RoleConfigPath);
			}
			log2.LogWarning(val);
			Log.LogWarning((object)"   - Add your Discord role IDs to adminRoles");
			Log.LogWarning((object)"   - Or add per-command grants in commandRoles");
			Log.LogWarning((object)"");
			Log.LogWarning((object)"3. Optionally edit the custom commands file:");
			ManualLogSource log3 = Log;
			val = new BepInExWarningLogInterpolatedStringHandler(3, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("   ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ConfigService.CustomCommandsPath);
			}
			log3.LogWarning(val);
			Log.LogWarning((object)"   - Add or remove slash command shortcuts for RCON commands");
			Log.LogWarning((object)"");
			Log.LogWarning((object)"4. Restart the server");
			Log.LogWarning((object)"========================================");
		}

		private static void LogStartupStatus()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Expected O, but got Unknown
			ConfigService configService = ConfigService;
			Log.LogInfo((object)"--- DiscordRcon Startup Status ---");
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(11, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  Discord: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.IsNullOrEmpty(configService.DiscordBotToken) ? "NOT CONFIGURED" : "Token set");
			}
			log.LogInfo(val);
			ManualLogSource log2 = Log;
			val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  Discord Guild: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((configService.DiscordGuildId == 0L) ? "NOT SET" : configService.DiscordGuildId.ToString());
			}
			log2.LogInfo(val);
			ManualLogSource log3 = Log;
			val = new BepInExInfoLogInterpolatedStringHandler(21, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  RCON: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(configService.RconHost);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(":");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(configService.RconPort);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (password ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.IsNullOrEmpty(configService.RconPassword) ? "NOT SET" : "set");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
			}
			log3.LogInfo(val);
			ManualLogSource log4 = Log;
			val = new BepInExInfoLogInterpolatedStringHandler(43, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  Role Config: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(configService.RoleConfig.AdminRoles.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" admin roles, ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(configService.RoleConfig.CommandRoles.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" command roles");
			}
			log4.LogInfo(val);
			ManualLogSource log5 = Log;
			val = new BepInExInfoLogInterpolatedStringHandler(28, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  Custom Commands: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(configService.CustomCommands.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" commands");
			}
			log5.LogInfo(val);
			Log.LogInfo((object)"-----------------------------------");
		}

		public static void Shutdown()
		{
			DiscordBotService?.Shutdown();
			RconService?.Shutdown();
		}
	}
	[BepInPlugin("io.vrising.DiscordRcon", "DiscordRcon", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class Plugin : BasePlugin
	{
		internal static Plugin Instance { get; private set; }

		public static ManualLogSource LogInstance => ((BasePlugin)Instance).Log;

		public static bool IsServer { get; private set; }

		public override void Load()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			Instance = this;
			IsServer = Application.productName == "VRisingServer";
			if (!IsServer)
			{
				((BasePlugin)this).Log.LogWarning((object)"DiscordRcon is a server-only plugin. It will not function on the client.");
				return;
			}
			Core.Initialize();
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(23, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("DiscordRcon");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded successfully!");
			}
			log.LogInfo(val);
		}

		public override bool Unload()
		{
			if (IsServer)
			{
				Core.Shutdown();
			}
			return true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "io.vrising.DiscordRcon";

		public const string PLUGIN_NAME = "DiscordRcon";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace DiscordRcon.Services
{
	public class CommandDiscoveryService
	{
		private volatile int _discoveryRunning;

		private static readonly Regex _ansiRegex = new Regex("\\x1b\\[\\d+(?:;\\d+)*m", RegexOptions.Compiled);

		public List<DiscoveredCommand> DiscoveredCommands { get; private set; } = new List<DiscoveredCommand>();


		public bool IsReady { get; private set; }

		public void RunDiscovery()
		{
			if (Interlocked.CompareExchange(ref _discoveryRunning, 1, 0) == 0)
			{
				DiscoverAndRetryAsync();
			}
		}

		private async Task DiscoverAndRetryAsync()
		{
			int attempt = 0;
			try
			{
				bool flag = default(bool);
				while (true)
				{
					if (await DiscoverAndBuildIndexAsync())
					{
						IsReady = true;
						return;
					}
					attempt++;
					if (attempt >= 20)
					{
						break;
					}
					ManualLogSource log = Core.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(47, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discovery failed (attempt ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(attempt);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("), retrying in 30s...");
					}
					log.LogInfo(val);
					await Task.Delay(30000);
				}
				Core.Log.LogError((object)"Discovery failed after 20 attempts. Restart the server to retry.");
			}
			finally
			{
				Interlocked.Exchange(ref _discoveryRunning, 0);
			}
		}

		private async Task<bool> DiscoverAndBuildIndexAsync()
		{
			bool flag = default(bool);
			try
			{
				RconResult rconResult = await Core.RconService.SendCommandAsync("help", 30000);
				if (!rconResult.Success)
				{
					ManualLogSource log = Core.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(18, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discovery failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(rconResult.Message);
					}
					log.LogWarning(val);
					return false;
				}
				string helpText = _ansiRegex.Replace(rconResult.Message, "");
				List<DiscoveredCommand> list2 = (DiscoveredCommands = ParseHelpOutput(helpText));
				IsReady = true;
				ManualLogSource log2 = Core.Log;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(37, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Discovery complete: indexed ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(list2.Count);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" commands");
				}
				log2.LogInfo(val2);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Core.Log;
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(17, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Discovery error: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				log3.LogError(val3);
				return false;
			}
		}

		private List<DiscoveredCommand> ParseHelpOutput(string helpText)
		{
			List<DiscoveredCommand> list = new List<DiscoveredCommand>();
			string[] array = helpText.Split('\n');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (string.IsNullOrEmpty(text) || text.StartsWith("Total commands:", StringComparison.OrdinalIgnoreCase) || !text.StartsWith("-"))
				{
					continue;
				}
				string text2 = text;
				string text3 = text2.Substring(1, text2.Length - 1).Trim();
				int num = text3.IndexOf(':');
				if (num < 0)
				{
					continue;
				}
				string text4 = text3.Substring(0, num).Trim();
				if (!string.IsNullOrEmpty(text4))
				{
					text2 = text3;
					int num2 = num + 1;
					string text5 = text2.Substring(num2, text2.Length - num2).Trim();
					string usage = "";
					string description = text5;
					int num3 = text5.IndexOf(" - ");
					if (num3 >= 0)
					{
						usage = text5.Substring(0, num3).Trim();
						text2 = text5;
						num2 = num3 + 3;
						description = text2.Substring(num2, text2.Length - num2).Trim();
					}
					list.Add(new DiscoveredCommand(text4, usage, description));
				}
			}
			return list;
		}

		public List<DiscoveredCommand> SearchCommands(string query)
		{
			if (string.IsNullOrEmpty(query) || DiscoveredCommands.Count == 0)
			{
				return new List<DiscoveredCommand>();
			}
			string query2 = query.ToLowerInvariant();
			List<DiscoveredCommand> list = PrefixMatches(query2);
			if (list.Count > 0)
			{
				return list;
			}
			List<DiscoveredCommand> list2 = ParentPrefixMatches(query2);
			if (list2.Count > 0)
			{
				return list2;
			}
			List<DiscoveredCommand> list3 = SubstringMatches(query2);
			if (list3.Count > 0)
			{
				return list3;
			}
			return new List<DiscoveredCommand>();
		}

		private List<DiscoveredCommand> PrefixMatches(string query)
		{
			return DiscoveredCommands.Where((DiscoveredCommand c) => c.CommandId.ToLowerInvariant() == query || c.CommandId.ToLowerInvariant().StartsWith(query + ".")).ToList();
		}

		private List<DiscoveredCommand> ParentPrefixMatches(string query)
		{
			int num = query.LastIndexOf('.');
			while (num > 0)
			{
				string text = query.Substring(0, num);
				List<DiscoveredCommand> list = PrefixMatches(text);
				if (list.Count > 0)
				{
					return list;
				}
				num = text.LastIndexOf('.');
			}
			return new List<DiscoveredCommand>();
		}

		private List<DiscoveredCommand> SubstringMatches(string query)
		{
			return DiscoveredCommands.Where((DiscoveredCommand c) => c.CommandId.ToLowerInvariant().Contains(query)).Take(10).ToList();
		}

		public DiscoveredCommand FindExact(string commandId)
		{
			return DiscoveredCommands.FirstOrDefault((DiscoveredCommand c) => string.Equals(c.CommandId, commandId, StringComparison.OrdinalIgnoreCase));
		}
	}
	public class DiscordBotService
	{
		private DiscordClient _client;

		private bool _shuttingDown;

		private Dictionary<string, CustomCommand> _customCommandMap = new Dictionary<string, CustomCommand>(StringComparer.OrdinalIgnoreCase);

		private static readonly FieldInfo _roleIdField = typeof(DiscordMember).GetField("_role_ids", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly Regex _ansiRegex = new Regex("\\x1b\\[(\\d+(?:;\\d+)*)m", RegexOptions.Compiled);

		private static readonly Regex _validSlashName = new Regex("^[a-z0-9_-]{1,32}$", RegexOptions.Compiled);

		private static string AnsiToMarkdown(string input)
		{
			StringBuilder stringBuilder = new StringBuilder(input.Length);
			string text = input;
			bool flag = false;
			while (text.Length > 0)
			{
				Match match = _ansiRegex.Match(text);
				if (!match.Success)
				{
					stringBuilder.Append(text);
					break;
				}
				stringBuilder.Append(text.Substring(0, match.Index));
				string[] array = match.Groups[1].Value.Split(';');
				if (array.Contains("0"))
				{
					if (flag)
					{
						stringBuilder.Append("**");
						flag = false;
					}
				}
				else
				{
					string[] array2 = array;
					foreach (string text2 in array2)
					{
						if ((text2 == "1" || text2 == "97") && !flag)
						{
							stringBuilder.Append("**");
							flag = true;
						}
					}
				}
				string text3 = text;
				int i = match.Index + match.Length;
				text = text3.Substring(i, text3.Length - i);
			}
			if (flag)
			{
				stringBuilder.Append("**");
			}
			return stringBuilder.ToString();
		}

		private static List<ulong> GetMemberRoleIds(DiscordMember member)
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				return member.Roles.Select((DiscordRole r) => r.Id).ToList();
			}
			catch (KeyNotFoundException)
			{
				if (Core.ConfigService.LogDiscordEvents)
				{
					ManualLogSource log = Core.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(87, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Perm] DiscordMember.Roles threw KeyNotFoundException for ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(member.Username);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("(");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ulong>(member.Id);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("), falling back to _role_ids");
					}
					log.LogWarning(val);
				}
			}
			if (_roleIdField == null)
			{
				Core.Log.LogWarning((object)"[Perm] _role_ids field not found via reflection");
				return null;
			}
			try
			{
				List<ulong> list = (List<ulong>)_roleIdField.GetValue(member);
				if (Core.ConfigService.LogDiscordEvents)
				{
					ManualLogSource log2 = Core.Log;
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(40, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Perm] read ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(list.Count);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" role IDs from _role_ids: [");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(string.Join(", ", list));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("]");
					}
					log2.LogInfo(val2);
				}
				return list;
			}
			catch (Exception ex2)
			{
				ManualLogSource log3 = Core.Log;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(33, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Perm] failed to read _role_ids: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex2.Message);
				}
				log3.LogWarning(val);
				return null;
			}
		}

		private static string FormatSuggestions(List<DiscoveredCommand> matches)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (DiscoveredCommand match in matches)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
				handler.AppendLiteral("\n  - **");
				handler.AppendFormatted(match.CommandId);
				handler.AppendLiteral("**");
				stringBuilder3.Append(ref handler);
				if (!string.IsNullOrEmpty(match.Usage))
				{
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder4 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
					handler.AppendLiteral(" `");
					handler.AppendFormatted(match.Usage);
					handler.AppendLiteral("`");
					stringBuilder4.Append(ref handler);
				}
				if (!string.IsNullOrEmpty(match.Description))
				{
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder5 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
					handler.AppendLiteral(" - ");
					handler.AppendFormatted(match.Description);
					stringBuilder5.Append(ref handler);
				}
			}
			return stringBuilder.ToString();
		}

		private static string FormatFullListing(List<DiscoveredCommand> commands)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (DiscoveredCommand command in commands)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(6, 1, stringBuilder2);
				handler.AppendLiteral("- **");
				handler.AppendFormatted(command.CommandId);
				handler.AppendLiteral("**");
				stringBuilder3.Append(ref handler);
				if (!string.IsNullOrEmpty(command.Usage))
				{
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder4 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
					handler.AppendLiteral(" `");
					handler.AppendFormatted(command.Usage);
					handler.AppendLiteral("`");
					stringBuilder4.Append(ref handler);
				}
				if (!string.IsNullOrEmpty(command.Description))
				{
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder5 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
					handler.AppendLiteral(" - ");
					handler.AppendFormatted(command.Description);
					stringBuilder5.Append(ref handler);
				}
				stringBuilder.Append('\n');
			}
			return stringBuilder.ToString();
		}

		public void Initialize()
		{
			ConfigService configService = Core.ConfigService;
			if (string.IsNullOrEmpty(configService.DiscordBotToken))
			{
				Core.Log.LogWarning((object)"Discord bot token is not configured. Set Discord.BotToken in the config and restart.");
				return;
			}
			if (configService.DiscordGuildId == 0L)
			{
				Core.Log.LogWarning((object)"Discord guild ID is not configured. Set Discord.GuildId in the config and restart.");
				return;
			}
			_client = new DiscordClient(new DiscordConfiguration
			{
				Token = configService.DiscordBotToken,
				TokenType = TokenType.Bot,
				Intents = (DiscordIntents.Guilds | DiscordIntents.GuildMembers)
			});
			_client.InteractionCreated += OnInteractionCreated;
			_client.SocketErrored += OnSocketError;
			_client.SocketClosed += OnSocketClosed;
			_client.Ready += OnReady;
			_client.GuildAvailable += OnGuildAvailable;
			ConnectAsync();
		}

		private async Task ConnectAsync()
		{
			try
			{
				await _client.ConnectAsync();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Core.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(106, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to connect Discord bot: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(". Verify your BotToken and that the bot is not already connected elsewhere.");
				}
				log.LogError(val);
			}
		}

		private async Task OnReady(DiscordClient sender, ReadyEventArgs e)
		{
			ManualLogSource log = Core.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discord bot is ready, guilds in cache: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(sender.Guilds.Count);
			}
			log.LogInfo(val);
			if (sender.Guilds.Count == 0)
			{
				Core.Log.LogWarning((object)"Discord guild cache is empty. Check that the bot has been added to your server.");
			}
			await RegisterSlashCommandsAsync();
			Core.Log.LogInfo((object)"Discovery will run in 60s");
			Task.Run(async delegate
			{
				await Task.Delay(60000);
				try
				{
					Core.CommandDiscoveryService.RunDiscovery();
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = Core.Log;
					bool flag2 = default(bool);
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Discovery launch error: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					log2.LogError(val2);
				}
			});
		}

		private async Task RegisterSlashCommandsAsync()
		{
			bool flag = default(bool);
			try
			{
				ulong discordGuildId = Core.ConfigService.DiscordGuildId;
				List<DiscordApplicationCommand> commands = new List<DiscordApplicationCommand>
				{
					new DiscordApplicationCommand("rcon", "Execute an RCON command", new List<DiscordApplicationCommandOption>
					{
						new DiscordApplicationCommandOption("command", "The RCON command to execute", ApplicationCommandOptionType.String, true)
					}),
					new DiscordApplicationCommand("help", "Show available RCON commands or details for a specific command", new List<DiscordApplicationCommandOption>
					{
						new DiscordApplicationCommandOption("command", "Command name to get help for", ApplicationCommandOptionType.String, false)
					})
				};
				_customCommandMap.Clear();
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
				foreach (CustomCommand customCommand in Core.ConfigService.CustomCommands)
				{
					if (string.IsNullOrEmpty(customCommand.Name) || string.IsNullOrEmpty(customCommand.RconCommand))
					{
						ManualLogSource log = Core.Log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(54, 0, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Skipping custom command with empty name or rconCommand");
						}
						log.LogWarning(val);
					}
					else if (customCommand.Name == "rcon" || customCommand.Name == "help")
					{
						ManualLogSource log2 = Core.Log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(65, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Custom command name '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(customCommand.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' conflicts with built-in commands, skipping");
						}
						log2.LogWarning(val);
					}
					else if (!_validSlashName.IsMatch(customCommand.Name))
					{
						ManualLogSource log3 = Core.Log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(107, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Custom command name '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(customCommand.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' is invalid (must be lowercase, 1-32 chars, a-z/0-9/hyphen/underscore only), skipping");
						}
						log3.LogWarning(val);
					}
					else if (!hashSet.Add(customCommand.Name))
					{
						ManualLogSource log4 = Core.Log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(42, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Duplicate custom command name '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(customCommand.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("', skipping");
						}
						log4.LogWarning(val);
					}
					else
					{
						_customCommandMap[customCommand.Name] = customCommand;
						commands.Add(new DiscordApplicationCommand(customCommand.Name, customCommand.Description ?? ("Shortcut for " + customCommand.RconCommand), new List<DiscordApplicationCommandOption>
						{
							new DiscordApplicationCommandOption("arguments", "Arguments for " + customCommand.RconCommand, ApplicationCommandOptionType.String, false)
						}));
					}
				}
				await _client.BulkOverwriteGuildApplicationCommandsAsync(discordGuildId, commands);
				ManualLogSource log5 = Core.Log;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(50, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Registered ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(commands.Count);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" slash commands (/rcon, /help, ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_customCommandMap.Count);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" custom)");
				}
				log5.LogInfo(val2);
			}
			catch (Exception ex)
			{
				ManualLogSource log6 = Core.Log;
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(35, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Failed to register slash commands: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				log6.LogError(val3);
			}
		}

		private Task OnGuildAvailable(DiscordClient sender, GuildCreateEventArgs e)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (Core.ConfigService.LogDiscordEvents)
			{
				ManualLogSource log = Core.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discord guild available: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(e.Guild.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("(");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ulong>(e.Guild.Id);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
				}
				log.LogInfo(val);
			}
			return Task.CompletedTask;
		}

		private async Task OnInteractionCreated(DiscordClient sender, InteractionCreateEventArgs e)
		{
			if (e.Interaction.Type == InteractionType.ApplicationCommand)
			{
				DiscordInteraction interaction = e.Interaction;
				string name = interaction.Data.Name;
				CustomCommand value;
				if (name == "rcon")
				{
					await HandleRconAsync(interaction);
				}
				else if (name == "help")
				{
					await HandleHelpAsync(interaction);
				}
				else if (_customCommandMap.TryGetValue(name, out value))
				{
					await HandleCustomCommandAsync(interaction, value);
				}
			}
		}

		private async Task HandleRconAsync(DiscordInteraction interaction)
		{
			string commandText = (interaction.Data.Options?.FirstOrDefault((DiscordInteractionDataOption o) => o.Name == "command"))?.Value?.ToString() ?? "";
			if (string.IsNullOrWhiteSpace(commandText))
			{
				await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent(":x: No command provided."));
				return;
			}
			string commandId = commandText.Split(' ')[0];
			ManualLogSource log = Core.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[/rcon] ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(interaction.User.Username);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(commandText);
			}
			log.LogInfo(val);
			if (!(await HasPermission(interaction.User, interaction.GuildId, commandId)))
			{
				await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent(":x: You don't have permission to use that command."));
				return;
			}
			await interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource);
			RconResult rconResult = await Core.RconService.SendCommandAsync(commandText);
			string text = AnsiToMarkdown(rconResult.Message);
			if (!rconResult.Success)
			{
				text = ":x: " + text;
			}
			else if (IsUnknownCommand(text) && Core.CommandDiscoveryService.IsReady)
			{
				List<DiscoveredCommand> list = Core.CommandDiscoveryService.SearchCommands(commandId);
				if (list.Count > 0)
				{
					text = text + "\n\nDid you mean one of these?" + FormatSuggestions(list);
				}
			}
			await RespondAsync(interaction, text);
		}

		private async Task HandleHelpAsync(DiscordInteraction interaction)
		{
			string query = (interaction.Data.Options?.FirstOrDefault((DiscordInteractionDataOption o) => o.Name == "command"))?.Value?.ToString() ?? "";
			ManualLogSource log = Core.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[/help] ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(interaction.User.Username);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.IsNullOrEmpty(query) ? "(full listing)" : query);
			}
			log.LogInfo(val);
			if (string.IsNullOrEmpty(query))
			{
				if (!(await HasAnyPermission(interaction.User, interaction.GuildId)))
				{
					await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent(":x: You don't have permission to use that command."));
					return;
				}
			}
			else if (!(await HasPermission(interaction.User, interaction.GuildId, query)))
			{
				await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent(":x: You don't have permission to use that command."));
				return;
			}
			await interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource);
			string text;
			if (Core.CommandDiscoveryService.IsReady)
			{
				if (string.IsNullOrEmpty(query))
				{
					text = FormatFullListing(Core.CommandDiscoveryService.DiscoveredCommands);
				}
				else
				{
					DiscoveredCommand discoveredCommand = Core.CommandDiscoveryService.FindExact(query);
					if (discoveredCommand != null)
					{
						StringBuilder stringBuilder = new StringBuilder();
						StringBuilder stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder3 = stringBuilder2;
						StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2);
						handler.AppendLiteral("**");
						handler.AppendFormatted(discoveredCommand.CommandId);
						handler.AppendLiteral("**");
						stringBuilder3.Append(ref handler);
						if (!string.IsNullOrEmpty(discoveredCommand.Usage))
						{
							stringBuilder2 = stringBuilder;
							StringBuilder stringBuilder4 = stringBuilder2;
							handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder2);
							handler.AppendLiteral("\nUsage: `");
							handler.AppendFormatted(discoveredCommand.Usage);
							handler.AppendLiteral("`");
							stringBuilder4.Append(ref handler);
						}
						if (!string.IsNullOrEmpty(discoveredCommand.Description))
						{
							stringBuilder2 = stringBuilder;
							StringBuilder stringBuilder5 = stringBuilder2;
							handler = new StringBuilder.AppendInterpolatedStringHandler(1, 1, stringBuilder2);
							handler.AppendLiteral("\n");
							handler.AppendFormatted(discoveredCommand.Description);
							stringBuilder5.Append(ref handler);
						}
						text = stringBuilder.ToString();
					}
					else
					{
						List<DiscoveredCommand> list = Core.CommandDiscoveryService.SearchCommands(query);
						text = ((list.Count <= 0) ? ("No commands found matching \"" + query + "\".") : ("No exact match for \"" + query + "\". Similar commands:" + FormatSuggestions(list)));
					}
				}
			}
			else
			{
				string command = (string.IsNullOrEmpty(query) ? "help" : ("help " + query));
				RconResult rconResult = await Core.RconService.SendCommandAsync(command);
				text = AnsiToMarkdown(rconResult.Message);
				if (!rconResult.Success)
				{
					text = ":x: " + text;
				}
			}
			await RespondAsync(interaction, text);
		}

		private static bool IsUnknownCommand(string response)
		{
			return response.IndexOf("unknown command", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private async Task HandleCustomCommandAsync(DiscordInteraction interaction, CustomCommand custom)
		{
			string text = (interaction.Data.Options?.FirstOrDefault((DiscordInteractionDataOption o) => o.Name == "arguments"))?.Value?.ToString() ?? "";
			string commandText = (string.IsNullOrEmpty(text) ? custom.RconCommand : (custom.RconCommand + " " + text));
			ManualLogSource log = Core.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(6, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[/");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(custom.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(interaction.User.Username);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(commandText);
			}
			log.LogInfo(val);
			if (!(await HasPermission(interaction.User, interaction.GuildId, custom.RconCommand)))
			{
				await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent(":x: You don't have permission to use that command."));
				return;
			}
			await interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource);
			RconResult rconResult = await Core.RconService.SendCommandAsync(commandText);
			string text2 = AnsiToMarkdown(rconResult.Message);
			if (!rconResult.Success)
			{
				text2 = ":x: " + text2;
			}
			else if (IsUnknownCommand(text2) && Core.CommandDiscoveryService.IsReady)
			{
				List<DiscoveredCommand> list = Core.CommandDiscoveryService.SearchCommands(custom.RconCommand);
				if (list.Count > 0)
				{
					text2 = text2 + "\n\nDid you mean one of these?" + FormatSuggestions(list);
				}
			}
			await RespondAsync(interaction, text2);
		}

		private async Task RespondAsync(DiscordInteraction interaction, string text)
		{
			if (text.Length <= 2000)
			{
				await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().WithContent(text));
			}
			else
			{
				await RespondLongAsync(interaction, text);
			}
		}

		private async Task RespondLongAsync(DiscordInteraction interaction, string text)
		{
			string[] array = text.Split('\n');
			string text2 = "";
			bool first = true;
			string[] array2 = array;
			foreach (string line in array2)
			{
				if (text2.Length + line.Length + 1 > 2000)
				{
					if (!first)
					{
						await interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().WithContent(text2));
					}
					else
					{
						await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().WithContent(text2));
						first = false;
					}
					text2 = line;
				}
				else
				{
					text2 = ((text2.Length == 0) ? line : (text2 + "\n" + line));
				}
			}
			if (text2.Length > 0)
			{
				if (first)
				{
					await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().WithContent(text2));
				}
				else
				{
					await interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().WithContent(text2));
				}
			}
		}

		private async Task<bool> HasAnyPermission(DiscordUser user, ulong? guildId)
		{
			var (flag, source) = await ResolveUserRoleIds(user, guildId);
			if (!flag)
			{
				return false;
			}
			RoleConfig roleConfig = Core.ConfigService.RoleConfig;
			if (roleConfig.AdminRoles.Count > 0 && source.Any((string id) => roleConfig.AdminRoles.Contains(id)))
			{
				return true;
			}
			foreach (List<string> entry in roleConfig.CommandRoles.Values)
			{
				if (source.Any((string id) => entry.Contains(id)))
				{
					return true;
				}
			}
			return false;
		}

		private async Task<(bool resolved, List<string> roleIds)> ResolveUserRoleIds(DiscordUser user, ulong? guildId)
		{
			if (_client == null)
			{
				return (false, null);
			}
			if (user == null)
			{
				Core.Log.LogWarning((object)"[Perm] user is null, denying");
				return (false, null);
			}
			List<ulong> roleIds = null;
			if (user is DiscordMember member)
			{
				roleIds = GetMemberRoleIds(member);
			}
			else if (guildId.HasValue)
			{
				if (_client.Guilds.TryGetValue(guildId.Value, out var value) && value.Members.TryGetValue(user.Id, out var value2))
				{
					roleIds = GetMemberRoleIds(value2);
				}
				if (roleIds == null)
				{
					try
					{
						roleIds = GetMemberRoleIds(await (await _client.GetGuildAsync(guildId.Value)).GetMemberAsync(user.Id));
					}
					catch (Exception ex)
					{
						ManualLogSource log = Core.Log;
						bool flag = default(bool);
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(33, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Perm] REST API fallback failed: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						log.LogWarning(val);
					}
				}
			}
			if (roleIds == null || roleIds.Count == 0)
			{
				Core.Log.LogWarning((object)"[Perm] no role IDs resolved, denying");
				return (false, null);
			}
			return (true, roleIds.Select((ulong id) => id.ToString()).ToList());
		}

		private async Task<bool> HasPermission(DiscordUser user, ulong? guildId, string commandId)
		{
			var (flag, source) = await ResolveUserRoleIds(user, guildId);
			if (!flag)
			{
				return false;
			}
			RoleConfig roleConfig = Core.ConfigService.RoleConfig;
			if (roleConfig.AdminRoles.Count > 0 && source.Any((string id) => roleConfig.AdminRoles.Contains(id)))
			{
				return true;
			}
			if (roleConfig.CommandRoles.TryGetValue(commandId, out var commandRoleIds) && source.Any((string id) => commandRoleIds.Contains(id)))
			{
				return true;
			}
			Core.Log.LogWarning((object)"[Perm] no admin or command role match, denying");
			return false;
		}

		private Task OnSocketError(DiscordClient sender, SocketErrorEventArgs e)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			ManualLogSource log = Core.Log;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(22, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discord socket error: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(e.Exception?.Message);
			}
			log.LogWarning(val);
			return Task.CompletedTask;
		}

		private Task OnSocketClosed(DiscordClient sender, SocketCloseEventArgs e)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (_shuttingDown)
			{
				return Task.CompletedTask;
			}
			ManualLogSource log = Core.Log;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(26, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discord socket closed: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(e.CloseCode);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" - ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(e.CloseMessage);
			}
			log.LogWarning(val);
			ReconnectWithBackoffAsync();
			return Task.CompletedTask;
		}

		private async Task ReconnectWithBackoffAsync()
		{
			int[] delays = new int[7] { 1, 2, 4, 8, 16, 32, 60 };
			int attempt = 0;
			bool flag = default(bool);
			while (!_shuttingDown && attempt < delays.Length)
			{
				await Task.Delay(delays[attempt] * 1000);
				try
				{
					ManualLogSource log = Core.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(29, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discord reconnect attempt ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(attempt + 1);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("...");
					}
					log.LogInfo(val);
					await _client.ConnectAsync();
					Core.Log.LogInfo((object)"Discord reconnected successfully");
					return;
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = Core.Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(26, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Discord reconnect failed: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					log2.LogWarning(val2);
					attempt++;
				}
			}
			Core.Log.LogError((object)"Discord reconnect exhausted all attempts. Manual restart required.");
		}

		public void Shutdown()
		{
			_shuttingDown = true;
			if (_client != null)
			{
				_client.DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false).GetAwaiter()
					.GetResult();
				_client.Dispose();
			}
		}
	}
	public class RconClient : IDisposable
	{
		private TcpClient _tcp;

		private NetworkStream _stream;

		private int _requestId;

		private const int SERVERDATA_AUTH = 3;

		private const int SERVERDATA_AUTH_RESPONSE = 2;

		private const int SERVERDATA_EXECCOMMAND = 2;

		private const int SERVERDATA_RESPONSE_VALUE = 0;

		public async Task ConnectAsync(string host, int port, string password, int timeoutMs = 5000)
		{
			_tcp = new TcpClient();
			IPAddress[] array = await Dns.GetHostAddressesAsync(host);
			if (array.Length == 0)
			{
				throw new Exception("Could not resolve RCON host: " + host);
			}
			using CancellationTokenSource cts = new CancellationTokenSource(timeoutMs);
			await _tcp.ConnectAsync(array[0], port, cts.Token);
			_stream = _tcp.GetStream();
			SendPacket(NextRequestId(), 3, password);
			(int, int, string) obj;
			int num;
			do
			{
				obj = await ReadPacketAsync(cts.Token);
				(num, _, _) = obj;
			}
			while (obj.Item2 != 2);
			if (num == -1)
			{
				throw new Exception("RCON authentication failed");
			}
		}

		public async Task<string> SendCommandAsync(string command, int timeoutMs = 10000)
		{
			SendPacket(NextRequestId(), 2, command);
			using CancellationTokenSource cts = new CancellationTokenSource(timeoutMs);
			int item;
			string item2;
			do
			{
				(int, int, string) obj = await ReadPacketAsync(cts.Token);
				item = obj.Item2;
				item2 = obj.Item3;
			}
			while (item != 0);
			return item2;
		}

		private int NextRequestId()
		{
			return ++_requestId;
		}

		private void SendPacket(int id, int type, string body)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(body);
			int num = 8 + bytes.Length + 2;
			byte[] array = new byte[4 + num];
			BitConverter.TryWriteBytes(array.AsSpan(0), num);
			BitConverter.TryWriteBytes(array.AsSpan(4), id);
			BitConverter.TryWriteBytes(array.AsSpan(8), type);
			bytes.CopyTo(array, 12);
			_stream.Write(array, 0, array.Length);
		}

		private async Task<(int id, int type, string body)> ReadPacketAsync(CancellationToken ct = default(CancellationToken))
		{
			byte[] sizeBuf = new byte[4];
			await ReadExactAsync(sizeBuf, ct);
			int size = BitConverter.ToInt32(sizeBuf, 0);
			if (size < 10 || size > 65536)
			{
				throw new Exception($"Invalid RCON packet size: {size}");
			}
			byte[] data = new byte[size];
			await ReadExactAsync(data, ct);
			int item = BitConverter.ToInt32(data, 0);
			int item2 = BitConverter.ToInt32(data, 4);
			int num = size - 4 - 4 - 2;
			string item3 = ((num > 0) ? Encoding.UTF8.GetString(data, 8, num) : "");
			return (item, item2, item3);
		}

		private async Task ReadExactAsync(byte[] buffer, CancellationToken ct)
		{
			int num;
			for (int offset = 0; offset < buffer.Length; offset += num)
			{
				num = await _stream.ReadAsync(buffer, offset, buffer.Length - offset, ct);
				if (num == 0)
				{
					throw new Exception("RCON connection closed");
				}
			}
		}

		public void Dispose()
		{
			_stream?.Dispose();
			_tcp?.Dispose();
		}
	}
	public class RconService
	{
		private readonly SemaphoreSlim _concurrencyLimiter = new SemaphoreSlim(1, 1);

		public async Task<RconResult> SendCommandAsync(string command, int? timeoutMs = null)
		{
			ConfigService cfg = Core.ConfigService;
			if (string.IsNullOrEmpty(cfg.RconPassword))
			{
				return RconResult.Fail("RCON password not configured");
			}
			await _concurrencyLimiter.WaitAsync();
			bool flag = default(bool);
			try
			{
				int timeout = timeoutMs ?? cfg.RconCommandTimeoutMs;
				using RconClient client = new RconClient();
				await client.ConnectAsync(cfg.RconHost, cfg.RconPort, cfg.RconPassword);
				string text = await client.SendCommandAsync(command, timeout);
				if (Core.ConfigService.LogRconEvents)
				{
					ManualLogSource log = Core.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(11, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RCON [");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(command);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] -> ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					}
					log.LogInfo(val);
				}
				return RconResult.Ok(string.IsNullOrEmpty(text) ? "Command executed (no output)" : text);
			}
			catch (OperationCanceledException)
			{
				return RconResult.Fail("RCON command timed out");
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = Core.Log;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(13, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("RCON failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex2.Message);
				}
				log2.LogWarning(val2);
				return RconResult.Fail("RCON not ready: " + ex2.Message);
			}
			finally
			{
				_concurrencyLimiter.Release();
			}
		}

		public void Shutdown()
		{
			_concurrencyLimiter.Dispose();
		}
	}
	public readonly struct RconResult
	{
		public bool Success { get; }

		public string Message { get; }

		private RconResult(bool success, string message)
		{
			Success = success;
			Message = message;
		}

		public static RconResult Ok(string message)
		{
			return new RconResult(success: true, message);
		}

		public static RconResult Fail(string message)
		{
			return new RconResult(success: false, message);
		}
	}
}
namespace DiscordRcon.Models
{
	public class CustomCommand
	{
		[JsonPropertyName("name")]
		public string Name { get; set; } = "";


		[JsonPropertyName("description")]
		public string Description { get; set; } = "";


		[JsonPropertyName("rconCommand")]
		public string RconCommand { get; set; } = "";

	}
	public class DiscoveredCommand
	{
		public string CommandId { get; set; } = "";


		public string Usage { get; set; } = "";


		public string Description { get; set; } = "";


		public DiscoveredCommand(string commandId, string usage, string description)
		{
			CommandId = commandId;
			Usage = usage;
			Description = description;
		}
	}
	public class RoleConfig
	{
		[JsonPropertyName("adminRoles")]
		public List<string> AdminRoles { get; set; } = new List<string>();


		[JsonPropertyName("commandRoles")]
		public Dictionary<string, List<string>> CommandRoles { get; set; } = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);

	}
}
namespace DiscordRcon.Config
{
	public class ConfigService
	{
		public static readonly string ConfigDir = Path.Combine(Paths.ConfigPath, "DiscordRcon");

		public static readonly string RoleConfigPath = Path.Combine(ConfigDir, "discordrcon_roles.json");

		public static readonly string CustomCommandsPath = Path.Combine(ConfigDir, "discordrcon_commands.json");

		public string DiscordBotToken { get; private set; } = "";


		public ulong DiscordGuildId { get; private set; }

		public string RconHost { get; private set; } = "127.0.0.1";


		public int RconPort { get; private set; } = 25575;


		public string RconPassword { get; private set; } = "";


		public int RconCommandTimeoutMs { get; private set; } = 10000;


		public bool LogDiscordEvents { get; private set; }

		public bool LogRconEvents { get; private set; }

		public RoleConfig RoleConfig { get; private set; } = new RoleConfig();


		public List<CustomCommand> CustomCommands { get; private set; } = new List<CustomCommand>();


		public bool IsFirstRun { get; private set; }

		public void Initialize()
		{
			Directory.CreateDirectory(ConfigDir);
			BindConfig();
			DetectFirstRun();
			LoadRoleConfig();
			LoadCustomCommands();
		}

		private void DetectFirstRun()
		{
			IsFirstRun = string.IsNullOrEmpty(DiscordBotToken) && DiscordGuildId == 0L && string.IsNullOrEmpty(RconPassword);
		}

		private void BindConfig()
		{
			ConfigFile config = ((BasePlugin)Plugin.Instance).Config;
			DiscordBotToken = config.Bind<string>("Discord", "BotToken", "", "Discord bot token. Get this from https://discord.com/developers/applications").Value;
			DiscordGuildId = config.Bind<ulong>("Discord", "GuildId", 0uL, "Discord server (guild) ID for registering slash commands").Value;
			RconHost = config.Bind<string>("RCON", "Host", "127.0.0.1", "RCON server hostname").Value;
			RconPort = config.Bind<int>("RCON", "Port", 25575, "RCON server port").Value;
			RconPassword = config.Bind<string>("RCON", "Password", "", "RCON server password").Value;
			RconCommandTimeoutMs = config.Bind<int>("RCON", "CommandTimeoutMs", 10000, "Timeout in milliseconds for RCON command responses").Value;
			LogDiscordEvents = config.Bind<bool>("Debug", "LogDiscordEvents", false, "Verbose logging of Discord gateway events").Value;
			LogRconEvents = config.Bind<bool>("Debug", "LogRconEvents", false, "Verbose logging of RCON events").Value;
		}

		private void LoadRoleConfig()
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			bool flag = default(bool);
			if (!File.Exists(RoleConfigPath))
			{
				RoleConfig config = new RoleConfig();
				SaveRoleConfig(config);
				ManualLogSource log = Core.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(23, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Created role config at ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(RoleConfigPath);
				}
				log.LogInfo(val);
			}
			try
			{
				string json = File.ReadAllText(RoleConfigPath);
				RoleConfig = System.Text.Json.JsonSerializer.Deserialize<RoleConfig>(json) ?? new RoleConfig();
				ManualLogSource log2 = Core.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Loaded role config: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(RoleConfig.AdminRoles.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" admin roles, ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(RoleConfig.CommandRoles.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" command roles");
				}
				log2.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Core.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(66, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to load role config: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(". Fix or delete the file and restart: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(RoleConfigPath);
				}
				log3.LogError(val2);
				throw;
			}
		}

		private void SaveRoleConfig(RoleConfig config)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			try
			{
				string contents = System.Text.Json.JsonSerializer.Serialize(config, new JsonSerializerOptions
				{
					WriteIndented = true
				});
				File.WriteAllText(RoleConfigPath, contents);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Core.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(28, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to save role config: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}

		private void LoadCustomCommands()
		{
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			bool flag = default(bool);
			if (!File.Exists(CustomCommandsPath))
			{
				List<CustomCommand> commands = new List<CustomCommand>
				{
					new CustomCommand
					{
						Name = "kick",
						Description = "Kick a player from the server",
						RconCommand = "kick"
					},
					new CustomCommand
					{
						Name = "ban",
						Description = "Ban a player from the server",
						RconCommand = "ban"
					},
					new CustomCommand
					{
						Name = "listplayers",
						Description = "List all online players",
						RconCommand = "listplayers"
					}
				};
				SaveCustomCommands(commands);
				ManualLogSource log = Core.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Created custom commands config at ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(CustomCommandsPath);
				}
				log.LogInfo(val);
			}
			try
			{
				string json = File.ReadAllText(CustomCommandsPath);
				CustomCommands = System.Text.Json.JsonSerializer.Deserialize<List<CustomCommand>>(json) ?? new List<CustomCommand>();
				ManualLogSource log2 = Core.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Loaded custom commands: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(CustomCommands.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" commands");
				}
				log2.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Core.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(70, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to load custom commands: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(". Fix or delete the file and restart: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(CustomCommandsPath);
				}
				log3.LogError(val2);
				throw;
			}
		}

		private void SaveCustomCommands(List<CustomCommand> commands)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			try
			{
				string contents = System.Text.Json.JsonSerializer.Serialize(commands, new JsonSerializerOptions
				{
					WriteIndented = true
				});
				File.WriteAllText(CustomCommandsPath, contents);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Core.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to save custom commands: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val);
			}
		}
	}
}
[CompilerGenerated]
internal sealed class <cced586a-35fd-45bb-938e-6d9753f8c7da><PrivateImplementationDetails>
{
	[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 28)]
	internal struct __StaticArrayInitTypeSize=28
	{
	}

	internal static readonly __StaticArrayInitTypeSize=28 BF7002736ADB60A23C32230A9AF55DF45D5C23AD0F3F03C0AF765A16CDB52EB6/* Not supported: data(01 00 00 00 02 00 00 00 04 00 00 00 08 00 00 00 10 00 00 00 20 00 00 00 3C 00 00 00) */;
}
namespace Newtonsoft.Json
{
	internal enum ConstructorHandling
	{
		Default,
		AllowNonPublicDefaultConstructor
	}
	internal enum DateFormatHandling
	{
		IsoDateFormat,
		MicrosoftDateFormat
	}
	internal enum DateParseHandling
	{
		None,
		DateTime,
		DateTimeOffset
	}
	internal enum DateTimeZoneHandling
	{
		Local,
		Utc,
		Unspecified,
		RoundtripKind
	}
	internal class DefaultJsonNameTable : JsonNameTable
	{
		private class Entry
		{
			internal readonly string Value;

			internal readonly int HashCode;

			internal Entry Next;

			internal Entry(string value, int hashCode, Entry next)
			{
				Value = value;
				HashCode = hashCode;
				Next = next;
			}
		}

		private static readonly int HashCodeRandomizer;

		private int _count;

		private Entry[] _entries;

		private int _mask = 31;

		static DefaultJsonNameTable()
		{
			HashCodeRandomizer = Environment.TickCount;
		}

		public DefaultJsonNameTable()
		{
			_entries = new Entry[_mask + 1];
		}

		public override string? Get(char[] key, int start, int length)
		{
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			num += (num << 7) ^ key[start];
			int num2 = start + length;
			for (int i = start + 1; i < num2; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			int num3 = Volatile.Read(ref _mask);
			int num4 = num & num3;
			for (Entry entry = _entries[num4]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && TextEquals(entry.Value, key, start, length))
				{
					return entry.Value;
				}
			}
			return null;
		}

		public string Add(string key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			int length = key.Length;
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			for (int i = 0; i < key.Length; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			for (Entry entry = _entries[num & _mask]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && entry.Value.Equals(key, StringComparison.Ordinal))
				{
					return entry.Value;
				}
			}
			return AddEntry(key, num);
		}

		private string AddEntry(string str, int hashCode)
		{
			int num = hashCode & _mask;
			Entry entry = new Entry(str, hashCode, _entries[num]);
			_entries[num] = entry;
			if (_count++ == _mask)
			{
				Grow();
			}
			return entry.Value;
		}

		private void Grow()
		{
			Entry[] entries = _entries;
			int num = _mask * 2 + 1;
			Entry[] array = new Entry[num + 1];
			for (int i = 0; i < entries.Length; i++)
			{
				Entry entry = entries[i];
				while (entry != null)
				{
					int num2 = entry.HashCode & num;
					Entry next = entry.Next;
					entry.Next = array[num2];
					array[num2] = entry;
					entry = next;
				}
			}
			_entries = array;
			Volatile.Write(ref _mask, num);
		}

		private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
		{
			if (str1.Length != str2Length)
			{
				return false;
			}
			for (int i = 0; i < str1.Length; i++)
			{
				if (str1[i] != str2[str2Start + i])
				{
					return false;
				}
			}
			return true;
		}
	}
	[Flags]
	internal enum DefaultValueHandling
	{
		Include = 0,
		Ignore = 1,
		Populate = 2,
		IgnoreAndPopulate = 3
	}
	internal enum FloatFormatHandling
	{
		String,
		Symbol,
		DefaultValue
	}
	internal enum FloatParseHandling
	{
		Double,
		Decimal
	}
	internal enum Formatting
	{
		None,
		Indented
	}
	internal interface IArrayPool<T>
	{
		T[] Rent(int minimumLength);

		void Return(T[]? array);
	}
	internal interface IJsonLineInfo
	{
		int LineNumber { get; }

		int LinePosition { get; }

		bool HasLineInfo();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	internal sealed class JsonArrayAttribute : JsonContainerAttribute
	{
		private bool _allowNullItems;

		public bool AllowNullItems
		{
			get
			{
				return _allowNullItems;
			}
			set
			{
				_allowNullItems = value;
			}
		}

		public JsonArrayAttribute()
		{
		}

		public JsonArrayAttribute(bool allowNullItems)
		{
			_allowNullItems = allowNullItems;
		}

		public JsonArrayAttribute(string id)
			: base(id)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
	internal sealed class JsonConstructorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	internal abstract class JsonContainerAttribute : Attribute
	{
		internal bool? _isReference;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		private Type? _namingStrategyType;

		private object[]? _namingStrategyParameters;

		public string? Id { get; set; }

		public string? Title { get; set; }

		public string? Description { get; set; }

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType
		{
			get
			{
				return _namingStrategyType;
			}
			set
			{
				_namingStrategyType = value;
				NamingStrategyInstance = null;
			}
		}

		public object[]? NamingStrategyParameters
		{
			get
			{
				return _namingStrategyParameters;
			}
			set
			{
				_namingStrategyParameters = value;
				NamingStrategyInstance = null;
			}
		}

		internal NamingStrategy? NamingStrategyInstance { get; set; }

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		protected JsonContainerAttribute()
		{
		}

		protected JsonContainerAttribute(string id)
		{
			Id = id;
		}
	}
	internal static class JsonConvert
	{
		public static readonly string True = "true";

		public static readonly string False = "false";

		public static readonly string Null = "null";

		public static readonly string Undefined = "undefined";

		public static readonly string PositiveInfinity = "Infinity";

		public static readonly string NegativeInfinity = "-Infinity";

		public static readonly string NaN = "NaN";

		public static Func<JsonSerializerSettings>? DefaultSettings { get; set; }

		public static string ToString(DateTime value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
		}

		public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
		{
			DateTime value2 = DateTimeUtils.EnsureDateTime(value, timeZoneHandling);
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeString(stringWriter, value2, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(DateTimeOffset value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat);
		}

		public static string ToString(DateTimeOffset value, DateFormatHandling format)
		{
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeOffsetString(stringWriter, value, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(bool value)
		{
			if (!value)
			{
				return False;
			}
			return True;
		}

		public static string ToString(char value)
		{
			return ToString(char.ToString(value));
		}

		public static string ToString(Enum value)
		{
			return value.ToString("D");
		}

		public static string ToString(int value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(short value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ushort value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(uint value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(long value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		private static string ToStringInternal(BigInteger value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ulong value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(float value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			if (floatFormatHandling == FloatFormatHandling.Symbol || (!double.IsInfinity(value) && !double.IsNaN(value)))
			{
				return text;
			}
			if (floatFormatHandling == FloatFormatHandling.DefaultValue)
			{
				if (nullable)
				{
					return Null;
				}
				return "0.0";
			}
			return quoteChar + text + quoteChar;
		}

		public static string ToString(double value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureDecimalPlace(double value, string text)
		{
			if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		private static string EnsureDecimalPlace(string text)
		{
			if (StringUtils.IndexOf(text, '.') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		public static string ToString(byte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(sbyte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(decimal value)
		{
			return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
		}

		public static string ToString(Guid value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(Guid value, char quoteChar)
		{
			string text = value.ToString("D", CultureInfo.InvariantCulture);
			string text2 = quoteChar.ToString(CultureInfo.InvariantCulture);
			return text2 + text + text2;
		}

		public static string ToString(TimeSpan value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(TimeSpan value, char quoteChar)
		{
			return ToString(value.ToString(), quoteChar);
		}

		public static string ToString(Uri? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ToString(value, '"');
		}

		internal static string ToString(Uri value, char quoteChar)
		{
			return ToString(value.OriginalString, quoteChar);
		}

		public static string ToString(string? value)
		{
			return ToString(value, '"');
		}

		public static string ToString(string? value, char delimiter)
		{
			return ToString(value, delimiter, StringEscapeHandling.Default);
		}

		public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling)
		{
			if (delimiter != '"' && delimiter != '\'')
			{
				throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter");
			}
			return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, appendDelimiters: true, stringEscapeHandling);
		}

		public static string ToString(object? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ConvertUtils.GetTypeCode(value.GetType()) switch
			{
				PrimitiveTypeCode.String => ToString((string)value), 
				PrimitiveTypeCode.Char => ToString((char)value), 
				PrimitiveTypeCode.Boolean => ToString((bool)value), 
				PrimitiveTypeCode.SByte => ToString((sbyte)value), 
				PrimitiveTypeCode.Int16 => ToString((short)value), 
				PrimitiveTypeCode.UInt16 => ToString((ushort)value), 
				PrimitiveTypeCode.Int32 => ToString((int)value), 
				PrimitiveTypeCode.Byte => ToString((byte)value), 
				PrimitiveTypeCode.UInt32 => ToString((uint)value), 
				PrimitiveTypeCode.Int64 => ToString((long)value), 
				PrimitiveTypeCode.UInt64 => ToString((ulong)value), 
				PrimitiveTypeCode.Single => ToString((float)value), 
				PrimitiveTypeCode.Double => ToString((double)value), 
				PrimitiveTypeCode.DateTime => ToString((DateTime)value), 
				PrimitiveTypeCode.Decimal => ToString((decimal)value), 
				PrimitiveTypeCode.DBNull => Null, 
				PrimitiveTypeCode.DateTimeOffset => ToString((DateTimeOffset)value), 
				PrimitiveTypeCode.Guid => ToString((Guid)value), 
				PrimitiveTypeCode.Uri => ToString((Uri)value), 
				PrimitiveTypeCode.TimeSpan => ToString((TimeSpan)value), 
				PrimitiveTypeCode.BigInteger => ToStringInternal((BigInteger)value), 
				_ => throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())), 
			};
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value)
		{
			return SerializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting)
		{
			return SerializeObject(value, formatting, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			jsonSerializer.Formatting = formatting;
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer)
		{
			StringWriter stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
			using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter))
			{
				jsonTextWriter.Formatting = jsonSerializer.Formatting;
				jsonSerializer.Serialize(jsonTextWriter, value, type);
			}
			return stringWriter.ToString();
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value)
		{
			return DeserializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, JsonSerializerSettings settings)
		{
			return DeserializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type)
		{
			return DeserializeObject(value, type, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value)
		{
			return JsonConvert.DeserializeObject<T>(value, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
		{
			return DeserializeObject<T>(value);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject, JsonSerializerSettings settings)
		{
			return DeserializeObject<T>(value, settings);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, params JsonConverter[] converters)
		{
			return (T)DeserializeObject(value, typeof(T), converters);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, JsonSerializerSettings? settings)
		{
			return (T)DeserializeObject(value, typeof(T), settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return DeserializeObject(value, type, settings);
		}

		public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings)
		{
			ValidationUtils.ArgumentNotNull(value, "value");
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			if (!jsonSerializer.IsCheckAdditionalContentSet())
			{
				jsonSerializer.CheckAdditionalContent = true;
			}
			using JsonTextReader reader = new JsonTextReader(new StringReader(value));
			return jsonSerializer.Deserialize(reader, type);
		}

		[DebuggerStepThrough]
		public static void PopulateObject(string value, object target)
		{
			PopulateObject(value, target, null);
		}

		public static void PopulateObject(string value, object target, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			using JsonReader jsonReader = new JsonTextReader(new StringReader(value));
			jsonSerializer.Populate(jsonReader, target);
			if (settings == null || !settings.CheckAdditionalContent)
			{
				return;
			}
			while (jsonReader.Read())
			{
				if (jsonReader.TokenType != JsonToken.Comment)
				{
					throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object.");
				}
			}
		}

		public static string SerializeXmlNode(XmlNode? node)
		{
			return SerializeXmlNode(node, Formatting.None);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XmlDocument? DeserializeXmlNode(string value)
		{
			return DeserializeXmlNode(value, null);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), xmlNodeConverter);
		}

		public static string SerializeXNode(XObject? node)
		{
			return SerializeXNode(node, Formatting.None);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting)
		{
			return SerializeXNode(node, formatting, omitRootObject: false);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XDocument? DeserializeXNode(string value)
		{
			return DeserializeXNode(value, null);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XDocument)DeserializeObject(value, typeof(XDocument), xmlNodeConverter);
		}
	}
	internal abstract class JsonConverter
	{
		public virtual bool CanRead => true;

		public virtual bool CanWrite => true;

		public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);

		public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

		public abstract bool CanConvert(Type objectType);
	}
	internal abstract class JsonConverter<T> : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (!((value != null) ? (value is T) : ReflectionUtils.IsNullable(typeof(T))))
			{
				throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			WriteJson(writer, (T)value, serializer);
		}

		public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			bool flag = existingValue == null;
			if (!flag && !(existingValue is T))
			{
				throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			return ReadJson(reader, objectType, flag ? default(T) : ((T)existingValue), !flag, serializer);
		}

		public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);

		public sealed override bool CanConvert(Type objectType)
		{
			return typeof(T).IsAssignableFrom(objectType);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class JsonConverterAttribute : Attribute
	{
		private readonly Type _converterType;

		public Type ConverterType => _converterType;

		public object[]? ConverterParameters { get; }

		public JsonConverterAttribute(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			_converterType = converterType;
		}

		public JsonConverterAttribute(Type converterType, params object[] converterParameters)
			: this(converterType)
		{
			ConverterParameters = converterParameters;
		}
	}
	internal class JsonConverterCollection : Collection<JsonConverter>
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	internal sealed class JsonDictionaryAttribute : JsonContainerAttribute
	{
		public JsonDictionaryAttribute()
		{
		}

		public JsonDictionaryAttribute(string id)
			: base(id)
		{
		}
	}
	[Serializable]
	internal class JsonException : Exception
	{
		public JsonException()
		{
		}

		public JsonException(string message)
			: base(message)
		{
		}

		public JsonException(string message, Exception? innerException)
			: base(message, innerException)
		{
		}

		public JsonException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			return new JsonException(message);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	internal class JsonExtensionDataAttribute : Attribute
	{
		public bool WriteData { get; set; }

		public bool ReadData { get; set; }

		public JsonExtensionDataAttribute()
		{
			WriteData = true;
			ReadData = true;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	internal sealed class JsonIgnoreAttribute : Attribute
	{
	}
	internal abstract class JsonNameTable
	{
		public abstract string? Get(char[] key, int start, int length);
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
	internal sealed class JsonObjectAttribute : JsonContainerAttribute
	{
		private MemberSerialization _memberSerialization;

		internal MissingMemberHandling? _missingMemberHandling;

		internal Required? _itemRequired;

		internal NullValueHandling? _itemNullValueHandling;

		public MemberSerialization MemberSerialization
		{
			get
			{
				return _memberSerialization;
			}
			set
			{
				_memberSerialization = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public NullValueHandling ItemNullValueHandling
		{
			get
			{
				return _itemNullValueHandling.GetValueOrDefault();
			}
			set
			{
				_itemNullValueHandling = value;
			}
		}

		public Required ItemRequired
		{
			get
			{
				return _itemRequired.GetValueOrDefault();
			}
			set
			{
				_itemRequired = value;
			}
		}

		public JsonObjectAttribute()
		{
		}

		public JsonObjectAttribute(MemberSerialization memberSerialization)
		{
			MemberSerialization = memberSerialization;
		}

		public JsonObjectAttribute(string id)
			: base(id)
		{
		}
	}
	internal enum JsonContainerType
	{
		None,
		Object,
		Array,
		Constructor
	}
	internal struct JsonPosition
	{
		private static readonly char[] SpecialCharacters = new char[18]
		{
			'.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t',
			'\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029'
		};

		internal JsonContainerType Type;

		internal int Position;

		internal string? PropertyName;

		internal bool HasIndex;

		public JsonPosition(JsonContainerType type)
		{
			Type = type;
			HasIndex = TypeHasIndex(type);
			Position = -1;
			PropertyName = null;
		}

		internal int CalculateLength()
		{
			switch (Type)
			{
			case JsonContainerType.Object:
				return PropertyName.Length + 5;
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				return MathUtils.IntLength((ulong)Position) + 2;
			default:
				throw new ArgumentOutOfRangeException("Type");
			}
		}

		internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer)
		{
			switch (Type)
			{
			case JsonContainerType.Object:
			{
				string propertyName = PropertyName;
				if (propertyName.IndexOfAny(SpecialCharacters) != -1)
				{
					sb.Append("['");
					if (writer == null)
					{
						writer = new StringWriter(sb);
					}
					JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', appendDelimiters: false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
					sb.Append("']");
				}
				else
				{
					if (sb.Length > 0)
					{
						sb.Append('.');
					}
					sb.Append(propertyName);
				}
				break;
			}
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				sb.Append('[');
				sb.Append(Position);
				sb.Append(']');
				break;
			}
		}

		internal static bool TypeHasIndex(JsonContainerType type)
		{
			if (type != JsonContainerType.Array)
			{
				return type == JsonContainerType.Constructor;
			}
			return true;
		}

		internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition)
		{
			int num = 0;
			if (positions != null)
			{
				for (int i = 0; i < positions.Count; i++)
				{
					num += positions[i].CalculateLength();
				}
			}
			if (currentPosition.HasValue)
			{
				num += currentPosition.GetValueOrDefault().CalculateLength();
			}
			StringBuilder stringBuilder = new StringBuilder(num);
			StringWriter writer = null;
			char[] buffer = null;
			if (positions != null)
			{
				foreach (JsonPosition position in positions)
				{
					position.WriteTo(stringBuilder, ref writer, ref buffer);
				}
			}
			currentPosition?.WriteTo(stringBuilder, ref writer, ref buffer);
			return stringBuilder.ToString();
		}

		internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message)
		{
			if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
			{
				message = message.Trim();
				if (!message.EndsWith('.'))
				{
					message += ".";
				}
				message += " ";
			}
			message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
			}
			message += ".";
			return message;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class JsonPropertyAttribute : Attribute
	{
		internal NullValueHandling? _nullValueHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal bool? _isReference;

		internal int? _order;

		internal Required? _required;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType { get; set; }

		public object[]? NamingStrategyParameters { get; set; }

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameHandling = value;
			}
		}

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public int Order
		{
			get
			{
				return _order.GetValueOrDefault();
			}
			set
			{
				_order = value;
			}
		}

		public Required Required
		{
			get
			{
				return _required.GetValueOrDefault();
			}
			set
			{
				_required = value;
			}
		}

		public string? PropertyName { get; set; }

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public JsonPropertyAttribute()
		{
		}