Decompiled source of CrimsonBanned v1.3.3

CrimsonBanned.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
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.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CrimsonBanned.Commands;
using CrimsonBanned.Structs;
using CrimsonBanned.Utilities;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Network;
using Stunlock.Network;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using UnityEngine;
using VAMP;
using VAMP.Models;
using VAMP.Services;
using VAMP.Structs;
using VAMP.Utilities;
using VampireCommandFramework;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("CrimsonBanned")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Created with VRising.ModTemplate, you should edit this.")]
[assembly: AssemblyFileVersion("1.3.3.0")]
[assembly: AssemblyInformationalVersion("1.3.3+Branch.master.Sha.705b40dbc049e91739ff631446044371a95429e1.705b40dbc049e91739ff631446044371a95429e1")]
[assembly: AssemblyProduct("CrimsonBanned")]
[assembly: AssemblyTitle("CrimsonBanned")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.3.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
public struct MessagePair
{
	public string Key { get; set; }

	public string Value { get; set; }

	public MessagePair(string key, string value)
	{
		Key = key;
		Value = value;
	}

	public string ToString(Ban ban, BanDetails details = null)
	{
		string value = Value;
		value = ((!string.IsNullOrEmpty(ban.PlayerName)) ? value.Replace("{player}", ban.PlayerName) : value.Replace("{player}", "<i>Unknown</i>"));
		value = value.Replace("{id}", ban.PlayerID.ToString());
		value = value.Replace("{issued}", ban.Issued.ToLocalTime().ToString("MM/dd/yy HH:mm"));
		value = ((!(ban.Reason == "") && !string.IsNullOrEmpty(ban.Reason)) ? value.Replace("{reason}", ban.Reason) : value.Replace("{reason}", "(None Provided)"));
		value = value.Replace("{by}", ban.IssuedBy);
		value = value.Replace("{local}", ban.LocalBan.ToString());
		value = ((details == null) ? value.Replace("{type}", "") : value.Replace("{type}", details.BanType));
		if (TimeUtility.IsPermanent(ban.TimeUntil))
		{
			value = value.Replace("{until}", "Permanent");
			return value.Replace("{remainder}", "Permanent");
		}
		value = value.Replace("{until}", ban.TimeUntil.ToLocalTime().ToString("MM/dd/yy HH:mm"));
		return value.Replace("{remainder}", TimeUtility.FormatRemainder(ban.TimeUntil.ToLocalTime()));
	}
}
public class Trust
{
	public string Alias { get; set; }

	public string Command { get; set; }

	public Trust(string alias, string command)
	{
		Alias = alias;
		Command = command;
	}
}
namespace CrimsonBanned
{
	[BepInPlugin("CrimsonBanned", "CrimsonBanned", "1.3.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		private Harmony _harmony;

		public static Settings Settings;

		public static bool LogLoaded;

		internal static Plugin Instance { get; private set; }

		public static Harmony Harmony => Instance._harmony;

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

		public static string ConfigFiles => Path.Combine(Paths.ConfigPath, "CrimsonBanned");

		public static Database Database { get; private set; }

		public override void Load()
		{
			Instance = this;
			Settings = default(Settings);
			Settings.InitConfig();
			_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
			CommandRegistry.RegisterAll();
			foreach (KeyValuePair<string, PluginInfo> plugin in ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins)
			{
				if (plugin.Value.Metadata.GUID.Equals("CrimsonLog"))
				{
					LogLoaded = true;
					break;
				}
			}
			Plugin.OnCoreLoaded = (Action)Delegate.Combine(Plugin.OnCoreLoaded, new Action(Loaded));
		}

		public void Loaded()
		{
			Database = new Database();
		}

		public override bool Unload()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return true;
		}

		public static void LogMessage(string message, bool console = false)
		{
			if (LogLoaded && !console)
			{
				Type type = Type.GetType("CrimsonLog.Systems.Logger, CrimsonLog");
				if (type != null)
				{
					type.GetMethod("Record").Invoke(null, new object[3]
					{
						"Banned",
						"bans",
						message + "\n"
					});
					return;
				}
			}
			LogInstance.LogInfo((object)message);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "CrimsonBanned";

		public const string PLUGIN_NAME = "CrimsonBanned";

		public const string PLUGIN_VERSION = "1.3.3";
	}
}
namespace CrimsonBanned.Utilities
{
	internal static class EntityUtilities
	{
		private static EntityManager EntityManager => Core.EntityManager;

		public static IEnumerable<Entity> GetEntitiesEnumerable(EntityQuery entityQuery)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			NativeArray<Entity> entities;
			JobHandle entities2 = GetEntities(entityQuery, out entities, (Allocator)3);
			((JobHandle)(ref entities2)).Complete();
			try
			{
				Enumerator<Entity> enumerator = entities.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Entity current = enumerator.Current;
					EntityManager entityManager = EntityManager;
					if (((EntityManager)(ref entityManager)).Exists(current))
					{
						yield return current;
					}
				}
			}
			finally
			{
				entities.Dispose();
			}
		}

		private static JobHandle GetEntities(EntityQuery entityQuery, out NativeArray<Entity> entities, Allocator allocator = 3)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			entities = ((EntityQuery)(ref entityQuery)).ToEntityArray(AllocatorHandle.op_Implicit(allocator));
			return default(JobHandle);
		}
	}
	public static class SQLConflict
	{
		public static async Task ResolveOfflines(List<Ban> list)
		{
			List<Ban> list2 = list.FindAll((Ban x) => x.DatabaseId == -1);
			foreach (Ban item in list2)
			{
				int num = SQLlink.AddBan(item, list);
				if (num >= 0)
				{
					item.DatabaseId = num;
				}
				else
				{
					await ResolveConflict(item, list);
				}
			}
		}

		public static async Task<int> ResolveConflict(Ban ban, List<Ban> list)
		{
			Ban ban2 = SQLlink.GetBan(ban.PlayerID, list);
			if (ban2 == null)
			{
				ManualLogSource logInstance = Plugin.LogInstance;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not find ban for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ulong>(ban.PlayerID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" in the database.");
				}
				logInstance.LogError(val);
				return -1000;
			}
			if (ban.DatabaseId != -1 && ban2.DatabaseId != -1 && ban.DatabaseId == ban2.DatabaseId)
			{
				list.Remove(ban);
				return 4;
			}
			if (ban.TimeUntil == ban2.TimeUntil)
			{
				list.Remove(ban);
				Database.AddBan(ban2, list);
				if (TimeUtility.IsPermanent(ban2.TimeUntil) && TimeUtility.IsPermanent(ban.TimeUntil))
				{
					return 0;
				}
				return 4;
			}
			if (TimeUtility.IsPermanent(ban2.TimeUntil))
			{
				list.Remove(ban);
				Database.AddBan(ban2, list);
				return 0;
			}
			if (IsExpiredBan(ban2))
			{
				return await ReplaceExistingBan(ban2, ban, list);
			}
			if (!TimeUtility.IsPermanent(ban2.TimeUntil) && TimeUtility.IsPermanent(ban.TimeUntil))
			{
				return await ReplaceExistingBan(ban2, ban, list);
			}
			if (ban.TimeUntil > ban2.TimeUntil)
			{
				return await ReplaceExistingBan(ban2, ban, list);
			}
			list.Remove(ban);
			Database.AddBan(ban2, list);
			return 1;
		}

		private static bool IsExpiredBan(Ban ban)
		{
			if (ban.TimeUntil < DateTime.UtcNow)
			{
				return !TimeUtility.IsPermanent(ban.TimeUntil);
			}
			return false;
		}

		private static async Task<int> ReplaceExistingBan(Ban oldBan, Ban newBan, List<Ban> list)
		{
			SQLlink.DeleteBan(oldBan, list);
			int databaseId = SQLlink.AddBan(newBan, list);
			newBan.DatabaseId = databaseId;
			Database.AddBan(newBan, list);
			return 2;
		}
	}
	public static class SQLUtility
	{
		private static bool IsSyncing;

		public static bool TrySQL()
		{
			return Database.SQL != null && Settings.UseSQL.Value && SQLlink.Connect();
		}

		public static async void SyncDB()
		{
			if (!TrySQL() || !SQLlink.Connect() || IsSyncing)
			{
				return;
			}
			IsSyncing = true;
			foreach (DeleteLater delete in Database.Deletes)
			{
				SQLlink.DeleteBan(delete.ID, delete.TableName);
			}
			Database.Deletes.Clear();
			if (File.Exists(Database.DeleteFile))
			{
				File.Delete(Database.DeleteFile);
			}
			await SyncTable(Database.ChatBans, "ChatBans");
			await SyncTable(Database.VoiceBans, "VoiceBans");
			await SyncTable(Database.Banned, "ServerBans");
			Database.SaveDatabases();
			IsSyncing = false;
		}

		private static async Task SyncTable(List<Ban> list, string tableName)
		{
			if (ValidateSync(list, tableName))
			{
				await SQLConflict.ResolveOfflines(list);
				DataTable sortedTableFromDatabase = GetSortedTableFromDatabase(tableName);
				HandleRemovedBans(list, sortedTableFromDatabase);
				RemoveExpiredBans(sortedTableFromDatabase, tableName);
				SyncMissingBans(list, sortedTableFromDatabase);
			}
		}

		private static DataTable GetSortedTableFromDatabase(string tableName)
		{
			DataView defaultView = ((DataTable)Database.SQL.Select(tableName)).DefaultView;
			defaultView.Sort = "Id ASC";
			return defaultView.ToTable();
		}

		private static void HandleRemovedBans(List<Ban> list, DataTable sortedTable)
		{
			HashSet<int> bansByID = new HashSet<int>(from DataRow row in sortedTable.Rows
				select Convert.ToInt32(row["Id"]));
			list.RemoveAll((Ban ban) => !bansByID.Contains(ban.DatabaseId) && ban.DatabaseId != -1);
			if (list == Database.Banned)
			{
				Database.BanListFix(list.Where((Ban ban) => !bansByID.Contains(ban.DatabaseId) && ban.DatabaseId != -1).ToList());
			}
		}

		private static void RemoveExpiredBans(DataTable sortedTable, string tableName)
		{
			foreach (DataRow row in sortedTable.Rows)
			{
				DateTime dateTime = Convert.ToDateTime(row["TimeUntil"]);
				if (dateTime < DateTime.UtcNow && !TimeUtility.IsPermanent(dateTime))
				{
					SQLlink.DeleteBan(Convert.ToInt32(row["Id"]), tableName);
				}
			}
		}

		private static void SyncMissingBans(List<Ban> list, DataTable sortedTable)
		{
			foreach (DataRow row in sortedTable.Rows)
			{
				Ban ban = CreateBanFromRow(row);
				if (list.Any((Ban x) => x.DatabaseId == ban.DatabaseId))
				{
					continue;
				}
				if (IsPlayerAlreadyBanned(ban, list, out var existingBan))
				{
					if (TimeUtility.IsPermanent(ban.TimeUntil))
					{
						list.Remove(existingBan);
						AddBanToList(list, ban);
						continue;
					}
					if (TimeUtility.IsPermanent(existingBan.TimeUntil))
					{
						SQLlink.DeleteBan(ban, list);
						AddBanToList(list, existingBan);
						break;
					}
					if (ban.TimeUntil > existingBan.TimeUntil)
					{
						list.Remove(existingBan);
						AddBanToList(list, ban);
					}
					else
					{
						SQLlink.DeleteBan(ban, list);
						AddBanToList(list, existingBan);
					}
				}
				else
				{
					AddBanToList(list, ban);
				}
			}
		}

		private static bool IsPlayerAlreadyBanned(Ban ban, List<Ban> list, out Ban existingBan)
		{
			existingBan = list.Find((Ban x) => x.PlayerID == ban.PlayerID || (x.DatabaseId != -1 && x.DatabaseId == ban.DatabaseId));
			return existingBan != null;
		}

		private static Ban CreateBanFromRow(DataRow row)
		{
			return new Ban(row["PlayerName"].ToString(), Convert.ToUInt64(row["PlayerID"]), Convert.ToDateTime(row["TimeUntil"]), row["Reason"].ToString(), row["IssuedBy"].ToString())
			{
				Issued = Convert.ToDateTime(row["Issued"]),
				DatabaseId = Convert.ToInt32(row["Id"])
			};
		}

		private static void AddBanToList(List<Ban> list, Ban ban)
		{
			list.Add(ban);
			if (list == Database.Banned)
			{
				HandleServerBan(ban);
			}
		}

		private static void HandleServerBan(Ban ban)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (PlayerService.TryFindBySteam(ban.PlayerID, ref val) && EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity).IsConnected)
			{
				Core.StartCoroutine(BanCommands.DelayKick(PlayerService.PlayerFromData(val)));
			}
			if (File.Exists(Settings.BanFilePath.Value))
			{
				UpdateBanFile(ban);
			}
		}

		private static void UpdateBanFile(Ban ban)
		{
			if (!File.ReadAllLines(Settings.BanFilePath.Value).Contains(ban.PlayerID.ToString()))
			{
				File.AppendAllText(Settings.BanFilePath.Value, ban.PlayerID + Environment.NewLine);
			}
		}

		private static bool ValidateSync(List<Ban> list, string tableName)
		{
			if (Database.SQL == null)
			{
				return false;
			}
			if (!SQLlink.Connect())
			{
				return false;
			}
			if (list == null)
			{
				return false;
			}
			if (string.IsNullOrEmpty(tableName))
			{
				return false;
			}
			return true;
		}
	}
	public static class TimeUtility
	{
		public static readonly DateTime MinValueUtc = new DateTime(0L, DateTimeKind.Utc);

		public static string FormatRemainder(DateTime date)
		{
			return FormatRemainder(date - DateTime.Now);
		}

		public static string FormatRemainder(TimeSpan remainder)
		{
			string text = string.Empty;
			if (remainder.Days > 0)
			{
				text += $"{remainder.Days} day{((remainder.Days > 1) ? "s" : "")}, ";
			}
			if (remainder.Hours > 0)
			{
				text += $"{remainder.Hours} hour{((remainder.Hours > 1) ? "s" : "")}, ";
			}
			if (remainder.Minutes > 0)
			{
				text += $"{remainder.Minutes} minute{((remainder.Minutes > 1) ? "s" : "")}";
			}
			if (text.EndsWith(", "))
			{
				text = text.Substring(0, text.Length - 2);
			}
			return text;
		}

		public static TimeSpan LengthParse(int length, string denomination)
		{
			denomination = denomination.ToLower();
			string[] source = new string[5] { "minute", "minutes", "min", "mins", "m" };
			string[] source2 = new string[5] { "hour", "hours", "hrs", "hr", "h" };
			string[] source3 = new string[3] { "day", "days", "d" };
			denomination = (source.Contains(denomination) ? "m" : (source2.Contains(denomination) ? "h" : ((!source3.Contains(denomination)) ? "m" : "d")));
			return denomination switch
			{
				"m" => TimeSpan.FromMinutes(length), 
				"h" => TimeSpan.FromHours(length), 
				"d" => TimeSpan.FromDays(length), 
				_ => TimeSpan.FromMinutes(length), 
			};
		}

		public static bool IsPermanent(DateTime date)
		{
			if (date == DateTime.MinValue)
			{
				return true;
			}
			if (date == DateTime.MinValue.ToUniversalTime())
			{
				return true;
			}
			if (date == DateTime.MinValue.ToLocalTime())
			{
				return true;
			}
			if (date == MinValueUtc)
			{
				return true;
			}
			return false;
		}
	}
}
namespace CrimsonBanned.Structs
{
	public class Ban
	{
		public string PlayerName { get; set; }

		public ulong PlayerID { get; set; }

		[JsonConverter(typeof(JsonDateTimeConverter))]
		public DateTime TimeUntil { get; set; }

		public string Reason { get; set; }

		public string IssuedBy { get; set; }

		[JsonConverter(typeof(JsonDateTimeConverter))]
		public DateTime Issued { get; set; }

		public int DatabaseId { get; set; }

		public bool LocalBan { get; set; }

		public Ban(string playerName, ulong playerID, DateTime timeUntil, string reason, string issuedBy)
		{
			PlayerName = playerName;
			PlayerID = playerID;
			TimeUntil = new DateTime(timeUntil.Year, timeUntil.Month, timeUntil.Day, timeUntil.Hour, timeUntil.Minute, timeUntil.Second, DateTimeKind.Utc);
			Reason = reason;
			DateTime utcNow = DateTime.UtcNow;
			Issued = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, utcNow.Hour, utcNow.Minute, utcNow.Second);
			IssuedBy = issuedBy;
		}
	}
	public class JsonDateTimeConverter : JsonConverter<DateTime>
	{
		public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			DateTime dateTime = new DateTime(reader.GetDateTime().Ticks / 10000000 * 10000000);
			if (dateTime.Kind != DateTimeKind.Utc)
			{
				return DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
			}
			return dateTime;
		}

		public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
		{
			writer.WriteStringValue(value.ToString("yyyy-MM-ddTHH:mm:ssZ"));
		}
	}
	public class Database
	{
		public static readonly JsonSerializerOptions prettyJsonOptions = new JsonSerializerOptions
		{
			WriteIndented = true,
			IncludeFields = true
		};

		public static string BannedFile = Path.Combine(Plugin.ConfigFiles, "bans_server.json");

		public static string ChatBanFile = Path.Combine(Plugin.ConfigFiles, "bans_chat.json");

		public static string VoiceBanFile = Path.Combine(Plugin.ConfigFiles, "bans_voice.json");

		public static string MessageFile = Path.Combine(Plugin.ConfigFiles, "messages.json");

		public static string DeleteFile = Path.Combine(Plugin.ConfigFiles, "ignore.json");

		public static string TrustedFile = Path.Combine(Plugin.ConfigFiles, "trusted.json");

		public static string TrustFile = Path.Combine(Plugin.ConfigFiles, "trust.json");

		public static List<Ban> Banned;

		public static List<Ban> ChatBans;

		public static List<Ban> VoiceBans;

		public static List<MessagePair> Messages;

		public static List<DeleteLater> Deletes;

		public static List<ulong> TrustedUsers;

		public static List<Trust> TrustCommands;

		public static dynamic SQL
		{
			get
			{
				if (!((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("CrimsonSQL", out var value))
				{
					return null;
				}
				return value.Instance.GetType().GetProperty("SQLService").GetValue(value.Instance);
			}
		}

		public Database()
		{
			LoadDatabases();
		}

		private static void LoadDatabases()
		{
			if (!Directory.Exists(Plugin.ConfigFiles))
			{
				Directory.CreateDirectory(Plugin.ConfigFiles);
			}
			if (File.Exists(ChatBanFile))
			{
				ChatBans = JsonSerializer.Deserialize<List<Ban>>(File.ReadAllText(ChatBanFile), prettyJsonOptions);
			}
			else
			{
				ChatBans = new List<Ban>();
			}
			if (File.Exists(VoiceBanFile))
			{
				VoiceBans = JsonSerializer.Deserialize<List<Ban>>(File.ReadAllText(VoiceBanFile), prettyJsonOptions);
			}
			else
			{
				VoiceBans = new List<Ban>();
			}
			if (File.Exists(BannedFile))
			{
				Banned = JsonSerializer.Deserialize<List<Ban>>(File.ReadAllText(BannedFile), prettyJsonOptions);
			}
			else
			{
				Banned = new List<Ban>();
			}
			if (File.Exists(DeleteFile))
			{
				Deletes = JsonSerializer.Deserialize<List<DeleteLater>>(File.ReadAllText(DeleteFile), prettyJsonOptions);
			}
			else
			{
				Deletes = new List<DeleteLater>();
			}
			if (File.Exists(MessageFile))
			{
				Messages = JsonSerializer.Deserialize<List<MessagePair>>(File.ReadAllText(MessageFile), prettyJsonOptions);
			}
			else
			{
				Messages = new List<MessagePair>(4)
				{
					new MessagePair("CheckHeader", "\n{player}'s ({id}) Bans:"),
					new MessagePair("CheckBanLine", "\n{type} Ban\nIssued: {issued}\nRemaining: {remainder}\nReason: {reason}"),
					new MessagePair("ListBan", "\n{player} ({id}) - {remainder}"),
					new MessagePair("AppendedNotification", "")
				};
				string contents = JsonSerializer.Serialize(Messages, prettyJsonOptions);
				File.WriteAllText(MessageFile, contents);
			}
			if (SQL != null && Settings.UseSQL.Value && SQLlink.Connect())
			{
				StartSQLConnection();
			}
			if (Settings.Trusted.Value)
			{
				if (File.Exists(TrustedFile))
				{
					TrustedUsers = JsonSerializer.Deserialize<List<ulong>>(File.ReadAllText(TrustedFile), prettyJsonOptions);
				}
				else
				{
					TrustedUsers = new List<ulong>();
					string contents2 = JsonSerializer.Serialize(TrustedUsers, prettyJsonOptions);
					File.WriteAllText(TrustedFile, contents2);
				}
				if (File.Exists(TrustFile))
				{
					TrustCommands = JsonSerializer.Deserialize<List<Trust>>(File.ReadAllText(TrustFile), prettyJsonOptions);
				}
				else
				{
					TrustCommands = new List<Trust>(10)
					{
						new Trust("?mute {playerName} {reason}", ".ban mute {playerName} 30 min {reason}"),
						new Trust("?ban {playerName} {reason}", ".ban server {playerName} 30 min {reason}"),
						new Trust("?chat {playerName} {reason}", ".ban chat {playerName} 30 min {reason}"),
						new Trust("?voice {playerName} {reason}", ".ban voice {playerName} 30 min {reason}"),
						new Trust("?unmute {playerName}", ".unban mute {playerName}"),
						new Trust("?unban {playerName}", ".unban server {playerName}"),
						new Trust("?unbanchat {playerName}", ".unban chat {playerName}"),
						new Trust("?unbanvoice {playerName}", ".unban voice {playerName}"),
						new Trust("?list {banType} {show} {page}", ".banned list {banType} {show} {page}"),
						new Trust("?check {playerName}", ".banned check {playerName}")
					};
					string contents3 = JsonSerializer.Serialize(TrustCommands, prettyJsonOptions);
					File.WriteAllText(TrustFile, contents3);
				}
			}
			Core.StartCoroutine(Clean());
		}

		public static bool AddTrusted(ulong id)
		{
			if (TrustedUsers.Contains(id))
			{
				return false;
			}
			TrustedUsers.Add(id);
			SaveTrusted();
			return true;
		}

		public static bool RemoveTrusted(ulong id)
		{
			return TrustedUsers.Remove(id);
		}

		private static void SaveTrusted()
		{
			string contents = JsonSerializer.Serialize(TrustedUsers, prettyJsonOptions);
			File.WriteAllText(TrustedFile, contents);
		}

		private static async void StartSQLConnection()
		{
			SQLlink.InitializeBanTables();
			await Task.Yield();
			SQLUtility.SyncDB();
			Core.StartCoroutine(SyncLoop());
		}

		public static void AddBan(Ban ban, List<Ban> list)
		{
			if (list.Exists((Ban x) => x.DatabaseId == ban.DatabaseId))
			{
				return;
			}
			string empty = string.Empty;
			if (list == ChatBans)
			{
				empty = "Chat";
				ChatBans.Add(ban);
			}
			else if (list == VoiceBans)
			{
				empty = "Voice";
				VoiceBans.Add(ban);
			}
			else
			{
				empty = "Server";
				Banned.Add(ban);
				if (File.Exists(Settings.BanFilePath.Value) && !File.ReadAllLines(Settings.BanFilePath.Value).Contains(ban.PlayerID.ToString()))
				{
					File.AppendAllText(Settings.BanFilePath.Value, ban.PlayerID + Environment.NewLine);
				}
			}
			string empty2 = string.Empty;
			string value = TimeUtility.FormatRemainder(ban.TimeUntil - ban.Issued);
			empty2 = ((!ban.LocalBan) ? $"A player with ID: {ban.PlayerID} has had their {empty} ban synced from SQL. Originally issued by {ban.IssuedBy} with {value} remaining." : $"{ban.PlayerName} with ID: {ban.PlayerID} has been {empty} banned. Issued by {ban.IssuedBy} for {value}.");
			Plugin.LogMessage(empty2);
			SaveDatabases();
		}

		public static void DeleteBan(Ban ban, List<Ban> list)
		{
			string empty = string.Empty;
			if (list == ChatBans)
			{
				empty = "Chat";
				ChatBans.Remove(ban);
			}
			else if (list == VoiceBans)
			{
				empty = "Voice";
				VoiceBans.Remove(ban);
			}
			else
			{
				empty = "Server";
				Banned.Remove(ban);
				if (File.Exists(Settings.BanFilePath.Value))
				{
					List<string> list2 = File.ReadAllLines(Settings.BanFilePath.Value).ToList();
					list2.RemoveAll((string line) => line.Trim() == ban.PlayerID.ToString());
					File.WriteAllLines(Settings.BanFilePath.Value, list2);
				}
			}
			string empty2 = string.Empty;
			empty2 = ((!ban.LocalBan) ? $"{empty} ban has ended for synced player ID: {ban.PlayerID}." : (empty + " ban has ended for " + ban.PlayerName + "."));
			Plugin.LogMessage(empty2);
			if (SQLUtility.TrySQL())
			{
				SQLlink.DeleteBan(ban, list);
			}
			else if (SQL != null)
			{
				Deletes.Add(new DeleteLater(ban.DatabaseId, empty + "Bans"));
			}
			SaveDatabases();
		}

		public static void SaveDatabases()
		{
			if (ChatBans.Count > 0 || File.Exists(ChatBanFile))
			{
				string contents = JsonSerializer.Serialize(ChatBans, prettyJsonOptions);
				File.WriteAllText(ChatBanFile, contents);
			}
			if (VoiceBans.Count > 0 || File.Exists(VoiceBanFile))
			{
				string contents2 = JsonSerializer.Serialize(VoiceBans, prettyJsonOptions);
				File.WriteAllText(VoiceBanFile, contents2);
			}
			if (Banned.Count > 0 || File.Exists(BannedFile))
			{
				string contents3 = JsonSerializer.Serialize(Banned, prettyJsonOptions);
				File.WriteAllText(BannedFile, contents3);
			}
			if (Deletes.Count > 0 || File.Exists(DeleteFile))
			{
				string contents4 = JsonSerializer.Serialize(Deletes, prettyJsonOptions);
				File.WriteAllText(DeleteFile, contents4);
			}
		}

		private static IEnumerator SyncLoop()
		{
			while (true)
			{
				BanListFix();
				yield return (object)new WaitForSeconds((float)(Settings.SyncInterval.Value * 60 + Random.Range(-10, 20)));
				SQLUtility.SyncDB();
			}
		}

		public static void BanListFix(List<Ban> additional = null)
		{
			List<Ban> list = Banned.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList();
			if (additional != null)
			{
				list = list.Concat(additional).ToList();
			}
			foreach (Ban ban2 in list)
			{
				DeleteBan(ban2, Banned);
				if (File.Exists(Settings.BanFilePath.Value))
				{
					List<string> list2 = File.ReadAllLines(Settings.BanFilePath.Value).ToList();
					list2.RemoveAll((string line) => line.Trim() == ban2.PlayerID.ToString());
					File.WriteAllLines(Settings.BanFilePath.Value, list2);
				}
			}
		}

		private static IEnumerator Clean()
		{
			while (true)
			{
				yield return (object)new WaitForSeconds(60f);
				List<Ban> list = Banned.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList();
				List<Ban> list2 = ChatBans.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList();
				List<Ban> list3 = VoiceBans.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList();
				foreach (Ban item in list)
				{
					DeleteBan(item, Banned);
				}
				foreach (Ban item2 in list2)
				{
					DeleteBan(item2, ChatBans);
				}
				foreach (Ban item3 in list3)
				{
					DeleteBan(item3, VoiceBans);
				}
			}
		}
	}
	public struct DeleteLater
	{
		public int ID { get; set; }

		public string TableName { get; set; }

		public DeleteLater(int id, string tableName)
		{
			ID = id;
			TableName = tableName;
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public readonly struct Settings
	{
		private const string ConfigHeader = "_Config";

		private const string ServerHeader = "ServerConnection";

		private static readonly List<string> directoryPaths = new List<string>(1) { Plugin.ConfigFiles };

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

		public static ConfigEntry<string> BanFilePath { get; private set; }

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

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

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

		public static void InitConfig()
		{
			foreach (string directoryPath in directoryPaths)
			{
				CreateDirectories(directoryPath);
			}
			ShadowBan = InitConfigEntry("_Config", "ShadowBan", defaultValue: false, "If this is set to true, the player will never be notified when chat or voice banned.");
			BanFilePath = InitConfigEntry("_Config", "BanFilePath", "save-data/Settings/banlist.txt", "The path from root to the banlist.txt file");
			Trusted = InitConfigEntry("_Config", "Trusted", defaultValue: false, "If this is set to true, you can assign trusted members to moderate using predefined commands from trust.json");
			if (Database.SQL != null)
			{
				UseSQL = InitConfigEntry("ServerConnection", "UseSQL", defaultValue: false, "If this is set to true, the plugin will use CrimsonSQL to store bans.");
				SyncInterval = InitConfigEntry("ServerConnection", "SyncInterval", 60, "The interval in minutes to sync the database.");
			}
		}

		private static ConfigEntry<T> InitConfigEntry<T>(string section, string key, T defaultValue, string description)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<T> val = ((BasePlugin)Plugin.Instance).Config.Bind<T>(section, key, defaultValue, description);
			string text = Path.Combine(Paths.ConfigPath, "CrimsonBanned.cfg");
			ConfigEntry<T> val2 = default(ConfigEntry<T>);
			if (File.Exists(text) && new ConfigFile(text, true).TryGetEntry<T>(section, key, ref val2))
			{
				val.Value = val2.Value;
			}
			return val;
		}

		private static void CreateDirectories(string path)
		{
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
		}
	}
	public static class SQLlink
	{
		public static void InitializeBanTables()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				["Id"] = "INT AUTO_INCREMENT PRIMARY KEY",
				["PlayerName"] = "VARCHAR(255)",
				["PlayerID"] = "BIGINT UNSIGNED NOT NULL UNIQUE",
				["TimeUntil"] = "DATETIME NOT NULL",
				["Reason"] = "TEXT",
				["Issued"] = "DATETIME NOT NULL",
				["IssuedBy"] = "VARCHAR(255)"
			};
			Database.SQL.CreateTable("ServerBans", dictionary);
			Database.SQL.CreateTable("ChatBans", dictionary);
			Database.SQL.CreateTable("VoiceBans", dictionary);
		}

		public static int AddBan(Ban ban, List<Ban> list)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>
			{
				["PlayerName"] = ban.PlayerName,
				["PlayerID"] = ban.PlayerID,
				["TimeUntil"] = ban.TimeUntil,
				["Reason"] = ban.Reason,
				["Issued"] = ban.Issued,
				["IssuedBy"] = ban.IssuedBy
			};
			string text = ((list == Database.ChatBans) ? "ChatBans" : ((list == Database.VoiceBans) ? "VoiceBans" : "ServerBans"));
			List<int> list2 = new List<int> { -1062, -1042 };
			int num = Database.SQL.Insert(text, dictionary, list2);
			if (num == -1042)
			{
				num = -1;
			}
			return num;
		}

		public static void DeleteBan(Ban ban, List<Ban> list)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object> { ["Id"] = ban.DatabaseId };
			string text = ((list == Database.ChatBans) ? "ChatBans" : ((list == Database.VoiceBans) ? "VoiceBans" : "ServerBans"));
			Database.SQL.Delete(text, dictionary);
		}

		public static void DeleteBan(int id, string tableName)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object> { ["Id"] = id };
			Database.SQL.Delete(tableName, dictionary);
		}

		public static Ban GetBan(ulong playerID, List<Ban> list)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object> { ["PlayerID"] = playerID };
			string text = ((list == Database.ChatBans) ? "ChatBans" : ((list == Database.VoiceBans) ? "VoiceBans" : "ServerBans"));
			dynamic val = Database.SQL.Select(text, new string[1] { "*" }, dictionary);
			if (val != null && val.Rows.Count > 0)
			{
				dynamic val2 = val.Rows[0];
				Ban ban = new Ban(val2["PlayerName"].ToString(), Convert.ToUInt64(val2["PlayerID"]), Convert.ToDateTime(val2["TimeUntil"]), val2["Reason"].ToString(), val2["IssuedBy"].ToString());
				ban.DatabaseId = Convert.ToInt32(val2["Id"]);
				ban.Issued = Convert.ToDateTime(val2["Issued"]);
				return ban;
			}
			return null;
		}

		public static bool Connect()
		{
			if (Database.SQL == null)
			{
				return false;
			}
			return Database.SQL.Connect();
		}
	}
}
namespace CrimsonBanned.Patches
{
	[HarmonyPatch]
	public static class ChatMessagePatch
	{
		[HarmonyPatch(typeof(ChatMessageSystem), "OnUpdate")]
		public static bool Prefix(ChatMessageSystem __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Invalid comparison between Unknown and I4
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			_ = __instance.__query_661171423_0;
			EntityQuery _query_661171423_ = __instance.__query_661171423_0;
			Enumerator<Entity> enumerator = ((EntityQuery)(ref _query_661171423_)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2)).GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
				FromCharacter componentData = ((EntityManager)(ref entityManager)).GetComponentData<FromCharacter>(current);
				entityManager = ((ComponentSystemBase)__instance).EntityManager;
				User userData = ((EntityManager)(ref entityManager)).GetComponentData<User>(componentData.User);
				entityManager = ((ComponentSystemBase)__instance).EntityManager;
				ChatMessageEvent componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<ChatMessageEvent>(current);
				string messageText = ((object)(FixedString512Bytes)(ref componentData2.MessageText)).ToString();
				if ((int)componentData2.MessageType == 5)
				{
					continue;
				}
				if (HandleTrustedCommand(userData, messageText))
				{
					entityManager = Core.EntityManager;
					((EntityManager)(ref entityManager)).DestroyEntity(current);
				}
				else if (HandleTrustedHelp(userData, messageText))
				{
					entityManager = Core.EntityManager;
					((EntityManager)(ref entityManager)).DestroyEntity(current);
				}
				else if (Database.Banned.Exists((Ban x) => x.PlayerID == userData.PlatformId))
				{
					entityManager = Core.EntityManager;
					((EntityManager)(ref entityManager)).DestroyEntity(current);
				}
				else if (Database.ChatBans.Exists((Ban x) => x.PlayerID == userData.PlatformId))
				{
					Ban ban = Database.ChatBans.First((Ban x) => x.PlayerID == userData.PlatformId);
					if (DateTime.UtcNow > ban.TimeUntil && !TimeUtility.IsPermanent(ban.TimeUntil))
					{
						Database.ChatBans.Remove(ban);
						ChatUtil.SystemSendUser(userData, "Your chat ban has ended.");
					}
					else
					{
						entityManager = Core.EntityManager;
						((EntityManager)(ref entityManager)).DestroyEntity(current);
					}
				}
			}
			return true;
		}

		private static bool HandleTrustedHelp(User userData, string messageText)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (Database.TrustedUsers == null || Database.TrustedUsers.Count == 0)
			{
				return false;
			}
			if (Database.TrustedUsers.Contains(userData.PlatformId))
			{
				if (Database.TrustCommands == null || Database.TrustCommands.Count == 0)
				{
					return false;
				}
				if (messageText.StartsWith($"{Database.TrustCommands[0].Alias[0]}modhelp"))
				{
					string text = "\n";
					foreach (Trust trustCommand in Database.TrustCommands)
					{
						text = text + trustCommand.Alias + " \n";
					}
					ChatUtil.SystemSendUser(userData, text);
					return true;
				}
			}
			return false;
		}

		private static bool HandleTrustedCommand(User userData, string messageText)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			if (Database.TrustedUsers == null || Database.TrustedUsers.Count == 0)
			{
				return false;
			}
			if (Database.TrustedUsers.Contains(userData.PlatformId))
			{
				if (Database.TrustCommands == null || Database.TrustCommands.Count == 0)
				{
					return false;
				}
				foreach (Trust trustCommand in Database.TrustCommands)
				{
					string[] array = messageText.Split(' ');
					string[] array2 = trustCommand.Alias.Split(' ');
					if (array.Length < array2.Length)
					{
						continue;
					}
					bool flag = true;
					string newValue = "";
					string newValue2 = "";
					string newValue3 = "";
					string newValue4 = "";
					string newValue5 = "";
					for (int i = 0; i < array2.Length; i++)
					{
						if (array2[i] == "{playerName}")
						{
							newValue = array[i];
							continue;
						}
						if (array2[i] == "{reason}")
						{
							newValue2 = string.Join(" ", array.Skip(i));
							newValue2 = newValue2.Trim('"');
							break;
						}
						if (array2[i] == "{banType}")
						{
							newValue3 = array[i];
						}
						else if (array2[i] == "{show}")
						{
							newValue4 = array[i];
						}
						else if (array2[i] == "{page}")
						{
							newValue5 = array[i];
						}
						else if (array2[i] != array[i])
						{
							flag = false;
							break;
						}
					}
					if (!flag)
					{
						continue;
					}
					string[] array3 = trustCommand.Command.Replace("{playerName}", newValue).Replace("{reason}", newValue2).Replace("{banType}", newValue3)
						.Replace("{show}", newValue4)
						.Replace("{page}", newValue5)
						.Split(' ');
					if (array3[0] == ".ban")
					{
						switch (array3[1].ToLower())
						{
						case "mute":
							BanCommands.Mute(userData, array3[2], int.Parse(array3[3]), array3[4], string.Join(" ", array3.Skip(5)));
							return true;
						case "chat":
							BanCommands.BanFromChat(userData, array3[2], int.Parse(array3[3]), array3[4], string.Join(" ", array3.Skip(5)));
							return true;
						case "voice":
							BanCommands.BanFromVoice(userData, array3[2], int.Parse(array3[3]), array3[4], string.Join(" ", array3.Skip(5)));
							return true;
						case "server":
							BanCommands.Ban(userData, array3[2], int.Parse(array3[3]), array3[4], string.Join(" ", array3.Skip(5)));
							return true;
						}
					}
					else if (array3[0] == ".unban")
					{
						switch (array3[1].ToLower())
						{
						case "mute":
							UnbanCommands.Unmute(userData, array3[2]);
							return true;
						case "chat":
							UnbanCommands.UnbanFromChat(userData, array3[2]);
							return true;
						case "voice":
							UnbanCommands.UnbanFromVoice(userData, array3[2]);
							return true;
						case "server":
							UnbanCommands.Unban(userData, array3[2]);
							return true;
						}
					}
					else
					{
						if (!(array3[0] == ".banned"))
						{
							continue;
						}
						string text = array3[1].ToLower();
						if (text == "list")
						{
							if (int.TryParse(array3[4], out var result))
							{
								if (result < 1)
								{
									result = 1;
								}
								BannedCommands.List(userData, array3[2], array3[3], result);
							}
							else
							{
								BannedCommands.List(userData, array3[2], array3[3]);
							}
							return true;
						}
						if (text == "check")
						{
							BannedCommands.Check(userData, array3[2]);
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUserConnected")]
	public static class OnUserConnectedPatcch
	{
		public static void Postfix(ServerBootstrapSystem __instance, NetConnectionId netConnectionId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				_ = ((ComponentSystemBase)__instance).EntityManager;
				int num = __instance._NetEndPointToApprovedUserIndex[netConnectionId];
				Entity userEntity = ((Il2CppArrayBase<ServerClient>)(object)__instance._ApprovedUsersLookup)[num].UserEntity;
				EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
				User userData = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
				_ = ((FixedString64Bytes)(ref userData.CharacterName)).IsEmpty;
				if (Database.Banned.Exists((Ban x) => x.PlayerID == userData.PlatformId))
				{
					Ban ban = Database.Banned.First((Ban x) => x.PlayerID == userData.PlatformId);
					if (DateTime.UtcNow > ban.TimeUntil)
					{
						Database.DeleteBan(ban, Database.Banned);
						return;
					}
					entityManager = Core.EntityManager;
					Entity val = ((EntityManager)(ref entityManager)).CreateEntity((ComponentType[])(object)new ComponentType[3]
					{
						ComponentType.ReadOnly<NetworkEventType>(),
						ComponentType.ReadOnly<SendEventToUser>(),
						ComponentType.ReadOnly<KickEvent>()
					});
					EntityUtil.Write<KickEvent>(val, new KickEvent
					{
						PlatformId = userData.PlatformId
					});
					EntityUtil.Write<SendEventToUser>(val, new SendEventToUser
					{
						UserIndex = userData.Index
					});
					EntityUtil.Write<NetworkEventType>(val, new NetworkEventType
					{
						EventId = NetworkEvents.EventId_KickEvent,
						IsAdminEvent = false,
						IsDebugEvent = false
					});
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logInstance = Plugin.LogInstance;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(51, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failure in ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("OnUserConnected");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\nMessage: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" Inner:");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.InnerException?.Message);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\n\nStack: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.StackTrace);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\nInner Stack: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.InnerException?.StackTrace);
				}
				logInstance.LogError(val2);
			}
		}
	}
	[HarmonyPatch]
	public static class VivoxPatch
	{
		[HarmonyPatch(typeof(VivoxConnectionSystem), "OnUpdate")]
		public static void Prefix(VivoxConnectionSystem __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			ProcessEntities(__instance.__query_337126773_0);
			ProcessEntities(__instance.__query_337126773_1);
			ProcessEntities(__instance.__query_337126773_2);
			ProcessEntities(__instance.__query_337126773_3);
		}

		private static void ProcessEntities(EntityQuery query)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			NativeArray<Entity> val = ((EntityQuery)(ref query)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				if (EntityUtil.Has<FromCharacter>(current))
				{
					User user = EntityUtil.Read<User>(EntityUtil.Read<FromCharacter>(current).User);
					HandleUser(current, user);
				}
			}
			val.Dispose();
		}

		private static void HandleUser(Entity entity, User user)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager;
			if (Database.VoiceBans.Exists((Ban x) => x.PlayerID == user.PlatformId))
			{
				Ban ban = Database.VoiceBans.First((Ban x) => x.PlayerID == user.PlatformId);
				if (!(DateTime.UtcNow > ban.TimeUntil) || TimeUtility.IsPermanent(ban.TimeUntil))
				{
					if (EntityUtil.Has<ClientEvent>(entity))
					{
						ClientEvent val = EntityUtil.Read<ClientEvent>(entity);
						val.Type = (VivoxRequestType)0;
						EntityUtil.Write<ClientEvent>(entity, val);
					}
					if (EntityUtil.Has<ClientStateEvent>(entity))
					{
						ClientStateEvent val2 = EntityUtil.Read<ClientStateEvent>(entity);
						val2.IsSpeaking = false;
						EntityUtil.Write<ClientStateEvent>(entity, val2);
					}
					entityManager = Core.EntityManager;
					((EntityManager)(ref entityManager)).DestroyEntity(entity);
					return;
				}
				Database.DeleteBan(ban, Database.VoiceBans);
				if (!Settings.ShadowBan.Value)
				{
					ChatUtil.SystemSendUser(user, "Your voice ban has expired. Please verify in your social settings that Voice Proximity is re-enabled.");
				}
			}
			if (Database.Banned.Exists((Ban x) => x.PlayerID == user.PlatformId))
			{
				entityManager = Core.EntityManager;
				((EntityManager)(ref entityManager)).DestroyEntity(entity);
			}
		}
	}
}
namespace CrimsonBanned.Commands
{
	[CommandGroup("ban", null)]
	internal static class BanCommands
	{
		[Command("server", "s", null, null, null, true)]
		public static void Ban(ChatCommandContext ctx, string name, int length = 0, string timeunit = "day", string reason = "")
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Task<(bool, Player)> task = HandleBanOperation(ctx.User, name, length, timeunit, Database.Banned, "banned from the server", isGameBan: true, reason);
			if (task.Result.Item1)
			{
				if (length > 0)
				{
					Core.StartCoroutine(DelayKick(task.Result.Item2));
				}
				else
				{
					Kick(task.Result.Item2);
				}
			}
		}

		public static void Ban(User user, string name, int length, string timeunit, string reason)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Task<(bool, Player)> task = HandleBanOperation(user, name, length, timeunit, Database.Banned, "banned from the server", isGameBan: true, reason);
			if (task.Result.Item1)
			{
				if (length > 0)
				{
					Core.StartCoroutine(DelayKick(task.Result.Item2));
				}
				else
				{
					Kick(task.Result.Item2);
				}
			}
		}

		[Command("chat", "c", null, null, null, true)]
		public static void BanFromChat(ChatCommandContext ctx, string name, int length = 30, string timeunit = "min", string reason = "")
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			HandleBanOperation(ctx.User, name, length, timeunit, Database.ChatBans, "banned from chat", isGameBan: false, reason);
		}

		public static void BanFromChat(User user, string name, int length = 30, string timeunit = "min", string reason = "")
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			HandleBanOperation(user, name, length, timeunit, Database.ChatBans, "banned from chat", isGameBan: false, reason);
		}

		[Command("voice", "v", null, null, null, true)]
		public static void BanFromVoice(ChatCommandContext ctx, string name, int length = 30, string timeunit = "min", string reason = "")
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			HandleBanOperation(ctx.User, name, length, timeunit, Database.VoiceBans, "banned from voice chat", isGameBan: false, reason);
		}

		public static void BanFromVoice(User user, string name, int length = 30, string timeunit = "min", string reason = "")
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			HandleBanOperation(user, name, length, timeunit, Database.VoiceBans, "banned from voice chat", isGameBan: false, reason);
		}

		[Command("mute", "m", null, null, null, true)]
		public static void Mute(ChatCommandContext ctx, string name, int length = 30, string timeunit = "min", string reason = "")
		{
			BanFromChat(ctx, name, length, timeunit, reason);
			BanFromVoice(ctx, name, length, timeunit, reason);
		}

		public static void Mute(User user, string name, int length = 30, string timeunit = "min", string reason = "")
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			BanFromChat(user, name, length, timeunit, reason);
			BanFromVoice(user, name, length, timeunit, reason);
		}

		[Command("kick", "k", null, null, null, true)]
		public static void KickPlayer(ChatCommandContext ctx, string name)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindByName(name, ref val))
			{
				ctx.Reply("Could not find player with the name " + name + ".");
			}
			else if (EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity) == ctx.User)
			{
				ctx.Reply("You cannot kick yourself.");
			}
			else
			{
				Kick(PlayerService.PlayerFromData(val));
			}
		}

		private static async Task<(bool Success, Player PlayerInfo)> HandleBanOperation(User ctx, string name, int length, string timeunit, List<Ban> banList, string banType, bool isGameBan = false, string reason = "")
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindByName(name, ref val))
			{
				ChatUtil.SystemSendUser(ctx, "Could not find player with the name " + name + ".");
				return (false, null);
			}
			Player player = PlayerService.PlayerFromData(val);
			User user = EntityUtil.Read<User>(player.User);
			if (player.IsAdmin)
			{
				ChatUtil.SystemSendUser(ctx, "You cannot ban an admin.");
				return (false, null);
			}
			if (user == ctx)
			{
				ChatUtil.SystemSendUser(ctx, "You cannot ban yourself.");
				return (false, null);
			}
			if (length < 0)
			{
				ChatUtil.SystemSendUser(ctx, "Please input a valid length of time.");
				return (false, null);
			}
			TimeSpan timeSpan = TimeUtility.LengthParse(length, timeunit);
			DateTime dateTime = DateTime.UtcNow + timeSpan;
			if (reason == "")
			{
				reason = "";
			}
			if (length == 0)
			{
				dateTime = TimeUtility.MinValueUtc;
			}
			if (banList.Exists((Ban x) => x.PlayerID == user.PlatformId))
			{
				Ban ban2 = banList.First((Ban x) => x.PlayerID == user.PlatformId);
				if (TimeUtility.IsPermanent(ban2.TimeUntil))
				{
					ChatUtil.SystemSendUser(ctx, name + " is already permanently " + banType + ".");
					return (false, null);
				}
				if (ban2.TimeUntil > dateTime)
				{
					ChatUtil.SystemSendUser(ctx, name + " is already " + banType + ".");
					return (false, null);
				}
				Database.DeleteBan(ban2, banList);
			}
			Ban ban = new Ban(((object)(FixedString64Bytes)(ref user.CharacterName)).ToString(), user.PlatformId, dateTime, reason, ((object)(FixedString64Bytes)(ref ctx.CharacterName)).ToString())
			{
				LocalBan = true
			};
			if (Database.SQL != null && Settings.UseSQL.Value)
			{
				if (SQLlink.Connect())
				{
					int num = SQLlink.AddBan(ban, banList);
					if (num >= 0 || num == -1)
					{
						ban.DatabaseId = num;
					}
					else
					{
						switch (await SQLConflict.ResolveConflict(ban, banList))
						{
						case 0:
							ChatUtil.SystemSendUser(ctx, name + " is already permanently " + banType + ".");
							return (false, null);
						case 1:
							ChatUtil.SystemSendUser(ctx, name + " already has an active ban with a longer length.");
							return (true, player);
						case 2:
							ChatUtil.SystemSendUser(ctx, $"{name} has been {banType} {((length == 0) ? "permanent" : ("for " + TimeUtility.FormatRemainder(timeSpan)))}");
							return (true, player);
						case 4:
							ChatUtil.SystemSendUser(ctx, name + " is already " + banType + ".");
							return (false, null);
						}
					}
				}
				else
				{
					ban.DatabaseId = -1;
				}
			}
			else
			{
				ban.DatabaseId = -1;
			}
			Database.AddBan(ban, banList);
			ChatUtil.SystemSendUser(ctx, $"{name} has been {banType} {((length == 0) ? "permanently." : ("for " + TimeUtility.FormatRemainder(timeSpan)))}");
			if (!Settings.ShadowBan.Value || isGameBan)
			{
				string text = (isGameBan ? $"You have been {banType} {((length == 0) ? "permanently" : ("for " + TimeUtility.FormatRemainder(timeSpan)))}." : $"You have been {banType} {((length == 0) ? "permanently" : ("for " + TimeUtility.FormatRemainder(timeSpan)))}.");
				ChatUtil.SystemSendUser(user, text + Database.Messages[3].ToString(ban));
			}
			return (true, player);
		}

		public static IEnumerator DelayKick(Player player)
		{
			yield return (object)new WaitForSeconds(5f);
			Kick(player);
		}

		private static void Kick(Player player)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = Core.Server.EntityManager;
			User val = EntityUtil.Read<User>(player.User);
			if (val.PlatformId != 0L)
			{
				Entity val2 = ((EntityManager)(ref entityManager)).CreateEntity((ComponentType[])(object)new ComponentType[3]
				{
					ComponentType.ReadOnly<NetworkEventType>(),
					ComponentType.ReadOnly<SendEventToUser>(),
					ComponentType.ReadOnly<KickEvent>()
				});
				EntityUtil.Write<KickEvent>(val2, new KickEvent
				{
					PlatformId = val.PlatformId
				});
				EntityUtil.Write<SendEventToUser>(val2, new SendEventToUser
				{
					UserIndex = val.Index
				});
				EntityUtil.Write<NetworkEventType>(val2, new NetworkEventType
				{
					EventId = NetworkEvents.EventId_KickEvent,
					IsAdminEvent = false,
					IsDebugEvent = false
				});
			}
		}
	}
	[CommandGroup("banid", null)]
	internal static class BanIDCommands
	{
		[Command("server", "s", null, null, null, true)]
		public static void Ban(ChatCommandContext ctx, ulong id, int length = 0, string timeunit = "day", string reason = "")
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindBySteam(id, ref val))
			{
				HandleBanOperation(ctx, id, length, timeunit, Database.Banned, "banned from the server", isServerBan: true, reason);
				return;
			}
			User val2 = EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity);
			BanCommands.Ban(ctx, ((object)(FixedString64Bytes)(ref val2.CharacterName)).ToString(), length, timeunit, reason);
		}

		[Command("chat", "c", null, null, null, true)]
		public static void BanFromChat(ChatCommandContext ctx, ulong id, int length = 30, string timeunit = "min", string reason = "")
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindBySteam(id, ref val))
			{
				HandleBanOperation(ctx, id, length, timeunit, Database.ChatBans, "banned from chat", isServerBan: false, reason);
				return;
			}
			User val2 = EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity);
			BanCommands.BanFromChat(ctx, ((object)(FixedString64Bytes)(ref val2.CharacterName)).ToString(), length, timeunit, reason);
		}

		[Command("voice", "v", null, null, null, true)]
		public static void BanFromVoice(ChatCommandContext ctx, ulong id, int length = 30, string timeunit = "min", string reason = "")
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindBySteam(id, ref val))
			{
				HandleBanOperation(ctx, id, length, timeunit, Database.VoiceBans, "banned from voice chat", isServerBan: false, reason);
				return;
			}
			User val2 = EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity);
			BanCommands.BanFromVoice(ctx, ((object)(FixedString64Bytes)(ref val2.CharacterName)).ToString(), length, timeunit, reason);
		}

		[Command("mute", "m", null, null, null, true)]
		public static void Mute(ChatCommandContext ctx, ulong id, int length = 30, string timeunit = "min", string reason = "")
		{
			BanFromChat(ctx, id, length, timeunit, reason);
			BanFromVoice(ctx, id, length, timeunit, reason);
		}

		private static async void HandleBanOperation(ChatCommandContext ctx, ulong id, int length, string timeunit, List<Ban> list, string banType, bool isServerBan, string reason)
		{
			TimeSpan timeSpan = TimeUtility.LengthParse(length, timeunit);
			DateTime dateTime = DateTime.UtcNow + timeSpan;
			if (list.Exists((Ban x) => x.PlayerID == id))
			{
				ctx.Reply($"Player {id} is already {banType}.");
				return;
			}
			if (length < 0)
			{
				ctx.Reply("Please input a valid length of time.");
				return;
			}
			if (length == 0)
			{
				dateTime = TimeUtility.MinValueUtc;
			}
			if (reason == "")
			{
				reason = "";
			}
			string empty = string.Empty;
			ulong playerID = id;
			DateTime timeUntil = dateTime;
			string reason2 = reason;
			User user = ctx.User;
			Ban ban = new Ban(empty, playerID, timeUntil, reason2, ((object)(FixedString64Bytes)(ref user.CharacterName)).ToString())
			{
				LocalBan = true
			};
			if (Database.SQL != null && Settings.UseSQL.Value)
			{
				if (SQLlink.Connect())
				{
					int num = SQLlink.AddBan(ban, list);
					if (num >= 0)
					{
						ban.DatabaseId = num;
					}
					else
					{
						switch (await SQLConflict.ResolveConflict(ban, list))
						{
						case 0:
							ctx.Reply($"{id} is already permanently {banType}.");
							return;
						case 1:
							ctx.Reply($"{id} has had their previous ban imported from SQL with a longer duration.");
							return;
						case 2:
							ctx.Reply($"{id} has been {banType} {((length == 0) ? "permanently." : ("for " + TimeUtility.FormatRemainder(timeSpan) + "."))}");
							return;
						}
					}
				}
				else
				{
					ban.DatabaseId = -1;
				}
			}
			else
			{
				ban.DatabaseId = -1;
			}
			Database.AddBan(ban, list);
			ctx.Reply($"Player {id} has been {banType}.");
		}
	}
	[CommandGroup("banned", null)]
	internal static class BannedCommands
	{
		private const int MESSAGE_LIMIT = 460;

		private const int MESSAGES_PER_PAGE = 2;

		[Command("list", "l", null, null, null, true)]
		public static void List(ChatCommandContext ctx, string banType = "server", string show = "perma/temp", int page = 1)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			List(ctx.User, banType, show, page);
		}

		public static void List(User ctx, string banType = "server", string show = "perma/temp", int page = 1)
		{
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			banType = banType.ToLower() switch
			{
				"server" => "Server", 
				"s" => "Server", 
				"chat" => "Chat", 
				"c" => "Chat", 
				"voice" => "Voice", 
				"v" => "Voice", 
				_ => "Server", 
			};
			List<Ban> list = banType switch
			{
				"Server" => Database.Banned, 
				"Chat" => Database.ChatBans, 
				"Voice" => Database.VoiceBans, 
				_ => new List<Ban>(), 
			};
			show = show switch
			{
				"perma" => "perma", 
				"temp" => "temp", 
				"p" => "perma", 
				"t" => "temp", 
				_ => "perma/temp", 
			};
			if (show == "temp")
			{
				list = list.FindAll((Ban x) => !TimeUtility.IsPermanent(x.TimeUntil));
			}
			else if (show == "perma")
			{
				list = list.FindAll((Ban x) => TimeUtility.IsPermanent(x.TimeUntil));
			}
			if (list.Count == 0)
			{
				ChatUtil.SystemSendUser(ctx, "No players in this ban list.");
				return;
			}
			list.Sort((Ban x, Ban y) => y.Issued.CompareTo(x.Issued));
			string item = "\n" + banType + " Bans:\n";
			List<string> list2 = new List<string> { item };
			int num = 0;
			foreach (Ban item2 in list)
			{
				string text = Database.Messages[2].ToString(item2);
				if (list2[num].Length + text.Length > 460)
				{
					num++;
					list2.Add(text);
				}
				else
				{
					list2[num] += text;
				}
			}
			int num2 = (int)Math.Ceiling((double)list2.Count / 2.0);
			if (page < 1 || page > num2)
			{
				page = 1;
			}
			int num3 = (page - 1) * 2;
			int num4 = Math.Min(num3 + 2, list2.Count);
			if (num2 > 1)
			{
				ChatUtil.SystemSendUser(ctx, $"Page {page} of {num2}:");
			}
			for (int i = num3; i < num4; i++)
			{
				ChatUtil.SystemSendUser(ctx, list2[i]);
			}
		}

		[Command("loaduntracked", null, null, null, null, true)]
		public static void Backlog(ChatCommandContext ctx)
		{
			SQLUtility.SyncDB();
			if (File.Exists(Settings.BanFilePath.Value))
			{
				string[] array = File.ReadAllLines(Settings.BanFilePath.Value);
				foreach (string line in array)
				{
					if (!Database.Banned.Exists((Ban x) => x.PlayerID == Convert.ToUInt64(line)))
					{
						Database.AddBan(new Ban(string.Empty, Convert.ToUInt64(line), TimeUtility.MinValueUtc, "", "banlist.txt")
						{
							LocalBan = true,
							DatabaseId = -1
						}, Database.Banned);
					}
				}
				ctx.Reply("Untracked server bans in banlist.txt imported and added to tracking.");
			}
			else
			{
				ctx.Reply("Local banlist.txt not found. Please specify the file path.");
			}
		}

		[Command("sync", null, null, null, null, true)]
		public static void Sync(ChatCommandContext ctx)
		{
			if (Database.SQL == null)
			{
				ctx.Reply("MySQL is not configured. Please configure MySQL using CrimsonSQL.");
				return;
			}
			if (!Settings.UseSQL.Value)
			{
				ctx.Reply("You are not using CrimsonSQL. Ensure it is installed and the setting is set to true.");
				return;
			}
			if (!SQLlink.Connect())
			{
				ctx.Reply("Connection could not be established with the SQL database.");
				return;
			}
			SQLUtility.SyncDB();
			ctx.Reply("Bans have been synced with SQL Database.");
		}

		[Command("checkid", null, null, null, null, true)]
		public static void CheckID(ChatCommandContext ctx, string id)
		{
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			ulong ID = Convert.ToUInt64(id);
			List<(Ban, BanDetails)> list = new List<(Ban, BanDetails)>();
			List<Ban> list2 = new List<Ban>();
			Ban ban = Database.Banned?.Find((Ban x) => x.PlayerID == ID);
			if (ban != null)
			{
				list2.Add(ban);
			}
			Ban ban2 = Database.ChatBans?.Find((Ban x) => x.PlayerID == ID);
			if (ban2 != null)
			{
				list2.Add(ban2);
			}
			Ban ban3 = Database.VoiceBans?.Find((Ban x) => x.PlayerID == ID);
			if (ban3 != null)
			{
				list2.Add(ban3);
			}
			if (list2.Count == 0)
			{
				ctx.Reply($"No bans found for ID {ID}.");
				return;
			}
			bool flag = false;
			foreach (Ban item3 in list2)
			{
				if (item3 == null)
				{
					continue;
				}
				if (!item3.LocalBan)
				{
					flag = true;
				}
				Ban ban4 = item3;
				List<Ban> list3;
				if (Database.Banned.Contains(ban4))
				{
					list3 = Database.Banned;
				}
				else
				{
					Ban item = ban4;
					if (Database.ChatBans.Contains(item))
					{
						list3 = Database.ChatBans;
					}
					else
					{
						Ban item2 = ban4;
						list3 = ((!Database.VoiceBans.Contains(item2)) ? null : Database.VoiceBans);
					}
				}
				List<Ban> list4 = list3;
				if (list4 != null && GetBanDetails(item3, list4, out var details))
				{
					list.Add((item3, details));
				}
			}
			if (list.Count == 0)
			{
				ctx.Reply($"No bans found for ID {ID}.");
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(Database.Messages[0].ToString(list[0].Item1, list[0].Item2));
			PlayerData val = default(PlayerData);
			if (PlayerService.TryFindBySteam(ID, ref val) && flag)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
				handler.AppendLiteral("Local server name: ");
				User val2 = EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity);
				handler.AppendFormatted(((object)(FixedString64Bytes)(ref val2.CharacterName)).ToString());
				stringBuilder2.AppendLine(ref handler);
			}
			foreach (var item4 in list)
			{
				stringBuilder.AppendLine(Database.Messages[1].ToString(item4.Item1, item4.Item2));
			}
			ctx.Reply(stringBuilder.ToString());
		}

		[Command("check", null, null, null, null, true)]
		public static void Check(ChatCommandContext ctx, string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Check(ctx.User, name);
		}

		public static void Check(User ctx, string name)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindByName(name, ref val))
			{
				ChatUtil.SystemSendUser(ctx, "Could not find player with the name " + name + ".");
				return;
			}
			Player val2 = PlayerService.PlayerFromData(val);
			User user = EntityUtil.Read<User>(val2.User);
			List<(Ban, BanDetails)> list = new List<(Ban, BanDetails)>();
			foreach (Ban item3 in new List<Ban>
			{
				Database.ChatBans.Find((Ban x) => x.PlayerID == user.PlatformId),
				Database.VoiceBans.Find((Ban x) => x.PlayerID == user.PlatformId),
				Database.Banned.Find((Ban x) => x.PlayerID == user.PlatformId)
			})
			{
				if (item3 == null)
				{
					continue;
				}
				Ban ban = item3;
				List<Ban> list2;
				if (Database.Banned.Contains(ban))
				{
					list2 = Database.Banned;
				}
				else
				{
					Ban item = ban;
					if (Database.ChatBans.Contains(item))
					{
						list2 = Database.ChatBans;
					}
					else
					{
						Ban item2 = ban;
						list2 = ((!Database.VoiceBans.Contains(item2)) ? null : Database.VoiceBans);
					}
				}
				List<Ban> list3 = list2;
				if (list3 != null && GetBanDetails(item3, list3, out var details))
				{
					list.Add((item3, details));
				}
			}
			if (list.Count == 0)
			{
				ChatUtil.SystemSendUser(ctx, name + " is not banned.");
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(Database.Messages[0].ToString(list[0].Item1, list[0].Item2));
			foreach (var item4 in list)
			{
				stringBuilder.AppendLine(Database.Messages[1].ToString(item4.Item1, item4.Item2));
			}
			ChatUtil.SystemSendUser(ctx, stringBuilder.ToString());
		}

		internal static bool GetBanDetails(Ban ban, List<Ban> list, out BanDetails details)
		{
			if (!TimeUtility.IsPermanent(ban.TimeUntil) && DateTime.UtcNow > ban.TimeUntil)
			{
				details = null;
				Database.DeleteBan(ban, list);
				return false;
			}
			details = new BanDetails();
			details.Ban = ban;
			details.IssuedOn = ban.Issued.ToLocalTime().ToString("MM/dd/yy HH:mm");
			if (list == Database.Banned)
			{
				details.BanType = "Server";
			}
			else if (list == Database.ChatBans)
			{
				details.BanType = "Chat";
			}
			else if (list == Database.VoiceBans)
			{
				details.BanType = "Voice";
			}
			if (TimeUtility.IsPermanent(ban.TimeUntil))
			{
				details.RemainingTime = "Permanent";
			}
			else
			{
				details.RemainingTime = $"Expires in {ban.TimeUntil - DateTime.UtcNow}";
			}
			return true;
		}
	}
	public class BanDetails
	{
		public Ban Ban { get; set; }

		public string BanType { get; set; }

		public string IssuedOn { get; set; }

		public string RemainingTime { get; set; }
	}
	[CommandGroup("trusted", null)]
	internal static class TrustCommands
	{
		[Command("add", "a", null, null, null, true)]
		public static void Add(ChatCommandContext ctx, string playerName)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			PlayerData playerInfo = default(PlayerData);
			if (!PlayerService.TryFindByName(playerName, ref playerInfo))
			{
				ctx.Reply("Could not find player with the name " + playerName + ".");
				return;
			}
			if (Database.TrustedUsers.Any((ulong t) => t == EntityUtil.Read<User>(((PlayerData)(ref playerInfo)).UserEntity).PlatformId))
			{
				ctx.Reply(playerName + " is already trusted.");
				return;
			}
			Database.AddTrusted(EntityUtil.Read<User>(((PlayerData)(ref playerInfo)).UserEntity).PlatformId);
			ctx.Reply(playerName + " has been added to the trusted list.");
		}

		[Command("remove", "r", null, null, null, true)]
		public static void Remove(ChatCommandContext ctx, string playerName)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			PlayerData playerInfo = default(PlayerData);
			if (!PlayerService.TryFindByName(playerName, ref playerInfo))
			{
				ctx.Reply("Could not find player with the name " + playerName + ".");
				return;
			}
			if (!Database.TrustedUsers.Any((ulong t) => t == EntityUtil.Read<User>(((PlayerData)(ref playerInfo)).UserEntity).PlatformId))
			{
				ctx.Reply(playerName + " is not on the trusted list.");
				return;
			}
			Database.RemoveTrusted(EntityUtil.Read<User>(((PlayerData)(ref playerInfo)).UserEntity).PlatformId);
			ctx.Reply(playerName + " has been removed from the trusted list.");
		}
	}
	[CommandGroup("unban", null)]
	internal static class UnbanCommands
	{
		[Command("server", "s", null, null, null, true)]
		public static void Unban(ChatCommandContext ctx, string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			HandleUnbanOperation(ctx.User, name, Database.Banned, "unbanned from the server", "the server");
		}

		public static void Unban(User user, string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			HandleUnbanOperation(user, name, Database.Banned, "unbanned from the server", "the server");
		}

		[Command("chat", "c", null, null, null, true)]
		public static void UnbanFromChat(ChatCommandContext ctx, string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			HandleUnbanOperation(ctx.User, name, Database.ChatBans, "unbanned from chat", "chat");
		}

		public static void UnbanFromChat(User user, string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			HandleUnbanOperation(user, name, Database.ChatBans, "unbanned from chat", "chat");
		}

		[Command("voice", "v", null, null, null, true)]
		public static void UnbanFromVoice(ChatCommandContext ctx, string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			HandleUnbanOperation(ctx.User, name, Database.VoiceBans, "unbanned from voice chat", "voice chat");
		}

		public static void UnbanFromVoice(User user, string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			HandleUnbanOperation(user, name, Database.VoiceBans, "unbanned from voice chat", "voice chat");
		}

		[Command("mute", "m", null, null, null, true)]
		public static void Unmute(ChatCommandContext ctx, string name)
		{
			UnbanFromChat(ctx, name);
			UnbanFromVoice(ctx, name);
		}

		public static void Unmute(User user, string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			UnbanFromChat(user, name);
			UnbanFromVoice(user, name);
		}

		private static void HandleUnbanOperation(User ctx, string name, List<Ban> banList, string unbanType, string noneFound)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			PlayerData playerInfo = default(PlayerData);
			if (!PlayerService.TryFindByName(name, ref playerInfo))
			{
				ChatUtil.SystemSendUser(ctx, "Could not find player with the name " + name + ".");
				return;
			}
			if (!banList.Exists((Ban x) => x.PlayerID == EntityUtil.Read<User>(((PlayerData)(ref playerInfo)).UserEntity).PlatformId))
			{
				ChatUtil.SystemSendUser(ctx, name + " is not banned from " + noneFound + ".");
				return;
			}
			Ban ban = banList.First((Ban x) => x.PlayerID == EntityUtil.Read<User>(((PlayerData)(ref playerInfo)).UserEntity).PlatformId);
			if (!ctx.IsAdmin && Database.TrustedUsers.Contains(ctx.PlatformId) && ban.IssuedBy != ((object)(FixedString64Bytes)(ref ctx.CharacterName)).ToString())
			{
				ChatUtil.SystemSendUser(ctx, $"You are not allowed to unban {name} from {noneFound}.");
				return;
			}
			Database.DeleteBan(ban, banList);
			ChatUtil.SystemSendUser(ctx, name + " has been " + unbanType + ".");
			if (!unbanType.Contains("server") && !Settings.ShadowBan.Value)
			{
				ChatUtil.SystemSendUser(EntityUtil.Read<User>(((PlayerData)(ref playerInfo)).UserEntity), "You have been " + unbanType + ".");
			}
			if (unbanType.Contains("server") && File.Exists(Settings.BanFilePath.Value))
			{
				List<string> list = File.ReadAllLines(Settings.BanFilePath.Value).ToList();
				list.RemoveAll((string line) => line.Trim() == ban.PlayerID.ToString());
				File.WriteAllLines(Settings.BanFilePath.Value, list);
			}
		}
	}
	[CommandGroup("unbanid", null)]
	internal static class UnbanIDCommands
	{
		[Command("server", "s", null, null, null, true)]
		public static void Unban(ChatCommandContext ctx, ulong id)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindBySteam(id, ref val))
			{
				HandleUnbanOperation(ctx, id, Database.Banned, "unbanned from the server", "the server");
				return;
			}
			User val2 = EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity);
			UnbanCommands.Unban(ctx, ((object)(FixedString64Bytes)(ref val2.CharacterName)).ToString());
		}

		[Command("chat", "c", null, null, null, true)]
		public static void UnbanFromChat(ChatCommandContext ctx, ulong id)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindBySteam(id, ref val))
			{
				HandleUnbanOperation(ctx, id, Database.ChatBans, "unbanned from chat", "chat");
				return;
			}
			User val2 = EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity);
			UnbanCommands.UnbanFromChat(ctx, ((object)(FixedString64Bytes)(ref val2.CharacterName)).ToString());
		}

		[Command("voice", "v", null, null, null, true)]
		public static void UnbanFromVoice(ChatCommandContext ctx, ulong id)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerData val = default(PlayerData);
			if (!PlayerService.TryFindBySteam(id, ref val))
			{
				HandleUnbanOperation(ctx, id, Database.VoiceBans, "unbanned from voice chat", "voice chat");
				return;
			}
			User val2 = EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity);
			UnbanCommands.UnbanFromVoice(ctx, ((object)(FixedString64Bytes)(ref val2.CharacterName)).ToString());
		}

		[Command("mute", "m", null, null, null, true)]
		public static void Unmute(ChatCommandContext ctx, ulong id)
		{
			UnbanFromChat(ctx, id);
			UnbanFromVoice(ctx, id);
		}

		private static void HandleUnbanOperation(ChatCommandContext ctx, ulong id, List<Ban> banList, string unbanType, string noneFound)
		{
			if (!banList.Exists((Ban x) => x.PlayerID == id))
			{
				ctx.Reply($"{id} is not banned from {noneFound}.");
				return;
			}
			Ban ban = banList.First((Ban x) => x.PlayerID == id);
			Database.DeleteBan(ban, banList);
			ctx.Reply($"{id} has been {unbanType}.");
			if (unbanType.Contains("server") && File.Exists(Settings.BanFilePath.Value))
			{
				List<string> list = File.ReadAllLines(Settings.BanFilePath.Value).ToList();
				list.RemoveAll((string line) => line.Trim() == ban.PlayerID.ToString());
				File.WriteAllLines(Settings.BanFilePath.Value, list);
			}
		}
	}
}