Decompiled source of CrimsonBanned v2.0.0

CrimsonBanned.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
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;
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.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("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+Branch.master.Sha.03d4f7542cdc7455740ba02c4c45ed7bb880f046.03d4f7542cdc7455740ba02c4c45ed7bb880f046")]
[assembly: AssemblyProduct("CrimsonBanned")]
[assembly: AssemblyTitle("CrimsonBanned")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.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;
		}
	}
}
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", "2.0.0")]
	[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;
				}
			}
			Events.OnCoreLoaded = (Action)Delegate.Combine(Events.OnCoreLoaded, new Action(Loaded));
		}

		public void Loaded()
		{
			Database = new Database();
			ThreadingUtility.Initialize();
			SQLBackgroundService.Initialize();
		}

		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 = "2.0.0";
	}
}
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 FileUtility
	{
		public static void WriteJsonToFileAsync<T>(string filePath, T data, JsonSerializerOptions options = null)
		{
			SQLBackgroundService.Enqueue(async delegate
			{
				try
				{
					string contents = JsonSerializer.Serialize(data, options ?? Database.prettyJsonOptions);
					await File.WriteAllTextAsync(filePath, contents);
				}
				catch (Exception ex2)
				{
					Exception ex3 = ex2;
					Exception ex = ex3;
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0010: Expected O, but got Unknown
						ManualLogSource logInstance = Plugin.LogInstance;
						bool flag = default(bool);
						BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(24, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error writing to file ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(filePath);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						logInstance.LogError(val);
					});
				}
			});
		}

		public static async Task<T> ReadJsonFromFileAsync<T>(string filePath, JsonSerializerOptions options = null)
		{
			try
			{
				if (!File.Exists(filePath))
				{
					return default(T);
				}
				return JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(filePath), options ?? Database.prettyJsonOptions);
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				ThreadingUtility.RunOnMainThread(delegate
				{
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					//IL_0010: Expected O, but got Unknown
					ManualLogSource logInstance = Plugin.LogInstance;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error reading from file ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(filePath);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					logInstance.LogError(val);
				});
				return default(T);
			}
		}

		public static void UpdateBanFileAsync(string filePath, ulong playerId, bool isAdding)
		{
			SQLBackgroundService.Enqueue(async delegate
			{
				_ = 3;
				try
				{
					if (!File.Exists(filePath))
					{
						if (isAdding)
						{
							await File.WriteAllTextAsync(filePath, playerId + Environment.NewLine);
						}
					}
					else
					{
						string[] source = await File.ReadAllLinesAsync(filePath);
						if (isAdding)
						{
							if (!source.Contains(playerId.ToString()))
							{
								await File.AppendAllTextAsync(filePath, playerId + Environment.NewLine);
							}
						}
						else
						{
							List<string> list = source.ToList();
							list.RemoveAll((string line) => line.Trim() == playerId.ToString());
							await File.WriteAllLinesAsync(filePath, list);
						}
					}
				}
				catch (Exception ex2)
				{
					Exception ex3 = ex2;
					Exception ex = ex3;
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0010: Expected O, but got Unknown
						ManualLogSource logInstance = Plugin.LogInstance;
						bool flag = default(bool);
						BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error updating ban file ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(filePath);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						logInstance.LogError(val);
					});
				}
			});
		}
	}
	public static class SQLBackgroundService
	{
		private static readonly ConcurrentQueue<Func<Task>> _taskQueue = new ConcurrentQueue<Func<Task>>();

		private static readonly CancellationTokenSource _cancellation = new CancellationTokenSource();

		private static Task _processingTask;

		private static readonly SemaphoreSlim _signal = new SemaphoreSlim(0);

		private static bool _isRunning = false;

		public static void Initialize()
		{
			if (!_isRunning)
			{
				_isRunning = true;
				_processingTask = Task.Run(() => ProcessQueueAsync(_cancellation.Token));
				Plugin.LogInstance.LogInfo((object)"SQL Background Service initialized");
			}
		}

		public static void Enqueue(Func<Task> task)
		{
			if (!_isRunning)
			{
				Initialize();
			}
			_taskQueue.Enqueue(task);
			_signal.Release();
		}

		private static async Task ProcessQueueAsync(CancellationToken token)
		{
			while (!token.IsCancellationRequested && _isRunning)
			{
				await _signal.WaitAsync(token).ConfigureAwait(continueOnCapturedContext: false);
				if (!_taskQueue.TryDequeue(out var result))
				{
					continue;
				}
				try
				{
					await result().ConfigureAwait(continueOnCapturedContext: false);
				}
				catch (Exception ex2)
				{
					Exception ex3 = ex2;
					Exception ex = ex3;
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0010: Expected O, but got Unknown
						ManualLogSource logInstance = Plugin.LogInstance;
						bool flag = default(bool);
						BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(27, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SQL background task error: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						logInstance.LogError(val);
					});
				}
			}
		}

		public static void Shutdown()
		{
			_isRunning = false;
			_cancellation.Cancel();
			_signal.Release();
		}
	}
	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 void SyncDB()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			if (!TrySQL() || IsSyncing)
			{
				return;
			}
			IsSyncing = true;
			Stopwatch stopwatch = Stopwatch.StartNew();
			Stopwatch stopwatch2 = Stopwatch.StartNew();
			SQLBackgroundService.Enqueue(async delegate
			{
				_ = 2;
				try
				{
					foreach (DeleteLater delete in Database.Deletes)
					{
						SQLlink.DeleteBan(delete.ID, delete.TableName);
					}
					Database.Deletes.Clear();
					if (File.Exists(Database.DeleteFile))
					{
						File.Delete(Database.DeleteFile);
					}
					string text = "\n                SELECT 'ChatBans' as TableName, Id, PlayerName, PlayerID, TimeUntil, Reason, IssuedBy, Issued FROM ChatBans\n                UNION ALL\n                SELECT 'VoiceBans' as TableName, Id, PlayerName, PlayerID, TimeUntil, Reason, IssuedBy, Issued FROM VoiceBans\n                UNION ALL\n                SELECT 'ServerBans' as TableName, Id, PlayerName, PlayerID, TimeUntil, Reason, IssuedBy, Issued FROM ServerBans\n                ORDER BY TableName, Id ASC";
					dynamic val2 = Database.SQL.ExecuteQuery(text);
					if (val2 != null && val2.Rows.Count > 0)
					{
						dynamic val3 = val2.Select("TableName = 'ChatBans'");
						dynamic val4 = val2.Select("TableName = 'VoiceBans'");
						dynamic val5 = val2.Select("TableName = 'ServerBans'");
						DataTable dataTable = ((val3.Length > 0) ? val2.Clone() : null);
						DataTable voiceBanTable = ((val4.Length > 0) ? val2.Clone() : null);
						DataTable serverBanTable = ((val5.Length > 0) ? val2.Clone() : null);
						if (dataTable != null)
						{
							foreach (dynamic item in val3)
							{
								dataTable.ImportRow(item);
							}
						}
						if (voiceBanTable != null)
						{
							foreach (dynamic item2 in val4)
							{
								voiceBanTable.ImportRow(item2);
							}
						}
						if (serverBanTable != null)
						{
							foreach (dynamic item3 in val5)
							{
								serverBanTable.ImportRow(item3);
							}
						}
						if (dataTable != null)
						{
							await SyncTable(Database.ChatBans, dataTable, "ChatBans");
						}
						if (voiceBanTable != null)
						{
							await SyncTable(Database.VoiceBans, voiceBanTable, "VoiceBans");
						}
						if (serverBanTable != null)
						{
							await SyncTable(Database.Banned, serverBanTable, "ServerBans");
						}
					}
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_0020: Unknown result type (might be due to invalid IL or missing references)
						//IL_0026: Expected O, but got Unknown
						Database.SaveDatabases();
						IsSyncing = false;
						stopwatch.Stop();
						ManualLogSource logInstance3 = Plugin.LogInstance;
						bool flag3 = default(bool);
						BepInExInfoLogInterpolatedStringHandler val7 = new BepInExInfoLogInterpolatedStringHandler(23, 1, ref flag3);
						if (flag3)
						{
							((BepInExLogInterpolatedStringHandler)val7).AppendLiteral("Sync took ");
							((BepInExLogInterpolatedStringHandler)val7).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
							((BepInExLogInterpolatedStringHandler)val7).AppendLiteral("ms to process");
						}
						logInstance3.LogInfo(val7);
					});
				}
				catch (Exception ex2)
				{
					Exception ex3 = ex2;
					Exception ex = ex3;
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_0010: Unknown result type (might be due to invalid IL or missing references)
						//IL_0016: Expected O, but got Unknown
						IsSyncing = false;
						ManualLogSource logInstance2 = Plugin.LogInstance;
						bool flag2 = default(bool);
						BepInExErrorLogInterpolatedStringHandler val6 = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("Error executing union query: ");
							((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(ex.Message);
						}
						logInstance2.LogError(val6);
					});
				}
			});
			stopwatch2.Stop();
			ManualLogSource logInstance = Plugin.LogInstance;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Sync took ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(stopwatch2.ElapsedMilliseconds);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ms to process on Main thread.");
			}
			logInstance.LogInfo(val);
		}

		private static async Task SyncTable(List<Ban> list, DataTable table, string tableName)
		{
			Stopwatch stopwatch = Stopwatch.StartNew();
			if (ValidateSync(list, tableName))
			{
				stopwatch.Stop();
				ManualLogSource logInstance = Plugin.LogInstance;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ValidateSync took ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ms to process for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(tableName);
				}
				logInstance.LogInfo(val);
				stopwatch.Restart();
				await SQLConflict.ResolveOfflines(list);
				stopwatch.Stop();
				ManualLogSource logInstance2 = Plugin.LogInstance;
				val = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ResolveOfflines took ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ms to process for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(tableName);
				}
				logInstance2.LogInfo(val);
				stopwatch.Restart();
				HandleRemovedBans(list, table);
				stopwatch.Stop();
				ManualLogSource logInstance3 = Plugin.LogInstance;
				val = new BepInExInfoLogInterpolatedStringHandler(41, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("HandleRemovedBans took ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ms to process for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(tableName);
				}
				logInstance3.LogInfo(val);
				stopwatch.Restart();
				RemoveExpiredBans(table, tableName);
				stopwatch.Stop();
				ManualLogSource logInstance4 = Plugin.LogInstance;
				val = new BepInExInfoLogInterpolatedStringHandler(41, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RemoveExpiredBans took ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ms to process for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(tableName);
				}
				logInstance4.LogInfo(val);
				stopwatch.Restart();
				SyncMissingBans(list, table);
				stopwatch.Stop();
				ManualLogSource logInstance5 = Plugin.LogInstance;
				val = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SyncMissingBans took ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ms to process for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(tableName);
				}
				logInstance5.LogInfo(val);
			}
		}

		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_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)
			Player val = default(Player);
			if (PlayerService.TryFindBySteam(ban.PlayerID, ref val) && EntityUtil.Read<User>(val.User).IsConnected)
			{
				Core.StartCoroutine(BanCommands.DelayKick(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 (list == null)
			{
				return false;
			}
			if (string.IsNullOrEmpty(tableName))
			{
				return false;
			}
			return true;
		}
	}
	public static class ThreadingUtility
	{
		private static readonly Queue<Action> _mainThreadActions = new Queue<Action>();

		private static readonly object _lockObject = new object();

		private static bool _initialized = false;

		public static void Initialize()
		{
			if (!_initialized)
			{
				Core.StartCoroutine(ProcessMainThreadActions());
				_initialized = true;
				Plugin.LogInstance.LogInfo((object)"Threading Utility initialized");
			}
		}

		private static IEnumerator ProcessMainThreadActions()
		{
			while (true)
			{
				ProcessActions();
				yield return null;
			}
		}

		private static void ProcessActions()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			lock (_lockObject)
			{
				bool flag = default(bool);
				while (_mainThreadActions.Count > 0)
				{
					try
					{
						_mainThreadActions.Dequeue()?.Invoke();
					}
					catch (Exception ex)
					{
						ManualLogSource logInstance = Plugin.LogInstance;
						BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(36, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error executing main thread action: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						logInstance.LogError(val);
					}
				}
			}
		}

		public static void RunOnMainThread(Action action)
		{
			if (action == null)
			{
				return;
			}
			lock (_lockObject)
			{
				_mainThreadActions.Enqueue(action);
			}
		}

		public static Task RunOnBackgroundThread(Action action)
		{
			return Task.Run(action);
		}

		public static Task<T> RunOnBackgroundThread<T>(Func<T> function)
		{
			return Task.Run(function);
		}

		public static void ShutDown()
		{
		}
	}
	public static class TimeUtility
	{
		public static readonly DateTime MinValueUtc = new DateTime(0L, DateTimeKind.Utc);

		public static string FormatRemainder(DateTime date, bool abbrev = false)
		{
			return FormatRemainder(date - DateTime.Now, abbrev);
		}

		public static string FormatRemainder(TimeSpan remainder, bool abbrev = false)
		{
			string text = string.Empty;
			if (remainder.Days > 0)
			{
				text += (abbrev ? $"{remainder.Days}d, " : $"{remainder.Days} {((remainder.Days == 1) ? "day" : "days")}, ");
			}
			if (remainder.Hours > 0)
			{
				text += (abbrev ? $"{remainder.Hours}h, " : $"{remainder.Hours} {((remainder.Hours == 1) ? "hour" : "hours")}, ");
			}
			if (remainder.Minutes > 0)
			{
				text += (abbrev ? $"{remainder.Minutes}m" : $"{remainder.Minutes} {((remainder.Minutes == 1) ? "minute" : "minutes")}");
			}
			if (text.EndsWith(", "))
			{
				text = text.Substring(0, text.Length - 2);
			}
			if (remainder.TotalSeconds < 1.0)
			{
				if (!abbrev)
				{
					return "1 second";
				}
				return "1s";
			}
			if (remainder.TotalSeconds < 60.0)
			{
				if (abbrev)
				{
					return $"{remainder.Seconds}s";
				}
				return $"{remainder.Seconds} {((remainder.Seconds == 1) ? "second" : "seconds")}";
			}
			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; } = -1000;


		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);
			}
			ChatBans = new List<Ban>();
			VoiceBans = new List<Ban>();
			Banned = new List<Ban>();
			Deletes = new List<DeleteLater>();
			SQLBackgroundService.Enqueue(async delegate
			{
				_ = 1;
				try
				{
					Task<List<Ban>> chatBansTask = FileUtility.ReadJsonFromFileAsync<List<Ban>>(ChatBanFile);
					Task<List<Ban>> voiceBansTask = FileUtility.ReadJsonFromFileAsync<List<Ban>>(VoiceBanFile);
					Task<List<Ban>> bannedTask = FileUtility.ReadJsonFromFileAsync<List<Ban>>(BannedFile);
					Task<List<DeleteLater>> deletesTask = FileUtility.ReadJsonFromFileAsync<List<DeleteLater>>(DeleteFile);
					Task<List<MessagePair>> messagesTask = FileUtility.ReadJsonFromFileAsync<List<MessagePair>>(MessageFile);
					if (Settings.Trusted.Value)
					{
						Task<List<ulong>> trustedUsersTask = FileUtility.ReadJsonFromFileAsync<List<ulong>>(TrustedFile);
						Task<List<Trust>> trustCommandsTask = FileUtility.ReadJsonFromFileAsync<List<Trust>>(TrustFile);
						await Task.WhenAll(trustedUsersTask, trustCommandsTask);
						ThreadingUtility.RunOnMainThread(delegate
						{
							TrustedUsers = trustedUsersTask.Result ?? new List<ulong>();
							TrustCommands = trustCommandsTask.Result ?? CreateDefaultTrustCommands();
							if (trustedUsersTask.Result == null)
							{
								FileUtility.WriteJsonToFileAsync(TrustedFile, TrustedUsers);
							}
							if (trustCommandsTask.Result == null)
							{
								FileUtility.WriteJsonToFileAsync(TrustFile, TrustCommands);
							}
						});
					}
					await Task.WhenAll(chatBansTask, voiceBansTask, bannedTask, deletesTask, messagesTask);
					ThreadingUtility.RunOnMainThread(delegate
					{
						ChatBans = chatBansTask.Result ?? new List<Ban>();
						VoiceBans = voiceBansTask.Result ?? new List<Ban>();
						Banned = bannedTask.Result ?? new List<Ban>();
						Deletes = deletesTask.Result ?? new List<DeleteLater>();
						Messages = messagesTask.Result ?? CreateDefaultMessages();
						if (messagesTask.Result == null)
						{
							FileUtility.WriteJsonToFileAsync(MessageFile, Messages);
						}
						if (SQL != null && Settings.UseSQL.Value && SQLlink.Connect())
						{
							StartSQLConnection();
						}
						Core.StartCoroutine(Clean());
					});
				}
				catch (Exception ex2)
				{
					Exception ex3 = ex2;
					Exception ex = ex3;
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0010: Expected O, but got Unknown
						ManualLogSource logInstance = Plugin.LogInstance;
						bool flag = default(bool);
						BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error loading databases: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						logInstance.LogError(val);
					});
				}
			});
		}

		private static List<MessagePair> CreateDefaultMessages()
		{
			return 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", "")
			};
		}

		private static List<Trust> CreateDefaultTrustCommands()
		{
			return new List<Trust>(10)
			{
				new Trust("?banserver {playerName} {reason}", ".ban server {playerName} 30 min {reason}"),
				new Trust("?banchat {playerName} {reason}", ".ban chat {playerName} 30 min {reason}"),
				new Trust("?banvoice {playerName} {reason}", ".ban voice {playerName} 30 min {reason}"),
				new Trust("?mute {playerName} {reason}", ".ban mute {playerName} 30 min {reason}"),
				new Trust("?unbanserver {playerName}", ".unban server {playerName}"),
				new Trust("?unbanchat {playerName}", ".unban chat {playerName}"),
				new Trust("?unbanvoice {playerName}", ".unban voice {playerName}"),
				new Trust("?unmute {playerName}", ".unban mute {playerName}"),
				new Trust("?list {banType} {page}", ".banned list {banType} perma/temp {page}"),
				new Trust("?check {playerName}", ".banned check {playerName}")
			};
		}

		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 void StartSQLConnection()
		{
			SQLBackgroundService.Enqueue(async delegate
			{
				try
				{
					SQLlink.InitializeBanTables();
					await Task.Yield();
					ThreadingUtility.RunOnMainThread(delegate
					{
						SQLUtility.SyncDB();
						Core.StartCoroutine(SyncLoop());
					});
				}
				catch (Exception ex2)
				{
					Exception ex3 = ex2;
					Exception ex = ex3;
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0010: Expected O, but got Unknown
						ManualLogSource logInstance = Plugin.LogInstance;
						bool flag = default(bool);
						BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SQL initialization error: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						logInstance.LogError(val);
					});
				}
			});
		}

		public static void AddBan(Ban ban, List<Ban> list, bool skipSave = false)
		{
			if (list.Exists((Ban x) => x.DatabaseId == ban.DatabaseId) && ban.DatabaseId != -1)
			{
				return;
			}
			string type = string.Empty;
			if (list == ChatBans)
			{
				type = "Chat";
				ChatBans.Add(ban);
			}
			else if (list == VoiceBans)
			{
				type = "Voice";
				VoiceBans.Add(ban);
			}
			else
			{
				type = "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 empty = string.Empty;
			string value = TimeUtility.FormatRemainder(ban.TimeUntil - ban.Issued);
			empty = ((!ban.LocalBan) ? $"A player with ID: {ban.PlayerID} has had their {type} ban synced from SQL. Originally issued by {ban.IssuedBy} with {value} remaining." : $"{ban.PlayerName} with ID: {ban.PlayerID} has been {type} banned. Issued by {ban.IssuedBy} for {value}.");
			Plugin.LogMessage(empty);
			if (SQLUtility.TrySQL() && ban.LocalBan && ban.DatabaseId == -1000)
			{
				SQLBackgroundService.Enqueue(async delegate
				{
					try
					{
						SQLlink.AddBan(ban, list);
						ThreadingUtility.RunOnMainThread(delegate
						{
							//IL_000a: Unknown result type (might be due to invalid IL or missing references)
							//IL_0010: Expected O, but got Unknown
							ManualLogSource logInstance2 = Plugin.LogInstance;
							bool flag2 = default(bool);
							BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(37, 3, ref flag2);
							if (flag2)
							{
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ban.PlayerName);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" with ID: ");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<ulong>(ban.PlayerID);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" has been ");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(type);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" banned with SQL.");
							}
							logInstance2.LogInfo(val2);
						});
					}
					catch (Exception ex2)
					{
						Exception ex3 = ex2;
						Exception ex = ex3;
						ThreadingUtility.RunOnMainThread(delegate
						{
							//IL_000a: Unknown result type (might be due to invalid IL or missing references)
							//IL_0010: Expected O, but got Unknown
							ManualLogSource logInstance = Plugin.LogInstance;
							bool flag = default(bool);
							BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error adding ban to SQL: ");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
							}
							logInstance.LogError(val);
						});
					}
				});
			}
			if (!skipSave)
			{
				SaveDatabases();
			}
		}

		public static void DeleteBan(Ban ban, List<Ban> list)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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)
			string empty = string.Empty;
			if (list == ChatBans)
			{
				empty = "Chat";
				ChatBans.Remove(ban);
				Player val = default(Player);
				if (!Settings.ShadowBan.Value && PlayerService.TryFindBySteam(ban.PlayerID, ref val))
				{
					ChatUtil.SystemSendUser(EntityUtil.Read<User>(val.User), "Your chat ban has been removed.");
				}
			}
			else if (list == VoiceBans)
			{
				empty = "Voice";
				VoiceBans.Remove(ban);
				Player val2 = default(Player);
				if (!Settings.ShadowBan.Value && PlayerService.TryFindBySteam(ban.PlayerID, ref val2))
				{
					ChatUtil.SystemSendUser(EntityUtil.Read<User>(val2.User), "Your voice ban has been removed. Please open your \"Social\" menu and verify that \"Voice Chat\" is set to \"Proximity\".");
				}
			}
			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())
			{
				SQLBackgroundService.Enqueue(async delegate
				{
					try
					{
						SQLlink.DeleteBan(ban, list);
					}
					catch (Exception ex2)
					{
						Exception ex3 = ex2;
						Exception ex = ex3;
						ThreadingUtility.RunOnMainThread(delegate
						{
							//IL_000a: Unknown result type (might be due to invalid IL or missing references)
							//IL_0010: Expected O, but got Unknown
							ManualLogSource logInstance = Plugin.LogInstance;
							bool flag = default(bool);
							BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Error deleting ban from SQL: ");
								((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
							}
							logInstance.LogError(val3);
						});
					}
				});
			}
			else if (SQL != null)
			{
				Deletes.Add(new DeleteLater(ban.DatabaseId, empty + "Bans"));
			}
			SaveDatabases();
		}

		public static void SaveDatabases()
		{
			if (ChatBans.Count > 0 || File.Exists(ChatBanFile))
			{
				FileUtility.WriteJsonToFileAsync(ChatBanFile, ChatBans);
			}
			if (VoiceBans.Count > 0 || File.Exists(VoiceBanFile))
			{
				FileUtility.WriteJsonToFileAsync(VoiceBanFile, VoiceBans);
			}
			if (Banned.Count > 0 || File.Exists(BannedFile))
			{
				FileUtility.WriteJsonToFileAsync(BannedFile, Banned);
			}
			if (Deletes.Count > 0 || File.Exists(DeleteFile))
			{
				FileUtility.WriteJsonToFileAsync(DeleteFile, Deletes);
			}
		}

		private static IEnumerator SyncLoop()
		{
			while (true)
			{
				ThreadingUtility.RunOnMainThread(delegate
				{
					SQLBackgroundService.Enqueue(async delegate
					{
						try
						{
							List<Ban> expiredBans = await ThreadingUtility.RunOnBackgroundThread(() => Banned.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList());
							ThreadingUtility.RunOnMainThread(delegate
							{
								foreach (Ban item in expiredBans)
								{
									DeleteBan(item, Banned);
								}
							});
						}
						catch (Exception ex2)
						{
							Exception ex3 = ex2;
							Exception ex = ex3;
							ThreadingUtility.RunOnMainThread(delegate
							{
								//IL_000a: Unknown result type (might be due to invalid IL or missing references)
								//IL_0010: Expected O, but got Unknown
								ManualLogSource logInstance = Plugin.LogInstance;
								bool flag = default(bool);
								BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(20, 1, ref flag);
								if (flag)
								{
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Ban list fix error: ");
									((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
								}
								logInstance.LogError(val);
							});
						}
					});
				});
				yield return (object)new WaitForSeconds((float)(Settings.SyncInterval.Value * 60 + Random.Range(-10, 20)));
				SQLUtility.SyncDB();
			}
		}

		public static void BanListFix(List<Ban> additional = null)
		{
			Stopwatch stopwatch = Stopwatch.StartNew();
			SQLBackgroundService.Enqueue(async delegate
			{
				try
				{
					List<Ban> expiredBans = await ThreadingUtility.RunOnBackgroundThread(delegate
					{
						List<Ban> list = Banned.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList();
						if (additional != null)
						{
							list = list.Concat(additional).ToList();
						}
						return list;
					});
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_0052: Unknown result type (might be due to invalid IL or missing references)
						//IL_0058: Expected O, but got Unknown
						foreach (Ban item in expiredBans)
						{
							DeleteBan(item, Banned);
						}
						stopwatch.Stop();
						ManualLogSource logInstance2 = Plugin.LogInstance;
						bool flag2 = default(bool);
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(50, 2, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Ban list fix took ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ms to process with ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(expiredBans.Count);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" expired bans");
						}
						logInstance2.LogInfo(val2);
					});
				}
				catch (Exception ex2)
				{
					Exception ex3 = ex2;
					Exception ex = ex3;
					ThreadingUtility.RunOnMainThread(delegate
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0010: Expected O, but got Unknown
						ManualLogSource logInstance = Plugin.LogInstance;
						bool flag = default(bool);
						BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(27, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error during ban list fix: ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						logInstance.LogError(val);
					});
				}
			});
		}

		private static IEnumerator Clean()
		{
			while (true)
			{
				yield return (object)new WaitForSeconds(60f);
				Stopwatch stopwatch = Stopwatch.StartNew();
				SQLBackgroundService.Enqueue(async delegate
				{
					_ = 2;
					try
					{
						List<Ban> bannedToRemove = await ThreadingUtility.RunOnBackgroundThread(() => Banned.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList());
						List<Ban> chatBansToRemove = await ThreadingUtility.RunOnBackgroundThread(() => ChatBans.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList());
						List<Ban> voiceBansToRemove = await ThreadingUtility.RunOnBackgroundThread(() => VoiceBans.Where((Ban ban) => !TimeUtility.IsPermanent(ban.TimeUntil) && ban.TimeUntil < DateTime.UtcNow).ToList());
						ThreadingUtility.RunOnMainThread(delegate
						{
							//IL_0090: Unknown result type (might be due to invalid IL or missing references)
							//IL_0096: Expected O, but got Unknown
							//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
							//IL_0105: Expected O, but got Unknown
							foreach (Ban item in bannedToRemove)
							{
								DeleteBan(item, Banned);
							}
							foreach (Ban item2 in chatBansToRemove)
							{
								DeleteBan(item2, ChatBans);
							}
							bool flag2 = default(bool);
							BepInExInfoLogInterpolatedStringHandler val2;
							foreach (Ban item3 in voiceBansToRemove)
							{
								ManualLogSource logInstance2 = Plugin.LogInstance;
								val2 = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag2);
								if (flag2)
								{
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Removing voice ban on ");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(item3.PlayerName);
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" in Clean Loop");
								}
								logInstance2.LogInfo(val2);
								DeleteBan(item3, VoiceBans);
							}
							stopwatch.Stop();
							ManualLogSource logInstance3 = Plugin.LogInstance;
							val2 = new BepInExInfoLogInterpolatedStringHandler(44, 2, ref flag2);
							if (flag2)
							{
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Ban cleanup took ");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ms to process ");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(bannedToRemove.Count + chatBansToRemove.Count + voiceBansToRemove.Count);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" expired bans");
							}
							logInstance3.LogInfo(val2);
						});
					}
					catch (Exception ex2)
					{
						Exception ex3 = ex2;
						Exception ex = ex3;
						ThreadingUtility.RunOnMainThread(delegate
						{
							//IL_000a: Unknown result type (might be due to invalid IL or missing references)
							//IL_0010: Expected O, but got Unknown
							ManualLogSource logInstance = Plugin.LogInstance;
							bool flag = default(bool);
							BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error during ban cleanup: ");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
							}
							logInstance.LogError(val);
						});
					}
				});
			}
		}
	}
	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)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			Stopwatch stopwatch = Stopwatch.StartNew();
			Dictionary<string, object> dictionary = new Dictionary<string, object> { ["Id"] = id };
			Database.SQL.Delete(tableName, dictionary);
			stopwatch.Stop();
			ManualLogSource logInstance = Plugin.LogInstance;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Delete took ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(stopwatch.ElapsedMilliseconds);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ms to process");
			}
			logInstance.LogInfo(val);
		}

		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_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			_ = __instance.__query_661171423_0;
			EntityQuery _query_661171423_ = __instance.__query_661171423_0;
			NativeArray<Entity> val = ((EntityQuery)(ref _query_661171423_)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val.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))
					{
						continue;
					}
					Ban ban = Database.ChatBans.First((Ban x) => x.PlayerID == userData.PlatformId);
					if (DateTime.UtcNow > ban.TimeUntil && !TimeUtility.IsPermanent(ban.TimeUntil))
					{
						Database.DeleteBan(ban, Database.ChatBans);
						continue;
					}
					if (!Settings.ShadowBan.Value)
					{
						string text = TimeUtility.FormatRemainder(ban.TimeUntil.ToLocalTime(), abbrev: true);
						ChatUtil.SystemSendUser(userData, "You are banned from chat (" + text + " remaining).");
					}
					entityManager = Core.EntityManager;
					((EntityManager)(ref entityManager)).DestroyEntity(current);
				}
			}
			val.Dispose();
			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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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);
				ManualLogSource logInstance = Plugin.LogInstance;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Removing voice ban on ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<FixedString64Bytes>(user.CharacterName);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" in VivoxPatch");
				}
				logInstance.LogInfo(val3);
				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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Player val = default(Player);
			if (!PlayerService.TryFindByName(name, ref val))
			{
				ctx.Reply("Could not find player with the name " + name + ".");
			}
			else if (EntityUtil.Read<User>(val.User) == ctx.User)
			{
				ctx.Reply("You cannot kick yourself.");
			}
			else
			{
				Kick(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)
			Player player = default(Player);
			if (!PlayerService.TryFindByName(name, ref player))
			{
				ChatUtil.SystemSendUser(ctx, "Could not find player with the name " + name + ".");
				return (false, null);
			}
			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) ? "permanently." : ("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_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_002d: Unknown result type (might be due to invalid IL or missing references)
			Player val = default(Player);
			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>(val.User);
			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_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_002d: Unknown result type (might be due to invalid IL or missing references)
			Player val = default(Player);
			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>(val.User);
			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_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_002d: Unknown result type (might be due to invalid IL or missing references)
			Player val = default(Player);
			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>(val.User);
			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 || num == -1)
					{
						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