Decompiled source of CustomKill v1.1.51

BepInEx/plugins/CustomKill.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
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.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CustomKill.Combat;
using CustomKill.Config;
using CustomKill.Database;
using CustomKill.Services;
using CustomKill.Utils;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LiteDB;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Gameplay.Systems;
using ProjectM.Network;
using Stunlock.Core;
using Stunlock.Network;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
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("BeardMagics, Morphine, OA: Irozer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Custom Killfeed for Blood Wars server - forked from Sunrise")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CustomKill")]
[assembly: AssemblyTitle("CustomKill")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CustomKill
{
	public static class Core
	{
		public static World Server { get; } = GetWorld("Server") ?? throw new Exception("Server World not found. Mod installation incorrect or missing resources.");


		public static EntityManager EntityManager => Server.EntityManager;

		public static PrefabCollectionSystem PrefabCollection { get; } = Server.GetExistingSystemManaged<PrefabCollectionSystem>();


		private static World GetWorld(string name)
		{
			Enumerator<World> enumerator = World.s_AllWorlds.GetEnumerator();
			while (enumerator.MoveNext())
			{
				World current = enumerator.Current;
				if (current.Name == name)
				{
					return current;
				}
			}
			return null;
		}

		public static void LogException(Exception e, [CallerMemberName] string caller = null)
		{
			Debug.LogError(Object.op_Implicit($"[CustomKill] Exception in {caller}: {e.Message}\n{e.StackTrace}"));
		}
	}
	public static class KillfeedSettings
	{
		public static ConfigEntry<bool> RestrictDamageToAdmin;

		public static ConfigEntry<bool> RestrictKillsToAdmin;

		public static ConfigEntry<bool> RestrictDeathsToAdmin;

		public static ConfigEntry<bool> RestrictAssistsToAdmin;

		public static ConfigEntry<bool> RestrictMaxStreakToAdmin;

		public static ConfigEntry<int> LevelTrackingMode;

		internal static ConfigEntry<int> ClanTrackingDays;

		public static ConfigEntry<string> WebhookURL;

		public static ConfigEntry<string> StatsWebhookURL;

		public static ConfigEntry<string> KillerNameColor;

		public static ConfigEntry<string> VictimNameColor;

		public static ConfigEntry<string> ClanTagColor;

		public static ConfigEntry<string> AllowedLevelColor;

		public static ConfigEntry<string> ForbiddenLevelColor;

		public static ConfigEntry<string> KillMessageFormat;

		public static ConfigEntry<int> MaxLevelGapNormal;

		public static ConfigEntry<int> MaxLevelGapHigh;

		public static void Init(ConfigFile config)
		{
			LevelTrackingMode = config.Bind<int>("Killfeed", "LevelTrackingMode", 1, "1 = Highest equipped gearscore, 2 = Current equipped gearscore on kill");
		}

		public static void Init(string configPath)
		{
			//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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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_00f5: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Expected O, but got Unknown
			ConfigFile val = new ConfigFile(Paths.ConfigPath + "\\CustomKill.cfg", true);
			ClanTrackingDays = val.Bind<int>("Clan Member Stats", "ClanMemberMinDaysForStats", 7, "Minimum days a clan member must be in a clan to be counted in .top clan damage/kills statistics.");
			WebhookURL = val.Bind<string>("Discord", "WebhookURL", "", "Discord Webhook URL for broadcasting kill messages.");
			StatsWebhookURL = val.Bind<string>("Discord", "StatsWebhookURL", "", "Discord Webhook URL for broadcasting player stats.");
			LevelTrackingMode = val.Bind<int>("Level Service Mode", "LevelTrackingMode", 1, "Level tracking mode: 1 = Track by max logged gearscore , 2 = Track using live gearscore data (Unity ECS Snapshot at time of kill)");
			RestrictDamageToAdmin = val.Bind<bool>("Top Command Access", "RestrictDamageToAdmin", false, "Restrict access to the 'damage' leaderboard to admins only.");
			RestrictKillsToAdmin = val.Bind<bool>("Top Command Access", "RestrictKillsToAdmin", false, "Restrict access to the 'kills' leaderboard to admins only.");
			RestrictDeathsToAdmin = val.Bind<bool>("Top Command Access", "RestrictDeathsToAdmin", true, "Restrict access to the 'deaths' leaderboard to admins only.");
			RestrictAssistsToAdmin = val.Bind<bool>("Top Command Access", "RestrictAssistsToAdmin", false, "Restrict access to the 'assists' leaderboard to admins only.");
			RestrictMaxStreakToAdmin = val.Bind<bool>("Top Command Access", "RestrictMaxStreakToAdmin", false, "Restrict access to the 'maxstreak' leaderboard to admins only.");
			KillerNameColor = val.Bind<string>("Killfeed Colors", "KillerNameColor", "#ffffff", "Color of the killer's name.");
			VictimNameColor = val.Bind<string>("Killfeed Colors", "VictimNameColor", "#ffffff", "Color of the victim's name.");
			ClanTagColor = val.Bind<string>("Killfeed Colors", "ClanTagColor", "#888888", "Color of the clan tags.");
			AllowedLevelColor = val.Bind<string>("Killfeed Colors", "AllowedLevelColor", "#55ff55", "Color for allowed kills (fair level difference).");
			ForbiddenLevelColor = val.Bind<string>("Killfeed Colors", "ForbiddenLevelColor", "#ff5555", "Color for forbidden kills (too high level difference).");
			KillMessageFormat = val.Bind<string>("Kill Message Format", "KillMessageFormat", "<color={ClanTagColor}>[{KillerClan}]</color><color={KillerNameColor}>{Killer}</color>[<color={LevelColor}>{KillerLevel}</color>] killed <color={ClanTagColor}>[{VictimClan}]</color><color={VictimNameColor}>{Victim}</color>[<color={LevelColor}>{VictimLevel}</color>]", "Killfeed message format. Available placeholders: {Killer}, {Victim}, {KillerClan}, {VictimClan}, {KillerLevel}, {VictimLevel}, {LevelColor}, {KillerNameColor}, {VictimNameColor}, {ClanTagColor}");
			MaxLevelGapNormal = val.Bind<int>("Level Restrictions", "MaxLevelGapNormal", 15, "Maximum level difference allowed for fair kills when killer is below level 91.");
			MaxLevelGapHigh = val.Bind<int>("Level Restrictions", "MaxLevelGapHigh", 21, "Maximum level difference allowed for fair kills when killer is level 91 or higher.");
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(52, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[CustomKill] Loaded Discord WebhookURL from config: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(WebhookURL.Value);
			}
			logger.LogInfo(val2);
		}
	}
	[BepInPlugin("com.beardmagics.customkill", "CustomKill", "1.1.51")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		private Harmony _harmony;

		public static ManualLogSource Logger;

		public static Plugin Instance { get; private set; }

		public override void Load()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			Instance = this;
			Logger = ((BasePlugin)this).Log;
			CommandRegistry.RegisterAll(Assembly.GetExecutingAssembly());
			ColorSettings.Init(Paths.ConfigPath);
			PvPStatsService.Init();
			KillfeedSettings.Init(Paths.ConfigPath);
			Logger.LogInfo((object)"CustomKill config initialized.");
			Logger.LogInfo((object)"CustomKill v1.1.51 is loading...");
			_harmony = new Harmony("com.beardmagics.customkill");
			_harmony.PatchAll();
			Logger.LogInfo((object)"CustomKill fully loaded.");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.beardmagics.customkill";

		public const string PLUGIN_NAME = "CustomKill";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace CustomKill.Utils
{
	public static class DiscordBroadcaster
	{
		private static readonly HttpClient client = new HttpClient();

		public static async void SendKillMessage(string message)
		{
			string text = KillfeedSettings.WebhookURL?.Value;
			if (string.IsNullOrWhiteSpace(text))
			{
				Plugin.Logger.LogWarning((object)"[CustomKill] Webhook URL is null or empty. Skipping Discord message.");
			}
			else
			{
				await PostToWebhook(text, message, "[CustomKill] Kill Message");
			}
		}

		public static async void PostTopStatsToDiscord(ChatCommandContext ctx)
		{
			Dictionary<string, PlayerStats> stats = PvPStatsService.GetAllStats();
			List<PlayerStats> list = (from s in stats.Values
				where s.Kills.GetValueOrDefault() > 0
				orderby s.Kills.GetValueOrDefault() descending
				select s).Take(10).ToList();
			var list2 = (from c in PvPStatsService.GetAllClans().Select(delegate(KeyValuePair<string, List<string>> clan)
				{
					PlayerStats value;
					List<PlayerStats> source = (from name in clan.Value
						select (!stats.TryGetValue(name, out value)) ? null : value into s
						where s != null
						select s).ToList();
					return new
					{
						ClanName = clan.Key,
						TotalKills = source.Sum((PlayerStats s) => s.Kills.GetValueOrDefault()),
						TotalDeaths = source.Sum((PlayerStats s) => s.Deaths.GetValueOrDefault()),
						TotalAssists = source.Sum((PlayerStats s) => s.Assists.GetValueOrDefault()),
						TotalDamage = source.Sum((PlayerStats s) => s.Damage.GetValueOrDefault())
					};
				})
				orderby c.TotalKills descending
				select c).Take(5).ToList();
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("**\ud83d\udcca Top 10 Players**");
			for (int i = 0; i < list.Count; i++)
			{
				PlayerStats playerStats = list[i];
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(31, 6, stringBuilder2);
				handler.AppendFormatted(i + 1);
				handler.AppendLiteral(". **");
				handler.AppendFormatted(playerStats.Name);
				handler.AppendLiteral("** — \ud83d\udd25 ");
				handler.AppendFormatted(playerStats.Damage);
				handler.AppendLiteral(" / \ud83d\udde1\ufe0f ");
				handler.AppendFormatted(playerStats.Kills);
				handler.AppendLiteral(" / \ud83d\udc80 ");
				handler.AppendFormatted(playerStats.Deaths);
				handler.AppendLiteral(" / \ud83e\udd1d ");
				handler.AppendFormatted(playerStats.Assists);
				stringBuilder3.AppendLine(ref handler);
			}
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("**\ud83c\udff0 Top 5 Clans**");
			for (int j = 0; j < list2.Count; j++)
			{
				var anon = list2[j];
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(31, 6, stringBuilder2);
				handler.AppendFormatted(j + 1);
				handler.AppendLiteral(". **");
				handler.AppendFormatted(anon.ClanName);
				handler.AppendLiteral("** — \ud83d\udd25 ");
				handler.AppendFormatted(anon.TotalDamage);
				handler.AppendLiteral(" / \ud83d\udde1\ufe0f ");
				handler.AppendFormatted(anon.TotalKills);
				handler.AppendLiteral(" / \ud83d\udc80 ");
				handler.AppendFormatted(anon.TotalDeaths);
				handler.AppendLiteral(" / \ud83e\udd1d ");
				handler.AppendFormatted(anon.TotalAssists);
				stringBuilder4.AppendLine(ref handler);
			}
			string text = KillfeedSettings.StatsWebhookURL?.Value;
			if (string.IsNullOrWhiteSpace(text))
			{
				Plugin.Logger.LogWarning((object)"[CustomKill] Stats webhook URL is null or empty. Skipping post.");
				ctx.Reply("⚠\ufe0f Stats webhook URL not configured.");
			}
			else
			{
				await PostToWebhook(text, stringBuilder.ToString(), "[CustomKill] Stats Post");
				ctx.Reply("[ OK ] Stats have been posted to Discord.");
			}
		}

		private static async Task PostToWebhook(string webhookUrl, string message, string logContext)
		{
			StringContent content = new StringContent(JsonSerializer.Serialize(new
			{
				content = message
			}), Encoding.UTF8, "application/json");
			bool flag = default(bool);
			try
			{
				HttpResponseMessage httpResponseMessage = await client.PostAsync(webhookUrl, content);
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(19, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(logContext);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" webhook response: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<HttpStatusCode>(httpResponseMessage.StatusCode);
				}
				logger.LogInfo(val);
				if (!httpResponseMessage.IsSuccessStatusCode)
				{
					ManualLogSource logger2 = Plugin.Logger;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(9, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(logContext);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" failed: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<HttpStatusCode>(httpResponseMessage.StatusCode);
					}
					logger2.LogWarning(val2);
				}
			}
			catch (HttpRequestException ex)
			{
				ManualLogSource logger3 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(16, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(logContext);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" webhook error: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				logger3.LogError(val3);
			}
		}
	}
	public static class KillCache
	{
		private static readonly Dictionary<Entity, Entity> DownerMap = new Dictionary<Entity, Entity>();

		public static void SetDowner(Entity victim, Entity downer)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			DownerMap[victim] = downer;
		}

		public static Entity GetDowner(Entity victim)
		{
			//IL_0005: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!DownerMap.TryGetValue(victim, out var value))
			{
				return Entity.Null;
			}
			return value;
		}

		public static void Clear(Entity victim)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			DownerMap.Remove(victim);
		}
	}
	public static class VWorld
	{
		public static World Server
		{
			get
			{
				Enumerator<World> enumerator = World.All.GetEnumerator();
				while (enumerator.MoveNext())
				{
					World current = enumerator.Current;
					if (current.Name == "Server")
					{
						return current;
					}
				}
				return null;
			}
		}

		public static EntityManager ServerEntityManager => Server.EntityManager;
	}
}
namespace CustomKill.Systems
{
	public class AssistTrackerSystem : SystemBase
	{
		public override void OnCreate()
		{
			((ComponentSystemBase)this).OnCreate();
			StatChangeHook.OnStatChanged += HandleStatChanged;
		}

		public override void OnDestroy()
		{
			StatChangeHook.OnStatChanged -= HandleStatChanged;
			((ComponentSystemBase)this).OnDestroy();
		}

		public override void OnUpdate()
		{
		}

		private void HandleStatChanged(StatChangeEvent ev)
		{
		}
	}
}
namespace CustomKill.Services
{
	public class LevelService
	{
		public static LevelService Instance = new LevelService();

		public int GetMaxLevel(string playerName)
		{
			return (DatabaseWrapper.Instance.Collection.FindById(BsonValue.op_Implicit(playerName))?.MaxGearScore).GetValueOrDefault();
		}

		public void UpdatePlayerLevel(Entity userEntity)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0025: 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_002d: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = Core.Server.EntityManager;
			if (!((EntityManager)(ref entityManager)).HasComponent<User>(userEntity))
			{
				return;
			}
			User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
			Entity entity = componentData.LocalCharacter._Entity;
			if (((EntityManager)(ref entityManager)).HasComponent<Equipment>(entity))
			{
				Equipment componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<Equipment>(entity);
				int num = Mathf.RoundToInt(ModifiableFloat.op_Implicit(componentData2.ArmorLevel) + ModifiableFloat.op_Implicit(componentData2.SpellLevel) + ModifiableFloat.op_Implicit(componentData2.WeaponLevel));
				string text = ((object)(FixedString64Bytes)(ref componentData.CharacterName)).ToString();
				ILiteCollection<PlayerStats> collection = DatabaseWrapper.Instance.Collection;
				PlayerStats playerStats = collection.FindById(BsonValue.op_Implicit(text));
				if (playerStats == null)
				{
					playerStats = new PlayerStats
					{
						Name = text,
						SteamID = componentData.PlatformId,
						MaxGearScore = num
					};
					collection.Insert(playerStats);
					Debug.Log(Object.op_Implicit($"[CustomKill] Inserted new PlayerStats for {text} with MaxGearScore: {num}"));
				}
				else if (num > playerStats.MaxGearScore.GetValueOrDefault())
				{
					playerStats.MaxGearScore = num;
					collection.Update(playerStats);
					Debug.Log(Object.op_Implicit($"[CustomKill] Updated MaxGearScore for {text}: {num}"));
				}
			}
		}
	}
}
namespace CustomKill.Config
{
	public static class ColorSettings
	{
		public static ConfigEntry<string> Top_TitleColor;

		public static ConfigEntry<string> Top_DamageColor;

		public static ConfigEntry<string> Top_KillsColor;

		public static ConfigEntry<string> Top_DeathsColor;

		public static ConfigEntry<string> Top_AssistsColor;

		public static ConfigEntry<string> Top_MaxStreakColor;

		public static ConfigEntry<string> Top_PlayerNameColor;

		public static ConfigEntry<string> Top_ClanTitleColor;

		public static ConfigEntry<string> Top_ClanNameColor;

		public static ConfigEntry<string> Top_ClanKillsColor;

		public static ConfigEntry<string> Top_ClanDamageColor;

		public static ConfigEntry<string> Stats_TitleColor;

		public static ConfigEntry<string> Stats_DamageColor;

		public static ConfigEntry<string> Stats_KillsColor;

		public static ConfigEntry<string> Stats_DeathsColor;

		public static ConfigEntry<string> Stats_AssistsColor;

		public static ConfigEntry<string> Stats_KillStreakColor;

		public static ConfigEntry<string> Stats_MaxStreakColor;

		public static ConfigEntry<string> Stats_PlayerNameColor;

		public static void Init(string configPath)
		{
			//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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: 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_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			ConfigFile val = new ConfigFile(Path.Combine(configPath, "CustomKill_top.cfg"), true);
			Top_TitleColor = val.Bind<string>("Top 5 Colors", "TitleColor", "#ffaa00", "Color for the title in .top");
			Top_DamageColor = val.Bind<string>("Top 5 Colors", "DamageColor", "#ffffff", "Color for the damage in .top");
			Top_KillsColor = val.Bind<string>("Top 5 Colors", "KillsColor", "#55ff55", "Color for kills shown");
			Top_DeathsColor = val.Bind<string>("Top 5 Colors", "DeathsColor", "#ff5555", "Color for deaths shown");
			Top_AssistsColor = val.Bind<string>("Top 5 Colors", "AssistsColor", "#aaaaaa", "Color for assists shown");
			Top_MaxStreakColor = val.Bind<string>("Top 5 Colors", "MaxStreakColor", "#55aaff", "Color for max streak shown");
			Top_PlayerNameColor = val.Bind<string>("Top 5 Colors", "PlayerNameColor", "#ffffff", "Color for player names");
			Top_ClanTitleColor = val.Bind<string>("Clan Colors", "ClanTitleColor", "#ffaa00", "Color for the clan title in .top");
			Top_ClanNameColor = val.Bind<string>("Clan Colors", "ClanNameColor", "#ffaa00", "Color for the clan name in .top");
			Top_ClanKillsColor = val.Bind<string>("Clan Colors", "ClanKillsColor", "#55ff55", "Color for clan kills shown");
			Top_ClanDamageColor = val.Bind<string>("Clan Colors", "ClanDamageColor", "#ffffff", "Color for clan damage shown");
			ConfigFile val2 = new ConfigFile(Path.Combine(configPath, "CustomKill_stats.cfg"), true);
			Stats_TitleColor = val2.Bind<string>("Stats Colors", "TitleColor", "#34abeb", "Color for the title in .stats");
			Stats_DamageColor = val2.Bind<string>("Stats Colors", "DamageColor", "#EB621F", "Color for the damage in .stats");
			Stats_KillsColor = val2.Bind<string>("Stats Colors", "KillsColor", "#69ff55", "Color for kills shown");
			Stats_DeathsColor = val2.Bind<string>("Stats Colors", "DeathsColor", "#e34d4d", "Color for deaths shown");
			Stats_AssistsColor = val2.Bind<string>("Stats Colors", "AssistsColor", "#63f5ff", "Color for assists shown");
			Stats_KillStreakColor = val2.Bind<string>("Stats Colors", "KillStreakColor", "#e84848", "Color for current kill streak");
			Stats_MaxStreakColor = val2.Bind<string>("Stats Colors", "MaxStreakColor", "#55aaff", "Color for max streak");
			Stats_PlayerNameColor = val2.Bind<string>("Stats Colors", "PlayerNameColor", "#9428fa", "Color for player names");
		}
	}
}
namespace CustomKill.Patches
{
	[HarmonyPatch(typeof(DeathEventListenerSystem), "OnUpdate")]
	public static class KillfeedPatch
	{
		public static void Postfix(DeathEventListenerSystem __instance)
		{
			//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_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_0024: 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)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = Core.Server.EntityManager;
			EntityQuery val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<DeathEvent>() });
			NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val2.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				if (!((EntityManager)(ref entityManager)).HasComponent<DeathEvent>(current))
				{
					continue;
				}
				DeathEvent componentData = ((EntityManager)(ref entityManager)).GetComponentData<DeathEvent>(current);
				Entity died = componentData.Died;
				Entity downer = KillCache.GetDowner(died);
				Entity val3 = ((downer != Entity.Null) ? downer : componentData.Killer);
				KillCache.Clear(died);
				if (!((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(died) || !((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(val3))
				{
					continue;
				}
				Entity userEntity = ((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(died).UserEntity;
				Entity userEntity2 = ((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(val3).UserEntity;
				if (!((EntityManager)(ref entityManager)).HasComponent<User>(userEntity) || !((EntityManager)(ref entityManager)).HasComponent<User>(userEntity2))
				{
					continue;
				}
				User componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
				User componentData3 = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity2);
				string text = ((object)(FixedString64Bytes)(ref componentData2.CharacterName)).ToString();
				string text2 = ((object)(FixedString64Bytes)(ref componentData3.CharacterName)).ToString();
				if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2) || text == text2)
				{
					continue;
				}
				LevelService.Instance.UpdatePlayerLevel(userEntity2);
				LevelService.Instance.UpdatePlayerLevel(userEntity);
				PvPStatsService.RegisterPvPStats(text2, componentData3.PlatformId, isKill: true, isDeath: false, isAssist: false);
				PvPStatsService.RegisterPvPStats(text, componentData2.PlatformId, isKill: false, isDeath: true, isAssist: false);
				int num;
				int num2;
				if (KillfeedSettings.LevelTrackingMode.Value == 1)
				{
					num = LevelService.Instance.GetMaxLevel(text2);
					num2 = LevelService.Instance.GetMaxLevel(text);
				}
				else
				{
					num = GetLiveGearLevel(entityManager, userEntity2);
					num2 = GetLiveGearLevel(entityManager, userEntity);
				}
				string text3 = TruncateClan(GetClanName(entityManager, componentData3));
				string newValue = TruncateClan(GetClanName(entityManager, componentData2));
				string newValue2 = (IsKillAllowed(num, num2) ? KillfeedSettings.AllowedLevelColor.Value : KillfeedSettings.ForbiddenLevelColor.Value);
				string text4 = KillfeedSettings.KillMessageFormat.Value.Replace("{Killer}", text2).Replace("{Victim}", text).Replace("{KillerClan}", text3)
					.Replace("{VictimClan}", newValue)
					.Replace("{KillerLevel}", num.ToString())
					.Replace("{VictimLevel}", num2.ToString())
					.Replace("{LevelColor}", newValue2)
					.Replace("{KillerNameColor}", KillfeedSettings.KillerNameColor.Value)
					.Replace("{VictimNameColor}", KillfeedSettings.VictimNameColor.Value)
					.Replace("{ClanTagColor}", KillfeedSettings.ClanTagColor.Value);
				ulong platformId = componentData2.PlatformId;
				ulong killerSteamId = componentData3.PlatformId;
				List<KeyValuePair<ulong, (string, int)>> list = (from x in PlayerHitStore.GetRecentAttackersWithLvl(platformId)
					where x.Key != killerSteamId
					select x).ToList();
				string text5 = $"⚔\ufe0f [{text3}] **{text2}** ({num}) killed **{text}** ({num2})";
				if (list.Count > 0)
				{
					IEnumerable<string> values = list.Select<KeyValuePair<ulong, (string, int)>, string>((KeyValuePair<ulong, (string Name, int Level)> e) => $"*{e.Value.Name}* ({e.Value.Level})");
					text5 = text5 + "\n-- Assisters: " + string.Join(", ", values);
					IEnumerable<string> values2 = list.Select<KeyValuePair<ulong, (string, int)>, string>((KeyValuePair<ulong, (string Name, int Level)> e) => $"<color={ColorSettings.Stats_AssistsColor.Value}>{e.Value.Name}</color> ({e.Value.Level})");
					text4 = text4 + "\n<color=#FFFFFF>[Assist(s): " + string.Join(", ", values2) + "]</color>";
					foreach (KeyValuePair<ulong, (string, int)> item in list)
					{
						PvPStatsService.RegisterPvPStats(item.Value.Item1, item.Key, isKill: false, isDeath: false, isAssist: true);
					}
				}
				FixedString512Bytes val4 = FixedString512Bytes.op_Implicit(text4);
				ServerChatUtils.SendSystemMessageToAllClients(entityManager, ref val4);
				DiscordBroadcaster.SendKillMessage(text5);
			}
			val2.Dispose();
		}

		private static string GetClanName(EntityManager em, User user)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_001b: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			Entity entity = user.ClanEntity._Entity;
			if (!(entity != Entity.Null) || !((EntityManager)(ref em)).HasComponent<ClanTeam>(entity))
			{
				return "-";
			}
			ClanTeam componentData = ((EntityManager)(ref em)).GetComponentData<ClanTeam>(entity);
			return ((object)(FixedString64Bytes)(ref componentData.Name)).ToString();
		}

		private static string TruncateClan(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				if (name.Length > 3)
				{
					return name.Substring(0, 3).ToUpper();
				}
				return name.ToUpper();
			}
			return "---";
		}

		private static bool IsKillAllowed(int killerLevel, int victimLevel)
		{
			int num = killerLevel - victimLevel;
			if (killerLevel < 91)
			{
				return num <= KillfeedSettings.MaxLevelGapNormal.Value;
			}
			return num <= KillfeedSettings.MaxLevelGapHigh.Value;
		}

		private static int GetLiveGearLevel(EntityManager entityManager, Entity userEntity)
		{
			//IL_0002: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0021: 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)
			//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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			if (!((EntityManager)(ref entityManager)).HasComponent<User>(userEntity))
			{
				return 0;
			}
			Entity entity = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity).LocalCharacter._Entity;
			if (!((EntityManager)(ref entityManager)).HasComponent<Equipment>(entity))
			{
				return 0;
			}
			Equipment componentData = ((EntityManager)(ref entityManager)).GetComponentData<Equipment>(entity);
			return Mathf.RoundToInt(ModifiableFloat.op_Implicit(componentData.ArmorLevel) + ModifiableFloat.op_Implicit(componentData.SpellLevel) + ModifiableFloat.op_Implicit(componentData.WeaponLevel));
		}
	}
	[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUserConnected")]
	public static class PlayerConnectPatch
	{
		public static void Postfix(ServerBootstrapSystem __instance, NetConnectionId netConnectionId)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
				int num = default(int);
				if (!__instance._NetEndPointToApprovedUserIndex.TryGetValue(netConnectionId, ref num))
				{
					return;
				}
				Il2CppReferenceArray<ServerClient> approvedUsersLookup = __instance._ApprovedUsersLookup;
				if (num < 0 || num >= ((Il2CppArrayBase<ServerClient>)(object)approvedUsersLookup).Length)
				{
					return;
				}
				Entity userEntity = ((Il2CppArrayBase<ServerClient>)(object)approvedUsersLookup)[num].UserEntity;
				if (((EntityManager)(ref entityManager)).HasComponent<User>(userEntity))
				{
					User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
					string text = ((object)(FixedString64Bytes)(ref componentData.CharacterName)).ToString();
					if (!string.IsNullOrWhiteSpace(text))
					{
						LevelService.Instance.UpdatePlayerLevel(userEntity);
						Debug.Log(Object.op_Implicit("[CustomKill] " + text + " connected. Level updated."));
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogError(Object.op_Implicit("[CustomKill] Error during OnUserConnected: " + ex.Message + "\n" + ex.StackTrace));
			}
		}
	}
	[HarmonyPatch(typeof(Destroy_TravelBuffSystem), "OnUpdate")]
	public class PlayerCreationPatch
	{
		public static void Postfix(Destroy_TravelBuffSystem __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0034: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
			EntityQuery _query_615927226_ = __instance.__query_615927226_0;
			NativeArray<Entity> val = ((EntityQuery)(ref _query_615927226_)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				PrefabGUID componentData = ((EntityManager)(ref entityManager)).GetComponentData<PrefabGUID>(current);
				if (((PrefabGUID)(ref componentData)).GuidHash != 722466953)
				{
					continue;
				}
				Entity owner = ((EntityManager)(ref entityManager)).GetComponentData<EntityOwner>(current).Owner;
				if (!((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(owner))
				{
					continue;
				}
				Entity userEntity = ((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(owner).UserEntity;
				if (((EntityManager)(ref entityManager)).HasComponent<User>(userEntity))
				{
					User componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
					string text = ((object)(FixedString64Bytes)(ref componentData2.CharacterName)).ToString();
					if (!string.IsNullOrWhiteSpace(text))
					{
						Debug.Log(Object.op_Implicit("[CustomKill] New player detected: " + text + "."));
					}
				}
			}
			val.Dispose();
		}
	}
	[HarmonyPatch(typeof(VampireDownedServerEventSystem), "OnUpdate")]
	public static class VampireDownedPatch
	{
		public static void Prefix(VampireDownedServerEventSystem __instance)
		{
			//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_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_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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0039: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = Core.Server.EntityManager;
			EntityQuery _query_1174204813_ = __instance.__query_1174204813_0;
			NativeArray<Entity> val = ((EntityQuery)(ref _query_1174204813_)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val.GetEnumerator();
			Entity val2 = default(Entity);
			Entity val3 = default(Entity);
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				if (VampireDownedServerEventSystem.TryFindRootOwner(current, 1, entityManager, ref val2) && VampireDownedServerEventSystem.TryFindRootOwner(((EntityManager)(ref entityManager)).GetComponentData<VampireDownedBuff>(current).Source, 1, entityManager, ref val3) && ((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(val2) && ((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(val3))
				{
					KillCache.SetDowner(val2, val3);
					User val4 = val3.Read<PlayerCharacter>().UserEntity.Read<User>();
					User val5 = val2.Read<PlayerCharacter>().UserEntity.Read<User>();
					PlayerHitStore.AddHit(val4.PlatformId, ((object)(FixedString64Bytes)(ref val4.CharacterName)).ToString(), LevelService.Instance.GetMaxLevel(((object)(FixedString64Bytes)(ref val4.CharacterName)).ToString()), val5.PlatformId, ((object)(FixedString64Bytes)(ref val5.CharacterName)).ToString(), LevelService.Instance.GetMaxLevel(((object)(FixedString64Bytes)(ref val5.CharacterName)).ToString()), -1, 1);
				}
			}
			val.Dispose();
		}
	}
}
namespace CustomKill.Database
{
	public class ClanMemberRecord
	{
		public string Id { get; set; }

		public ulong SteamID { get; set; }

		public string ClanName { get; set; }

		public DateTime JoinedAt { get; set; }
	}
	public sealed class DatabaseWrapper : IDisposable
	{
		private static DatabaseWrapper _instance;

		private readonly LiteDatabase _database;

		public static DatabaseWrapper Instance => _instance ?? (_instance = new DatabaseWrapper());

		public ILiteCollection<PlayerStats> Collection { get; }

		public ILiteCollection<ClanMemberRecord> ClanMembersCollection => _database.GetCollection<ClanMemberRecord>("clan_members", (BsonAutoId)10);

		private DatabaseWrapper()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			string text = Path.Combine(Paths.ConfigPath, "CustomKillDB");
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
			}
			string text2 = Path.Combine(text, "PlayerStats.db");
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(28, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[CustomKill] Database path: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
			}
			logger.LogInfo(val);
			_database = new LiteDatabase("Filename=" + text2 + "; Connection=shared", (BsonMapper)null);
			Collection = _database.GetCollection<PlayerStats>("player_stats", (BsonAutoId)10);
			Collection.EnsureIndex<string>((Expression<Func<PlayerStats, string>>)((PlayerStats x) => x.Name), false);
			Collection.EnsureIndex<ulong>((Expression<Func<PlayerStats, ulong>>)((PlayerStats x) => x.SteamID), false);
			ClanMembersCollection.EnsureIndex<string>((Expression<Func<ClanMemberRecord, string>>)((ClanMemberRecord x) => x.Id), false);
			ClanMembersCollection.EnsureIndex<DateTime>((Expression<Func<ClanMemberRecord, DateTime>>)((ClanMemberRecord x) => x.JoinedAt), false);
		}

		public void Dispose()
		{
			LiteDatabase database = _database;
			if (database != null)
			{
				database.Dispose();
			}
		}
	}
	public class PlayerStats
	{
		[BsonId]
		public string Name { get; set; }

		public ulong SteamID { get; set; }

		public DateTime CreatedAt { get; set; } = DateTime.UtcNow;


		public int? Kills { get; set; } = 0;


		public int? Damage { get; set; } = 0;


		public int? DamageTaken { get; set; } = 0;


		public int? Deaths { get; set; } = 0;


		public int? Assists { get; set; } = 0;


		public int? MaxStreak { get; set; } = 0;


		public int? KillStreak { get; set; } = 0;


		public int? MaxGearScore { get; set; } = 0;

	}
	public static class PvPStatsService
	{
		public static void RegisterPvPStats(string name, ulong steamID, bool isKill, bool isDeath, bool isAssist)
		{
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				ILiteCollection<PlayerStats> collection = DatabaseWrapper.Instance.Collection;
				PlayerStats playerStats = collection.FindById(BsonValue.op_Implicit(name));
				if (playerStats == null || (!playerStats.Kills.HasValue && !playerStats.Deaths.HasValue && !playerStats.Assists.HasValue && !playerStats.MaxStreak.HasValue && !playerStats.KillStreak.HasValue))
				{
					playerStats = new PlayerStats
					{
						Name = name,
						SteamID = steamID,
						Kills = 0,
						Deaths = 0,
						Assists = 0,
						MaxStreak = 0,
						KillStreak = 0
					};
					collection.Insert(playerStats);
				}
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(54, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Registering PvP stats for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" - Kill: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(isKill);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Death: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(isDeath);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Assist: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(isAssist);
				}
				logger.LogInfo(val);
				if (isKill)
				{
					playerStats.Kills = playerStats.Kills.GetValueOrDefault() + 1;
					playerStats.KillStreak = playerStats.KillStreak.GetValueOrDefault() + 1;
					if (playerStats.KillStreak > playerStats.MaxStreak)
					{
						playerStats.MaxStreak = playerStats.KillStreak;
					}
				}
				if (isDeath)
				{
					playerStats.Deaths = playerStats.Deaths.GetValueOrDefault() + 1;
					playerStats.KillStreak = 0;
				}
				if (isAssist)
				{
					playerStats.Assists = playerStats.Assists.GetValueOrDefault() + 1;
				}
				collection.Update(playerStats);
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(43, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[PvPStatsService] Error while registering: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				logger2.LogError(val2);
			}
		}

		public static void RegisterDamage(string name, ulong steamID, int amount)
		{
			ILiteCollection<PlayerStats> collection = DatabaseWrapper.Instance.Collection;
			PlayerStats playerStats = collection.FindById(BsonValue.op_Implicit(name)) ?? new PlayerStats
			{
				Name = name,
				SteamID = steamID
			};
			playerStats.Damage = playerStats.Damage.GetValueOrDefault() + amount;
			collection.Upsert(playerStats);
		}

		public static Dictionary<string, List<string>> GetAllClans()
		{
			DatabaseWrapper instance = DatabaseWrapper.Instance;
			List<ClanMemberRecord> source = instance.ClanMembersCollection.FindAll().ToList();
			Dictionary<ulong, string> playerStats = instance.Collection.FindAll().ToDictionary((PlayerStats p) => p.SteamID, (PlayerStats p) => p.Name);
			string value;
			return (from m in source
				group m by m.ClanName).ToDictionary((IGrouping<string, ClanMemberRecord> g) => g.Key, (IGrouping<string, ClanMemberRecord> g) => g.Select((ClanMemberRecord m) => (!playerStats.TryGetValue(m.SteamID, out value)) ? $"Unknown({m.SteamID})" : value).ToList());
		}

		public static void RegisterDamageTaken(string name, ulong steamID, int amount)
		{
			ILiteCollection<PlayerStats> collection = DatabaseWrapper.Instance.Collection;
			PlayerStats playerStats = collection.FindById(BsonValue.op_Implicit(name)) ?? new PlayerStats
			{
				Name = name,
				SteamID = steamID
			};
			playerStats.DamageTaken = playerStats.DamageTaken.GetValueOrDefault() + amount;
			collection.Upsert(playerStats);
		}

		public static Dictionary<string, PlayerStats> GetAllStats()
		{
			return DatabaseWrapper.Instance.Collection.FindAll().ToDictionary((PlayerStats ps) => ps.Name, (PlayerStats ps) => ps);
		}

		public static PlayerStats GetStats(string name)
		{
			return DatabaseWrapper.Instance.Collection.FindById(BsonValue.op_Implicit(name)) ?? new PlayerStats
			{
				Name = name
			};
		}

		public static void Init()
		{
			_ = DatabaseWrapper.Instance;
			Plugin.Logger.LogInfo((object)"[PvPStatsService] Database initialized.");
		}
	}
}
namespace CustomKill.Commands
{
	public static class ExportStatsCommand
	{
		[Command("exportstats", null, null, "Exports all player stats and clan members to a CSV file.", null, true)]
		public static void ExportStats(ChatCommandContext ctx)
		{
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Expected O, but got Unknown
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				Dictionary<string, PlayerStats> allStats = PvPStatsService.GetAllStats();
				Dictionary<string, List<string>> allClans = PvPStatsService.GetAllClans();
				StringBuilder stringBuilder = new StringBuilder();
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				foreach (KeyValuePair<string, List<string>> item in allClans)
				{
					foreach (string item2 in item.Value)
					{
						if (!dictionary.ContainsKey(item2))
						{
							dictionary[item2] = item.Key;
						}
					}
				}
				stringBuilder.AppendLine("PlayerName,ClanName,ClanTag,Damage,Kills,Deaths,Assists");
				foreach (KeyValuePair<string, PlayerStats> item3 in allStats.OrderBy((KeyValuePair<string, PlayerStats> p) => p.Value.Name))
				{
					PlayerStats value = item3.Value;
					string value2;
					string text = (dictionary.TryGetValue(value.Name, out value2) ? value2 : "");
					string value3 = ((!string.IsNullOrWhiteSpace(text)) ? TruncateClan(text) : "---");
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(6, 7, stringBuilder2);
					handler.AppendFormatted(value.Name);
					handler.AppendLiteral(",");
					handler.AppendFormatted(text);
					handler.AppendLiteral(",");
					handler.AppendFormatted(value3);
					handler.AppendLiteral(",");
					handler.AppendFormatted(value.Damage.GetValueOrDefault());
					handler.AppendLiteral(",");
					handler.AppendFormatted(value.Kills.GetValueOrDefault());
					handler.AppendLiteral(",");
					handler.AppendFormatted(value.Deaths.GetValueOrDefault());
					handler.AppendLiteral(",");
					handler.AppendFormatted(value.Assists.GetValueOrDefault());
					stringBuilder2.AppendLine(ref handler);
				}
				string text2 = Path.Combine(Paths.PluginPath, "CustomKill", "Exports");
				Directory.CreateDirectory(text2);
				string text3 = $"PvPStatsExport_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
				string text4 = Path.Combine(text2, text3);
				File.WriteAllText(text4, stringBuilder.ToString());
				ctx.Reply("Export completed. File saved to: " + text3);
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ExportStatsCommand] Exported stats to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text4);
				}
				logger.LogInfo(val);
			}
			catch (Exception ex)
			{
				ctx.Reply("Export failed: " + ex.Message);
				ManualLogSource logger2 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(28, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[ExportStatsCommand] Error: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				logger2.LogError(val2);
			}
		}

		private static string TruncateClan(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "---";
			}
			if (name.Length > 3)
			{
				return name.Substring(0, 3).ToUpper();
			}
			return name.ToUpper();
		}
	}
	public static class KDCommand
	{
		[Command("kd", null, null, "Shows your Kill/Death ratio.", null, false)]
		public static void ShowKD(ChatCommandContext ctx)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			User user = ctx.Event.User;
			PlayerStats stats = PvPStatsService.GetStats(((object)(FixedString64Bytes)(ref user.CharacterName)).ToString());
			int valueOrDefault = stats.Kills.GetValueOrDefault();
			int valueOrDefault2 = stats.Deaths.GetValueOrDefault();
			if (valueOrDefault == 0 && valueOrDefault2 == 0)
			{
				ctx.Reply("<color=#aaaaaa>You have no kills or deaths recorded yet.</color>");
				return;
			}
			string text = ((valueOrDefault2 == 0) ? ((float)valueOrDefault) : ((float)valueOrDefault / (float)valueOrDefault2)).ToString("0.00");
			string text2 = "<color=#e34d4d>Your K/D Ratio:</color> <color=#FFD700>" + text + "</color>";
			ctx.Reply(text2);
		}

		[Command("kda", null, null, "Shows your Kill/Death/Assist ratio.", null, false)]
		public static void ShowKDA(ChatCommandContext ctx)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			User user = ctx.Event.User;
			PlayerStats stats = PvPStatsService.GetStats(((object)(FixedString64Bytes)(ref user.CharacterName)).ToString());
			int valueOrDefault = stats.Kills.GetValueOrDefault();
			int valueOrDefault2 = stats.Deaths.GetValueOrDefault();
			int valueOrDefault3 = stats.Assists.GetValueOrDefault();
			if (valueOrDefault == 0 && valueOrDefault2 == 0 && valueOrDefault3 == 0)
			{
				ctx.Reply("<color=#aaaaaa>You have no K/D/A stats recorded yet.</color>");
				return;
			}
			float num = (float)valueOrDefault + (float)valueOrDefault3 * 0.5f;
			string text = ((valueOrDefault2 == 0) ? num : (num / (float)valueOrDefault2)).ToString("0.00");
			string text2 = "<color=#e34d4d>Your K/D/A Ratio:</color> <color=#00FFFF>" + text + "</color>";
			ctx.Reply(text2);
		}
	}
	internal class PlayerInfo
	{
		public static class PlayerInfoCommand
		{
			[Command("playerinfo", "pi", null, "Displays information about a player.", null, false)]
			public static void HandleCommand(ChatCommandContext ctx, string arg)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: 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)
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f3: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
				//IL_0175: Unknown result type (might be due to invalid IL or missing references)
				//IL_0177: Unknown result type (might be due to invalid IL or missing references)
				//IL_017c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0181: Unknown result type (might be due to invalid IL or missing references)
				//IL_018a: Unknown result type (might be due to invalid IL or missing references)
				//IL_018c: Unknown result type (might be due to invalid IL or missing references)
				//IL_019d: 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_0109: Unknown result type (might be due to invalid IL or missing references)
				//IL_010d: Unknown result type (might be due to invalid IL or missing references)
				//IL_010f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Unknown result type (might be due to invalid IL or missing references)
				//IL_0119: Unknown result type (might be due to invalid IL or missing references)
				//IL_0131: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_033a: Unknown result type (might be due to invalid IL or missing references)
				//IL_033c: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01db: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_020e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0210: Unknown result type (might be due to invalid IL or missing references)
				//IL_0221: Unknown result type (might be due to invalid IL or missing references)
				//IL_0223: Unknown result type (might be due to invalid IL or missing references)
				//IL_0228: Unknown result type (might be due to invalid IL or missing references)
				//IL_022d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0230: Unknown result type (might be due to invalid IL or missing references)
				//IL_0232: Unknown result type (might be due to invalid IL or missing references)
				//IL_023c: Unknown result type (might be due to invalid IL or missing references)
				//IL_029c: Unknown result type (might be due to invalid IL or missing references)
				//IL_029e: Unknown result type (might be due to invalid IL or missing references)
				ctx.Reply("Usage: .pi <playernamehere> - Display Clan name, members, and level of player.");
				LevelService instance = LevelService.Instance;
				World serverWorld = GetServerWorld();
				if (serverWorld == null)
				{
					ctx.Reply("Server world is not available.");
					return;
				}
				EntityManager entityManager = serverWorld.EntityManager;
				EntityQuery val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<User>() });
				NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
				val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<PlayerCharacter>() });
				NativeArray<Entity> val3 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
				Entity val4 = Entity.Null;
				User val5 = default(User);
				bool flag = false;
				Enumerator<Entity> enumerator = val2.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Entity current = enumerator.Current;
					User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(current);
					bool num = ((object)(FixedString64Bytes)(ref componentData.CharacterName)).ToString().ToLower().Contains(arg.ToLower());
					bool flag2 = componentData.PlatformId.ToString() == arg;
					if (!(num || flag2))
					{
						continue;
					}
					val4 = current;
					val5 = componentData;
					Enumerator<Entity> enumerator2 = val3.GetEnumerator();
					while (enumerator2.MoveNext())
					{
						Entity current2 = enumerator2.Current;
						if (((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(current2).UserEntity == current)
						{
							flag = true;
							break;
						}
					}
					instance.UpdatePlayerLevel(current);
					break;
				}
				if (val4 == Entity.Null)
				{
					ctx.Reply("No player found.");
					val2.Dispose();
					val3.Dispose();
					return;
				}
				string value = "No clan";
				Entity entity = val5.ClanEntity._Entity;
				List<string> list = new List<string>();
				if (entity != Entity.Null && ((EntityManager)(ref entityManager)).HasComponent<ClanTeam>(entity))
				{
					ClanTeam componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<ClanTeam>(entity);
					value = ((object)(FixedString64Bytes)(ref componentData2.Name)).ToString();
					if (((EntityManager)(ref entityManager)).HasComponent<SyncToUserBuffer>(entity))
					{
						Enumerator<SyncToUserBuffer> enumerator3 = ((EntityManager)(ref entityManager)).GetBuffer<SyncToUserBuffer>(entity, false).GetEnumerator();
						while (enumerator3.MoveNext())
						{
							SyncToUserBuffer current3 = enumerator3.Current;
							if (((EntityManager)(ref entityManager)).Exists(current3.UserEntity) && ((EntityManager)(ref entityManager)).HasComponent<User>(current3.UserEntity))
							{
								User componentData3 = ((EntityManager)(ref entityManager)).GetComponentData<User>(current3.UserEntity);
								instance.UpdatePlayerLevel(current3.UserEntity);
								string value2 = (componentData3.IsConnected ? "#00FF00" : "#FF0000");
								int maxLevel = instance.GetMaxLevel(((object)(FixedString64Bytes)(ref componentData3.CharacterName)).ToString());
								list.Add($"<color={value2}>{componentData3.CharacterName} [{maxLevel}]</color>");
							}
						}
					}
				}
				int maxLevel2 = instance.GetMaxLevel(((object)(FixedString64Bytes)(ref val5.CharacterName)).ToString());
				string value3 = (flag ? "#00FF00" : "#FF0000");
				string value4 = $"<color={value3}>{val5.CharacterName} [{maxLevel2}]</color>";
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("--- <color=#FFD700>Player Info</color> ---");
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(29, 1, stringBuilder2);
				handler.AppendLiteral("<color=#FFFF00>Name:</color> ");
				handler.AppendFormatted(value4);
				stringBuilder3.AppendLine(ref handler);
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(52, 1, stringBuilder2);
				handler.AppendLiteral("<color=#FFFF00>Clan:</color> <color=#FFFFFF>");
				handler.AppendFormatted(value);
				handler.AppendLiteral("</color>");
				stringBuilder4.AppendLine(ref handler);
				if (list.Count > 0)
				{
					string value5 = string.Join(" - ", list);
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder5 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(37, 1, stringBuilder2);
					handler.AppendLiteral("<color=#FFFF00>Clan Members:</color> ");
					handler.AppendFormatted(value5);
					stringBuilder5.AppendLine(ref handler);
				}
				ctx.Reply(stringBuilder.ToString());
				val2.Dispose();
				val3.Dispose();
			}

			private static World? GetServerWorld()
			{
				Enumerator<World> enumerator = World.All.GetEnumerator();
				while (enumerator.MoveNext())
				{
					World current = enumerator.Current;
					if (current.Name == "Server")
					{
						return current;
					}
				}
				return null;
			}
		}
	}
	public static class ResetStatsCommands
	{
		private static readonly HashSet<ulong> PendingConfirmations = new HashSet<ulong>();

		[Command("resetstats", "rs", null, "Resets all PvP stats and clan memberships (admin only)", null, true)]
		public static void ResetStats(ChatCommandContext ctx)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ulong platformId = ctx.User.PlatformId;
			if (!PendingConfirmations.Contains(platformId))
			{
				PendingConfirmations.Add(platformId);
				ctx.Reply("⚠ Are you sure you want to reset ALL PvP stats and clan membership records? This cannot be undone.\nPlease confirm by typing `.y` to proceed or `.n` to cancel.");
			}
			else
			{
				ctx.Reply("⚠ A reset confirmation is already pending. Please type `.y` to confirm or `.n` to cancel.");
			}
		}

		[Command("y", null, null, "Confirm pending reset (admin only)", null, true)]
		public static void ConfirmReset(ChatCommandContext ctx)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ulong platformId = ctx.User.PlatformId;
			if (PendingConfirmations.Contains(platformId))
			{
				int value = DatabaseWrapper.Instance.Collection.DeleteAll();
				int value2 = DatabaseWrapper.Instance.ClanMembersCollection.DeleteAll();
				ctx.Reply($"[ ! ] Reset complete. Deleted {value} player stat entries and {value2} clan membership entries.");
				PendingConfirmations.Remove(platformId);
			}
		}

		[Command("n", null, null, "Cancel pending reset (admin only)", null, true)]
		public static void CancelReset(ChatCommandContext ctx)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ulong platformId = ctx.User.PlatformId;
			if (PendingConfirmations.Contains(platformId))
			{
				ctx.Reply("[ X ] Reset cancelled. No data was changed.");
				PendingConfirmations.Remove(platformId);
			}
		}
	}
	public static class StatsCommand
	{
		[Command("stats", null, "playerName", "Shows your PvP stats or another player's.", null, false)]
		public static void HandleCommand(ChatCommandContext ctx, string playerName = null)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			User user = ctx.Event.User;
			string text = ((object)(FixedString64Bytes)(ref user.CharacterName)).ToString();
			bool flag = string.IsNullOrWhiteSpace(playerName) || playerName == text;
			string text2 = (flag ? text : playerName);
			PlayerStats stats = PvPStatsService.GetStats(text2);
			if (stats.Kills.GetValueOrDefault() == 0 && stats.Deaths.GetValueOrDefault() == 0 && stats.Assists.GetValueOrDefault() == 0 && stats.KillStreak.GetValueOrDefault() == 0 && stats.MaxStreak.GetValueOrDefault() == 0 && stats.Damage.GetValueOrDefault() == 0)
			{
				ctx.Reply(flag ? "<color=#aaaaaa>You have no PvP stats to display.</color>" : $"<color=#aaaaaa>No stats found for player <color={ColorSettings.Stats_PlayerNameColor.Value}>{text2}</color>.</color>");
				return;
			}
			bool isAdmin = ctx.Event.User.IsAdmin;
			string value = ((flag || isAdmin || !KillfeedSettings.RestrictDamageToAdmin.Value) ? $"{stats.Damage}" : "<color=#eb34db>Denied</color>");
			string value2 = ((flag || isAdmin || !KillfeedSettings.RestrictKillsToAdmin.Value) ? $"{stats.Kills}" : "<color=#eb34db>Denied</color>");
			string value3 = ((flag || isAdmin || !KillfeedSettings.RestrictDeathsToAdmin.Value) ? $"{stats.Deaths}" : "<color=#eb34db>Denied</color>");
			string value4 = ((flag || isAdmin || !KillfeedSettings.RestrictAssistsToAdmin.Value) ? $"{stats.Assists}" : "<color=#eb34db>Denied</color>");
			string value5 = ((flag || isAdmin || !KillfeedSettings.RestrictMaxStreakToAdmin.Value) ? $"{stats.MaxStreak}" : "<color=#eb34db>Denied</color>");
			string value6 = $"{stats.KillStreak.GetValueOrDefault()}";
			string text3 = $"<color={ColorSettings.Stats_TitleColor.Value}>Displaying stats for</color> <color={ColorSettings.Stats_PlayerNameColor.Value}>{text2}</color>\nDamage: <color={ColorSettings.Stats_DamageColor.Value}>{value}</color> | Kills: <color={ColorSettings.Stats_KillsColor.Value}>{value2}</color> | Deaths: <color={ColorSettings.Stats_DeathsColor.Value}>{value3}</color> | Assists: <color={ColorSettings.Stats_AssistsColor.Value}>{value4}</color>\nKill Streak: <color={ColorSettings.Stats_KillStreakColor.Value}>{value6}</color> | Max Streak: <color={ColorSettings.Stats_MaxStreakColor.Value}>{value5}</color>";
			ctx.Reply(text3);
		}

		[Command("ptd", null, null, "Post top player and clan stats to Discord", null, true)]
		public static void PostStatsToDiscord(ChatCommandContext ctx)
		{
			DiscordBroadcaster.PostTopStatsToDiscord(ctx);
		}
	}
	internal class Top
	{
		public static class TopCommand
		{
			[Command("top", null, "[category] [subcategory]", "Displays leaderboards for players or clans.", null, false)]
			public static void HandleCommand(ChatCommandContext ctx, string category = null, string metric = null)
			{
				//IL_06e5: Unknown result type (might be due to invalid IL or missing references)
				category = (category ?? string.Empty).ToLowerInvariant();
				metric = (metric ?? string.Empty).ToLowerInvariant();
				StringBuilder stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler;
				if (category == "clan")
				{
					if (metric != "kills" && metric != "damage")
					{
						ctx.Reply($"<color={ColorSettings.Top_ClanTitleColor.Value}>Usage:</color> <color={ColorSettings.Top_ClanTitleColor.Value}>.top clan [category]</color>\n <color={ColorSettings.Top_ClanTitleColor.Value}>Categories:</color>\n <color={ColorSettings.Top_ClanKillsColor.Value}>kills</color>\n <color={ColorSettings.Top_ClanDamageColor.Value}>damage</color>\n");
						return;
					}
					int value = KillfeedSettings.ClanTrackingDays.Value;
					DateTime cutoff = DateTime.UtcNow.AddDays(-value);
					List<ClanMemberRecord> source = DatabaseWrapper.Instance.ClanMembersCollection.Find((Expression<Func<ClanMemberRecord, bool>>)((ClanMemberRecord x) => x.JoinedAt <= cutoff), 0, int.MaxValue).ToList();
					if (!source.Any())
					{
						ctx.Reply($"<color={ColorSettings.Top_ClanTitleColor.Value}>No clans with members older than {value} day{((value == 1) ? "" : "s")}.</color>");
						return;
					}
					var source2 = (from m in source
						group m by m.ClanName into g
						select new
						{
							Clan = g.Key,
							Kills = g.Sum((ClanMemberRecord m) => PvPStatsService.GetStats(m.SteamID.ToString()).Kills.GetValueOrDefault()),
							Damage = g.Sum((ClanMemberRecord m) => PvPStatsService.GetStats(m.SteamID.ToString()).Damage.GetValueOrDefault())
						}).ToList();
					var list = ((metric == "damage") ? source2.OrderByDescending(c => c.Damage) : source2.OrderByDescending(c => c.Kills)).Take(3).ToList();
					if (!list.Any())
					{
						ctx.Reply("<color=#aaaaaa>No clan stats to display.</color>");
						return;
					}
					StringBuilder stringBuilder = new StringBuilder();
					stringBuilder.AppendLine((metric == "damage") ? $"<color={ColorSettings.Top_ClanTitleColor.Value}>Top Clans by</color> <color={ColorSettings.Top_ClanDamageColor.Value}Damage \ud83c\udfc6</color>" : $"<color={ColorSettings.Top_ClanTitleColor.Value}>Top Clans by</color> <color={ColorSettings.Top_ClanKillsColor.Value}Kills \ud83c\udfc6</color>");
					for (int i = 0; i < list.Count; i++)
					{
						var anon = list[i];
						int value2 = ((metric == "damage") ? anon.Damage : anon.Kills);
						string value3 = ((metric == "damage") ? ColorSettings.Top_ClanDamageColor.Value : ColorSettings.Top_ClanKillsColor.Value);
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder3 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(37, 5, stringBuilder2);
						handler.AppendFormatted(i + 1);
						handler.AppendLiteral(". <color=");
						handler.AppendFormatted(ColorSettings.Top_ClanNameColor.Value);
						handler.AppendLiteral(">");
						handler.AppendFormatted(anon.Clan);
						handler.AppendLiteral("</color> — ");
						handler.AppendLiteral("<color=");
						handler.AppendFormatted(value3);
						handler.AppendLiteral(">");
						handler.AppendFormatted(value2);
						handler.AppendLiteral("</color>");
						stringBuilder3.AppendLine(ref handler);
					}
					ctx.Reply(stringBuilder.ToString());
					return;
				}
				Dictionary<string, PlayerStats> allStats = PvPStatsService.GetAllStats();
				if (allStats.Count == 0)
				{
					ctx.Reply("<color=#aaaaaa>No player stats found.</color>");
					return;
				}
				string text = "<color=#ff5555>Missing or invalid category.</color> Usage: <color=#ffff00>.top [category]</color>\nCategories:\n <color=#ffaa00>clan</color>)\n <color=#ffaa00>damage</color>" + (KillfeedSettings.RestrictDamageToAdmin.Value ? " (Admin Only)" : "") + "\n <color=#ffaa00>kills</color>" + (KillfeedSettings.RestrictKillsToAdmin.Value ? " (Admin Only)" : "") + "\n <color=#ffaa00>deaths</color>" + (KillfeedSettings.RestrictDeathsToAdmin.Value ? " (Admin Only)" : "") + "\n <color=#ffaa00>assists</color>" + (KillfeedSettings.RestrictAssistsToAdmin.Value ? " (Admin Only)" : "") + "\n <color=#ffaa00>maxstreak</color>" + (KillfeedSettings.RestrictMaxStreakToAdmin.Value ? " (Admin Only)" : "");
				if (string.IsNullOrWhiteSpace(category))
				{
					ctx.Reply(text);
					return;
				}
				if (category == "ms")
				{
					category = "maxstreak";
				}
				if (!new string[6] { "clan", "damage", "kills", "deaths", "assists", "maxstreak" }.Contains(category))
				{
					ctx.Reply(text);
					return;
				}
				if (((category == "damage" && KillfeedSettings.RestrictDamageToAdmin.Value) || (category == "kills" && KillfeedSettings.RestrictKillsToAdmin.Value) || (category == "deaths" && KillfeedSettings.RestrictDeathsToAdmin.Value) || (category == "assists" && KillfeedSettings.RestrictAssistsToAdmin.Value) || (category == "maxstreak" && KillfeedSettings.RestrictMaxStreakToAdmin.Value)) && !ctx.Event.User.IsAdmin)
				{
					ctx.Reply("<color=#ff5555>Access to the '" + category + "' leaderboard is restricted to admins only.</color>");
					return;
				}
				List<KeyValuePair<string, PlayerStats>> list2 = (category switch
				{
					"damage" => (from p in allStats
						where p.Value.Damage.GetValueOrDefault() > 0
						orderby p.Value.Damage descending
						select p).Take(5), 
					"kills" => (from p in allStats
						where p.Value.Kills.GetValueOrDefault() > 0
						orderby p.Value.Kills descending
						select p).Take(5), 
					"deaths" => (from p in allStats
						where p.Value.Deaths.GetValueOrDefault() > 0
						orderby p.Value.Deaths descending
						select p).Take(5), 
					"assists" => (from p in allStats
						where p.Value.Assists.GetValueOrDefault() > 0
						orderby p.Value.Assists descending
						select p).Take(5), 
					"maxstreak" => (from p in allStats
						where p.Value.MaxStreak.GetValueOrDefault() > 0
						orderby p.Value.MaxStreak descending
						select p).Take(5), 
					_ => Enumerable.Empty<KeyValuePair<string, PlayerStats>>(), 
				}).ToList();
				if (!list2.Any())
				{
					ctx.Reply("<color=#aaaaaa>No " + category + " to display.</color>");
					return;
				}
				StringBuilder stringBuilder4 = new StringBuilder();
				stringBuilder2 = stringBuilder4;
				StringBuilder stringBuilder5 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(34, 2, stringBuilder2);
				handler.AppendLiteral("<color=");
				handler.AppendFormatted(ColorSettings.Top_TitleColor.Value);
				handler.AppendLiteral(">Top 5 players by ");
				handler.AppendFormatted(category);
				handler.AppendLiteral(":</color>");
				stringBuilder5.AppendLine(ref handler);
				int num = 1;
				foreach (KeyValuePair<string, PlayerStats> item in list2)
				{
					string value4 = category switch
					{
						"damage" => ColorSettings.Top_DamageColor.Value, 
						"kills" => ColorSettings.Top_KillsColor.Value, 
						"deaths" => ColorSettings.Top_DeathsColor.Value, 
						"assists" => ColorSettings.Top_AssistsColor.Value, 
						"maxstreak" => ColorSettings.Top_MaxStreakColor.Value, 
						_ => "#ffffff", 
					};
					int value5 = category switch
					{
						"damage" => item.Value.Damage.GetValueOrDefault(), 
						"kills" => item.Value.Kills.GetValueOrDefault(), 
						"deaths" => item.Value.Deaths.GetValueOrDefault(), 
						"assists" => item.Value.Assists.GetValueOrDefault(), 
						"maxstreak" => item.Value.MaxStreak.GetValueOrDefault(), 
						_ => 0, 
					};
					stringBuilder2 = stringBuilder4;
					StringBuilder stringBuilder6 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(37, 5, stringBuilder2);
					handler.AppendFormatted(num);
					handler.AppendLiteral(". <color=");
					handler.AppendFormatted(ColorSettings.Top_PlayerNameColor.Value);
					handler.AppendLiteral(">");
					handler.AppendFormatted(item.Key);
					handler.AppendLiteral("</color> - <color=");
					handler.AppendFormatted(value4);
					handler.AppendLiteral(">");
					handler.AppendFormatted(value5);
					handler.AppendLiteral("</color>");
					stringBuilder6.AppendLine(ref handler);
					num++;
				}
				ctx.Reply(stringBuilder4.ToString());
			}
		}
	}
}
namespace CustomKill.Combat
{
	public static class ECSExtensions
	{
		public unsafe static T Read<T>(this Entity entity) where T : struct
		{
			//IL_0012: 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_001a: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			ComponentType val = default(ComponentType);
			((ComponentType)(ref val))..ctor(Il2CppType.Of<T>(), (AccessMode)0);
			EntityManager entityManager = Helpers.Server.EntityManager;
			return Marshal.PtrToStructure<T>(new IntPtr(((EntityManager)(ref entityManager)).GetComponentDataRawRO(entity, val.TypeIndex)));
		}

		public static bool Has<T>(this Entity entity) where T : struct
		{
			//IL_0012: 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_001a: 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)
			ComponentType val = default(ComponentType);
			((ComponentType)(ref val))..ctor(Il2CppType.Of<T>(), (AccessMode)0);
			EntityManager entityManager = Helpers.Server.EntityManager;
			return ((EntityManager)(ref entityManager)).HasComponent(entity, val);
		}
	}
	public static class Helpers
	{
		public static World Server { get; } = GetWorld("Server");


		private static World GetWorld(string name)
		{
			Enumerator<World> enumerator = World.s_AllWorlds.GetEnumerator();
			while (enumerator.MoveNext())
			{
				World current = enumerator.Current;
				if (current.Name == name)
				{
					return current;
				}
			}
			return null;
		}
	}
	public struct HitInteraction
	{
		public ulong AttackerSteamId;

		public ulong VictimSteamId;

		public string AttackerName;

		public int AttackerLevel;

		public string VictimName;

		public int VictimLevel;

		public long Timestamp;

		public int DmgSourceGUID;

		public int DmgAmount;
	}
	public class PlayerHitData
	{
		public List<HitInteraction> Attacks { get; } = new List<HitInteraction>();


		public List<HitInteraction> Defenses { get; } = new List<HitInteraction>();

	}
	public static class PlayerHitStore
	{
		private const double PVP_WINDOW_SECONDS = 30.0;

		private static readonly Dictionary<ulong, PlayerHitData> interactionsByPlayer = new Dictionary<ulong, PlayerHitData>();

		public static IReadOnlyDictionary<ulong, PlayerHitData> InteractionsByPlayer => interactionsByPlayer;

		public static void AddHit(ulong attackerSteamId, string attackerName, int attackerLevel, ulong victimSteamId, string victimName, int victimLevel, int dmgSourceGUID, int damageAmount)
		{
			HitInteraction hitInteraction = default(HitInteraction);
			hitInteraction.AttackerSteamId = attackerSteamId;
			hitInteraction.AttackerName = attackerName;
			hitInteraction.AttackerLevel = attackerLevel;
			hitInteraction.VictimSteamId = victimSteamId;
			hitInteraction.VictimName = victimName;
			hitInteraction.VictimLevel = victimLevel;
			hitInteraction.Timestamp = DateTime.UtcNow.Ticks;
			hitInteraction.DmgSourceGUID = dmgSourceGUID;
			hitInteraction.DmgAmount = damageAmount;
			HitInteraction hit = hitInteraction;
			AddAttack(attackerSteamId, hit);
			AddDefense(victimSteamId, hit);
			if (interactionsByPlayer.TryGetValue(victimSteamId, out var value) && value.Defenses.Count >= 500)
			{
				CleanupOldHitInteractionsByPlayer(victimSteamId);
			}
		}

		private static void AddAttack(ulong playerSteamId, HitInteraction hit)
		{
			if (!interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				value = new PlayerHitData();
				interactionsByPlayer[playerSteamId] = value;
			}
			value.Attacks.Add(hit);
		}

		private static void AddDefense(ulong playerSteamId, HitInteraction hit)
		{
			if (!interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				value = new PlayerHitData();
				interactionsByPlayer[playerSteamId] = value;
			}
			value.Defenses.Add(hit);
		}

		public static IReadOnlyList<HitInteraction> GetAttacks(ulong playerSteamId)
		{
			if (interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				return value.Attacks;
			}
			return Array.Empty<HitInteraction>();
		}

		public static IReadOnlyList<HitInteraction> GetDefenses(ulong playerSteamId)
		{
			if (interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				return value.Defenses;
			}
			return Array.Empty<HitInteraction>();
		}

		public static Dictionary<ulong, (string Name, int Level)> GetRecentAttackersWithLvl(ulong playerSteamId, double pvpWindowSeconds = 30.0)
		{
			Dictionary<ulong, (string, int)> dictionary = new Dictionary<ulong, (string, int)>();
			if (!interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				return dictionary;
			}
			long ticks = DateTime.UtcNow.Ticks;
			long ticks2 = TimeSpan.FromSeconds(pvpWindowSeconds).Ticks;
			foreach (HitInteraction defense in value.Defenses)
			{
				if (ticks - defense.Timestamp > ticks2 || playerSteamId == defense.AttackerSteamId)
				{
					continue;
				}
				if (dictionary.TryGetValue(defense.AttackerSteamId, out var value2))
				{
					if (defense.AttackerLevel > value2.Item2)
					{
						dictionary[defense.AttackerSteamId] = (defense.AttackerName, defense.AttackerLevel);
					}
				}
				else
				{
					dictionary[defense.AttackerSteamId] = (defense.AttackerName, defense.AttackerLevel);
				}
			}
			return dictionary;
		}

		public static int GetHighestLvlUsedOnKiller(ulong victimSteamId, ulong killerSteamId, double pvpWindowSeconds = 30.0)
		{
			int num = -1;
			if (!interactionsByPlayer.TryGetValue(victimSteamId, out var value))
			{
				return num;
			}
			long ticks = DateTime.UtcNow.Ticks;
			long ticks2 = TimeSpan.FromSeconds(pvpWindowSeconds).Ticks;
			foreach (HitInteraction attack in value.Attacks)
			{
				if (ticks - attack.Timestamp <= ticks2 && killerSteamId == attack.VictimSteamId)
				{
					num = Math.Max(num, attack.AttackerLevel);
				}
			}
			return num;
		}

		public static IReadOnlyList<HitInteraction> GetRecentInteractions(ulong playerSteamId, double pvpWindowSeconds = 30.0)
		{
			if (!interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				return Array.Empty<HitInteraction>();
			}
			long ticks = DateTime.UtcNow.Ticks;
			long ticks2 = TimeSpan.FromSeconds(pvpWindowSeconds).Ticks;
			long earliest = ticks - ticks2;
			return (from hit in value.Attacks.Concat(value.Defenses)
				where hit.Timestamp >= earliest
				orderby hit.Timestamp
				select hit).ToList();
		}

		public static void CleanupOldHitInteractionsByPlayer(ulong playerSteamId, double pvpWindowSeconds = 30.0)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			if (interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				long nowTicks = DateTime.UtcNow.Ticks;
				long windowTicks = TimeSpan.FromSeconds(pvpWindowSeconds).Ticks;
				int count = value.Defenses.Count;
				value.Defenses.RemoveAll((HitInteraction hit) => nowTicks - hit.Timestamp > windowTicks);
				int count2 = value.Defenses.Count;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExMessageLogInterpolatedStringHandler val = new BepInExMessageLogInterpolatedStringHandler(46, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("CLEANED up ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(count - count2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" old hit interactions for SteamID: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ulong>(playerSteamId);
				}
				logger.LogMessage(val);
			}
		}

		public static void ResetPlayerHitInteractions(ulong playerSteamId)
		{
			if (interactionsByPlayer.TryGetValue(playerSteamId, out var value))
			{
				value.Attacks.Clear();
				value.Defenses.Clear();
			}
		}

		public static void Clear()
		{
			interactionsByPlayer.Clear();
		}
	}
	public static class StatChangeHook
	{
		[HarmonyPatch(typeof(StatChangeSystem), "OnUpdate")]
		public static class Patch
		{
			public static void Prefix(StatChangeSystem __instance)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: 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_001d: 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)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Invalid comparison between Unknown and I4
				//IL_0030: 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_0054: Unknown result type (might b

BepInEx/plugins/LiteDB.dll

Decompiled 2 weeks ago
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using LiteDB.Engine;
using LiteDB.Utils;
using LiteDB.Utils.Extensions;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("LiteDB.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010029e66990e22110ce40a7197e37f8f82df3332c399e696df7f27d09e14ee590ac2dda735d4777fe554c427540bde93b14d3d26c04731c963383dcaa18859c8cbcd4a1a9c394d1204f474c2ab6f23a2eaadf81eb8a7a3d3cc73658868b0302163b92a2614ca050ab703be33c3e1d76f55b11f4f87cb73558f3aa69c1ce726d9ee8")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Maurício David")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("MIT")]
[assembly: AssemblyDescription("LiteDB - A lightweight embedded .NET NoSQL document store in a single datafile")]
[assembly: AssemblyFileVersion("5.0.21")]
[assembly: AssemblyInformationalVersion("5.0.21+391cc9318c5be6e56cb71b3ce14b1ed9cb324763")]
[assembly: AssemblyProduct("LiteDB")]
[assembly: AssemblyTitle("LiteDB")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/mbdavid/LiteDB")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("5.0.21.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]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LiteDB
{
	public sealed class LiteCollection<T> : ILiteCollection<T>
	{
		private readonly string _collection;

		private readonly ILiteEngine _engine;

		private readonly List<BsonExpression> _includes;

		private readonly BsonMapper _mapper;

		private readonly EntityMapper _entity;

		private readonly MemberMapper _id;

		private readonly BsonAutoId _autoId;

		public string Name => _collection;

		public BsonAutoId AutoId => _autoId;

		public EntityMapper EntityMapper => _entity;

		public int Count()
		{
			return Query().Count();
		}

		public int Count(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).Count();
		}

		public int Count(string predicate, BsonDocument parameters)
		{
			return Count(BsonExpression.Create(predicate, parameters));
		}

		public int Count(string predicate, params BsonValue[] args)
		{
			return Count(BsonExpression.Create(predicate, args));
		}

		public int Count(Expression<Func<T, bool>> predicate)
		{
			return Count(_mapper.GetExpression(predicate));
		}

		public int Count(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count();
		}

		public long LongCount()
		{
			return Query().LongCount();
		}

		public long LongCount(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).LongCount();
		}

		public long LongCount(string predicate, BsonDocument parameters)
		{
			return LongCount(BsonExpression.Create(predicate, parameters));
		}

		public long LongCount(string predicate, params BsonValue[] args)
		{
			return LongCount(BsonExpression.Create(predicate, args));
		}

		public long LongCount(Expression<Func<T, bool>> predicate)
		{
			return LongCount(_mapper.GetExpression(predicate));
		}

		public long LongCount(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count();
		}

		public bool Exists(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).Exists();
		}

		public bool Exists(string predicate, BsonDocument parameters)
		{
			return Exists(BsonExpression.Create(predicate, parameters));
		}

		public bool Exists(string predicate, params BsonValue[] args)
		{
			return Exists(BsonExpression.Create(predicate, args));
		}

		public bool Exists(Expression<Func<T, bool>> predicate)
		{
			return Exists(_mapper.GetExpression(predicate));
		}

		public bool Exists(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Exists();
		}

		public BsonValue Min(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonDocument bsonDocument = Query().OrderBy(keySelector).Select(keySelector).ToDocuments()
				.First();
			return bsonDocument[bsonDocument.Keys.First()];
		}

		public BsonValue Min()
		{
			return Min("_id");
		}

		public K Min<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			BsonValue value = Min(expression);
			return (K)_mapper.Deserialize(typeof(K), value);
		}

		public BsonValue Max(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonDocument bsonDocument = Query().OrderByDescending(keySelector).Select(keySelector).ToDocuments()
				.First();
			return bsonDocument[bsonDocument.Keys.First()];
		}

		public BsonValue Max()
		{
			return Max("_id");
		}

		public K Max<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			BsonValue value = Max(expression);
			return (K)_mapper.Deserialize(typeof(K), value);
		}

		public bool Delete(BsonValue id)
		{
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			return _engine.Delete(_collection, new BsonValue[1] { id }) == 1;
		}

		public int DeleteAll()
		{
			return _engine.DeleteMany(_collection, null);
		}

		public int DeleteMany(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return _engine.DeleteMany(_collection, predicate);
		}

		public int DeleteMany(string predicate, BsonDocument parameters)
		{
			return DeleteMany(BsonExpression.Create(predicate, parameters));
		}

		public int DeleteMany(string predicate, params BsonValue[] args)
		{
			return DeleteMany(BsonExpression.Create(predicate, args));
		}

		public int DeleteMany(Expression<Func<T, bool>> predicate)
		{
			return DeleteMany(_mapper.GetExpression(predicate));
		}

		public ILiteQueryable<T> Query()
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, new Query()).Include(_includes);
		}

		public IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Include(_includes).Where(predicate).Skip(skip)
				.Limit(limit)
				.ToEnumerable();
		}

		public IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue)
		{
			if (query == null)
			{
				throw new ArgumentNullException("query");
			}
			if (skip != 0)
			{
				query.Offset = skip;
			}
			if (limit != int.MaxValue)
			{
				query.Limit = limit;
			}
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).ToEnumerable();
		}

		public IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue)
		{
			return Find(_mapper.GetExpression(predicate), skip, limit);
		}

		public T FindById(BsonValue id)
		{
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			return Find(BsonExpression.Create("_id = @0", id)).FirstOrDefault();
		}

		public T FindOne(BsonExpression predicate)
		{
			return Find(predicate).FirstOrDefault();
		}

		public T FindOne(string predicate, BsonDocument parameters)
		{
			return FindOne(BsonExpression.Create(predicate, parameters));
		}

		public T FindOne(BsonExpression predicate, params BsonValue[] args)
		{
			return FindOne(BsonExpression.Create(predicate, args));
		}

		public T FindOne(Expression<Func<T, bool>> predicate)
		{
			return FindOne(_mapper.GetExpression(predicate));
		}

		public T FindOne(Query query)
		{
			return Find(query).FirstOrDefault();
		}

		public IEnumerable<T> FindAll()
		{
			return Query().Include(_includes).ToEnumerable();
		}

		public ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			return Include(expression);
		}

		public ILiteCollection<T> Include(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			LiteCollection<T> liteCollection = new LiteCollection<T>(_collection, _autoId, _engine, _mapper);
			liteCollection._includes.AddRange(_includes);
			liteCollection._includes.Add(keySelector);
			return liteCollection;
		}

		public bool EnsureIndex(string name, BsonExpression expression, bool unique = false)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			return _engine.EnsureIndex(_collection, name, expression, unique);
		}

		public bool EnsureIndex(BsonExpression expression, bool unique = false)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			string name = Regex.Replace(expression.Source, "[^a-z0-9]", "", RegexOptions.IgnoreCase | RegexOptions.Compiled);
			return EnsureIndex(name, expression, unique);
		}

		public bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false)
		{
			BsonExpression indexExpression = GetIndexExpression(keySelector);
			return EnsureIndex(indexExpression, unique);
		}

		public bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false)
		{
			BsonExpression indexExpression = GetIndexExpression(keySelector);
			return EnsureIndex(name, indexExpression, unique);
		}

		private BsonExpression GetIndexExpression<K>(Expression<Func<T, K>> keySelector)
		{
			BsonExpression bsonExpression = _mapper.GetIndexExpression(keySelector);
			if (typeof(K).IsEnumerable() && bsonExpression.IsScalar)
			{
				if (bsonExpression.Type != BsonExpressionType.Path)
				{
					throw new LiteException(0, "Expression `" + bsonExpression.Source + "` must return a enumerable expression");
				}
				bsonExpression = bsonExpression.Source + "[*]";
			}
			return bsonExpression;
		}

		public bool DropIndex(string name)
		{
			return _engine.DropIndex(_collection, name);
		}

		public BsonValue Insert(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bool flag = RemoveDocId(bsonDocument);
			_engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId);
			BsonValue bsonValue = bsonDocument["_id"];
			if (flag)
			{
				_id.Setter(entity, bsonValue.RawValue);
			}
			return bsonValue;
		}

		public void Insert(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			_engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId);
		}

		public int Insert(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Insert(_collection, GetBsonDocs(entities), _autoId);
		}

		[Obsolete("Use normal Insert()")]
		public int InsertBulk(IEnumerable<T> entities, int batchSize = 5000)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Insert(_collection, GetBsonDocs(entities), _autoId);
		}

		private IEnumerable<BsonDocument> GetBsonDocs(IEnumerable<T> documents)
		{
			foreach (T document in documents)
			{
				BsonDocument doc = _mapper.ToDocument(document);
				bool removed = RemoveDocId(doc);
				yield return doc;
				if (removed && _id != null)
				{
					_id.Setter(document, doc["_id"].RawValue);
				}
			}
		}

		private bool RemoveDocId(BsonDocument doc)
		{
			if (_id != null && doc.TryGetValue("_id", out var value) && ((_autoId == BsonAutoId.Int32 && value.IsInt32 && value.AsInt32 == 0) || (_autoId == BsonAutoId.ObjectId && (value.IsNull || (value.IsObjectId && value.AsObjectId == ObjectId.Empty))) || (_autoId == BsonAutoId.Guid && value.IsGuid && value.AsGuid == Guid.Empty) || (_autoId == BsonAutoId.Int64 && value.IsInt64 && value.AsInt64 == 0L)))
			{
				doc.Remove("_id");
				return true;
			}
			return false;
		}

		public bool Update(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0;
		}

		public bool Update(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0;
		}

		public int Update(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Update(_collection, entities.Select((T x) => _mapper.ToDocument(x)));
		}

		public int UpdateMany(BsonExpression transform, BsonExpression predicate)
		{
			if (transform == null)
			{
				throw new ArgumentNullException("transform");
			}
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			if (transform.Type != BsonExpressionType.Document)
			{
				throw new ArgumentException("Extend expression must return a document. Eg: `col.UpdateMany('{ Name: UPPER(Name) }', 'Age > 10')`");
			}
			return _engine.UpdateMany(_collection, transform, predicate);
		}

		public int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate)
		{
			if (extend == null)
			{
				throw new ArgumentNullException("extend");
			}
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			BsonExpression expression = _mapper.GetExpression(extend);
			BsonExpression expression2 = _mapper.GetExpression(predicate);
			if (expression.Type != BsonExpressionType.Document)
			{
				throw new ArgumentException("Extend expression must return an anonymous class to be merge with entities. Eg: `col.UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10)`");
			}
			return _engine.UpdateMany(_collection, expression, expression2);
		}

		public bool Upsert(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			return Upsert(new T[1] { entity }) == 1;
		}

		public int Upsert(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Upsert(_collection, GetBsonDocs(entities), _autoId);
		}

		public bool Upsert(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			return _engine.Upsert(_collection, new BsonDocument[1] { bsonDocument }, _autoId) > 0;
		}

		internal LiteCollection(string name, BsonAutoId autoId, ILiteEngine engine, BsonMapper mapper)
		{
			_collection = name ?? mapper.ResolveCollectionName(typeof(T));
			_engine = engine;
			_mapper = mapper;
			_includes = new List<BsonExpression>();
			if (typeof(T) == typeof(BsonDocument))
			{
				_entity = null;
				_id = null;
				_autoId = autoId;
				return;
			}
			_entity = mapper.GetEntityMapper(typeof(T));
			_id = _entity.Id;
			if (_id != null && _id.AutoId)
			{
				_autoId = ((_id.DataType == typeof(int) || _id.DataType == typeof(int?)) ? BsonAutoId.Int32 : ((_id.DataType == typeof(long) || _id.DataType == typeof(long?)) ? BsonAutoId.Int64 : ((_id.DataType == typeof(Guid) || _id.DataType == typeof(Guid?)) ? BsonAutoId.Guid : BsonAutoId.ObjectId)));
			}
			else
			{
				_autoId = autoId;
			}
		}
	}
	public interface ILiteCollection<T>
	{
		string Name { get; }

		BsonAutoId AutoId { get; }

		EntityMapper EntityMapper { get; }

		ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector);

		ILiteCollection<T> Include(BsonExpression keySelector);

		bool Upsert(T entity);

		int Upsert(IEnumerable<T> entities);

		bool Upsert(BsonValue id, T entity);

		bool Update(T entity);

		bool Update(BsonValue id, T entity);

		int Update(IEnumerable<T> entities);

		int UpdateMany(BsonExpression transform, BsonExpression predicate);

		int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate);

		BsonValue Insert(T entity);

		void Insert(BsonValue id, T entity);

		int Insert(IEnumerable<T> entities);

		int InsertBulk(IEnumerable<T> entities, int batchSize = 5000);

		bool EnsureIndex(string name, BsonExpression expression, bool unique = false);

		bool EnsureIndex(BsonExpression expression, bool unique = false);

		bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false);

		bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false);

		bool DropIndex(string name);

		ILiteQueryable<T> Query();

		IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue);

		IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue);

		IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue);

		T FindById(BsonValue id);

		T FindOne(BsonExpression predicate);

		T FindOne(string predicate, BsonDocument parameters);

		T FindOne(BsonExpression predicate, params BsonValue[] args);

		T FindOne(Expression<Func<T, bool>> predicate);

		T FindOne(Query query);

		IEnumerable<T> FindAll();

		bool Delete(BsonValue id);

		int DeleteAll();

		int DeleteMany(BsonExpression predicate);

		int DeleteMany(string predicate, BsonDocument parameters);

		int DeleteMany(string predicate, params BsonValue[] args);

		int DeleteMany(Expression<Func<T, bool>> predicate);

		int Count();

		int Count(BsonExpression predicate);

		int Count(string predicate, BsonDocument parameters);

		int Count(string predicate, params BsonValue[] args);

		int Count(Expression<Func<T, bool>> predicate);

		int Count(Query query);

		long LongCount();

		long LongCount(BsonExpression predicate);

		long LongCount(string predicate, BsonDocument parameters);

		long LongCount(string predicate, params BsonValue[] args);

		long LongCount(Expression<Func<T, bool>> predicate);

		long LongCount(Query query);

		bool Exists(BsonExpression predicate);

		bool Exists(string predicate, BsonDocument parameters);

		bool Exists(string predicate, params BsonValue[] args);

		bool Exists(Expression<Func<T, bool>> predicate);

		bool Exists(Query query);

		BsonValue Min(BsonExpression keySelector);

		BsonValue Min();

		K Min<K>(Expression<Func<T, K>> keySelector);

		BsonValue Max(BsonExpression keySelector);

		BsonValue Max();

		K Max<K>(Expression<Func<T, K>> keySelector);
	}
	public interface ILiteDatabase : IDisposable
	{
		BsonMapper Mapper { get; }

		ILiteStorage<string> FileStorage { get; }

		int UserVersion { get; set; }

		TimeSpan Timeout { get; set; }

		bool UtcDate { get; set; }

		long LimitSize { get; set; }

		int CheckpointSize { get; set; }

		Collation Collation { get; }

		ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId);

		ILiteCollection<T> GetCollection<T>();

		ILiteCollection<T> GetCollection<T>(BsonAutoId autoId);

		ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId);

		bool BeginTrans();

		bool Commit();

		bool Rollback();

		ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks");

		IEnumerable<string> GetCollectionNames();

		bool CollectionExists(string name);

		bool DropCollection(string name);

		bool RenameCollection(string oldName, string newName);

		IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null);

		IBsonDataReader Execute(string command, BsonDocument parameters = null);

		IBsonDataReader Execute(string command, params BsonValue[] args);

		void Checkpoint();

		long Rebuild(RebuildOptions options = null);

		BsonValue Pragma(string name);

		BsonValue Pragma(string name, BsonValue value);
	}
	public interface ILiteQueryable<T> : ILiteQueryableResult<T>
	{
		ILiteQueryable<T> Include(BsonExpression path);

		ILiteQueryable<T> Include(List<BsonExpression> paths);

		ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path);

		ILiteQueryable<T> Where(BsonExpression predicate);

		ILiteQueryable<T> Where(string predicate, BsonDocument parameters);

		ILiteQueryable<T> Where(string predicate, params BsonValue[] args);

		ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate);

		ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1);

		ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1);

		ILiteQueryable<T> OrderByDescending(BsonExpression keySelector);

		ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector);

		ILiteQueryable<T> GroupBy(BsonExpression keySelector);

		ILiteQueryable<T> Having(BsonExpression predicate);

		ILiteQueryableResult<BsonDocument> Select(BsonExpression selector);

		ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector);
	}
	public interface ILiteQueryableResult<T>
	{
		ILiteQueryableResult<T> Limit(int limit);

		ILiteQueryableResult<T> Skip(int offset);

		ILiteQueryableResult<T> Offset(int offset);

		ILiteQueryableResult<T> ForUpdate();

		BsonDocument GetPlan();

		IBsonDataReader ExecuteReader();

		IEnumerable<BsonDocument> ToDocuments();

		IEnumerable<T> ToEnumerable();

		List<T> ToList();

		T[] ToArray();

		int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId);

		T First();

		T FirstOrDefault();

		T Single();

		T SingleOrDefault();

		int Count();

		long LongCount();

		bool Exists();
	}
	public interface ILiteRepository : IDisposable
	{
		ILiteDatabase Database { get; }

		BsonValue Insert<T>(T entity, string collectionName = null);

		int Insert<T>(IEnumerable<T> entities, string collectionName = null);

		bool Update<T>(T entity, string collectionName = null);

		int Update<T>(IEnumerable<T> entities, string collectionName = null);

		bool Upsert<T>(T entity, string collectionName = null);

		int Upsert<T>(IEnumerable<T> entities, string collectionName = null);

		bool Delete<T>(BsonValue id, string collectionName = null);

		int DeleteMany<T>(BsonExpression predicate, string collectionName = null);

		int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		ILiteQueryable<T> Query<T>(string collectionName = null);

		bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null);

		bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null);

		bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null);

		bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null);

		T SingleById<T>(BsonValue id, string collectionName = null);

		List<T> Fetch<T>(BsonExpression predicate, string collectionName = null);

		List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T First<T>(BsonExpression predicate, string collectionName = null);

		T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null);

		T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T Single<T>(BsonExpression predicate, string collectionName = null);

		T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null);

		T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null);
	}
	public class LiteDatabase : ILiteDatabase, IDisposable
	{
		private readonly ILiteEngine _engine;

		private readonly BsonMapper _mapper;

		private readonly bool _disposeOnClose;

		private ILiteStorage<string> _fs;

		public BsonMapper Mapper => _mapper;

		public ILiteStorage<string> FileStorage => _fs ?? (_fs = GetStorage<string>());

		public int UserVersion
		{
			get
			{
				return _engine.Pragma("USER_VERSION");
			}
			set
			{
				_engine.Pragma("USER_VERSION", value);
			}
		}

		public TimeSpan Timeout
		{
			get
			{
				return TimeSpan.FromSeconds(_engine.Pragma("TIMEOUT").AsInt32);
			}
			set
			{
				_engine.Pragma("TIMEOUT", (int)value.TotalSeconds);
			}
		}

		public bool UtcDate
		{
			get
			{
				return _engine.Pragma("UTC_DATE");
			}
			set
			{
				_engine.Pragma("UTC_DATE", value);
			}
		}

		public long LimitSize
		{
			get
			{
				return _engine.Pragma("LIMIT_SIZE");
			}
			set
			{
				_engine.Pragma("LIMIT_SIZE", value);
			}
		}

		public int CheckpointSize
		{
			get
			{
				return _engine.Pragma("CHECKPOINT");
			}
			set
			{
				_engine.Pragma("CHECKPOINT", value);
			}
		}

		public Collation Collation => new Collation(_engine.Pragma("COLLATION").AsString);

		public LiteDatabase(string connectionString, BsonMapper mapper = null)
			: this(new ConnectionString(connectionString), mapper)
		{
		}

		public LiteDatabase(ConnectionString connectionString, BsonMapper mapper = null)
		{
			if (connectionString == null)
			{
				throw new ArgumentNullException("connectionString");
			}
			_engine = connectionString.CreateEngine();
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = true;
		}

		public LiteDatabase(Stream stream, BsonMapper mapper = null, Stream logStream = null)
		{
			EngineSettings settings = new EngineSettings
			{
				DataStream = (stream ?? throw new ArgumentNullException("stream")),
				LogStream = logStream
			};
			_engine = new LiteEngine(settings);
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = true;
		}

		public LiteDatabase(ILiteEngine engine, BsonMapper mapper = null, bool disposeOnClose = true)
		{
			_engine = engine ?? throw new ArgumentNullException("engine");
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = disposeOnClose;
		}

		public ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			return new LiteCollection<T>(name, autoId, _engine, _mapper);
		}

		public ILiteCollection<T> GetCollection<T>()
		{
			return GetCollection<T>(null);
		}

		public ILiteCollection<T> GetCollection<T>(BsonAutoId autoId)
		{
			return GetCollection<T>(null, autoId);
		}

		public ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return new LiteCollection<BsonDocument>(name, autoId, _engine, _mapper);
		}

		public bool BeginTrans()
		{
			return _engine.BeginTrans();
		}

		public bool Commit()
		{
			return _engine.Commit();
		}

		public bool Rollback()
		{
			return _engine.Rollback();
		}

		public ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks")
		{
			return new LiteStorage<TFileId>(this, filesCollection, chunksCollection);
		}

		public IEnumerable<string> GetCollectionNames()
		{
			return (from x in GetCollection("$cols").Query().Where("type = 'user'").ToDocuments()
				select x["name"].AsString).ToArray();
		}

		public bool CollectionExists(string name)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return GetCollectionNames().Contains<string>(name, StringComparer.OrdinalIgnoreCase);
		}

		public bool DropCollection(string name)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return _engine.DropCollection(name);
		}

		public bool RenameCollection(string oldName, string newName)
		{
			if (oldName.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("oldName");
			}
			if (newName.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("newName");
			}
			return _engine.RenameCollection(oldName, newName);
		}

		public IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null)
		{
			if (commandReader == null)
			{
				throw new ArgumentNullException("commandReader");
			}
			Tokenizer tokenizer = new Tokenizer(commandReader);
			return new SqlParser(_engine, tokenizer, parameters).Execute();
		}

		public IBsonDataReader Execute(string command, BsonDocument parameters = null)
		{
			if (command == null)
			{
				throw new ArgumentNullException("command");
			}
			Tokenizer tokenizer = new Tokenizer(command);
			return new SqlParser(_engine, tokenizer, parameters).Execute();
		}

		public IBsonDataReader Execute(string command, params BsonValue[] args)
		{
			BsonDocument bsonDocument = new BsonDocument();
			int num = 0;
			foreach (BsonValue value in args)
			{
				bsonDocument[num.ToString()] = value;
				num++;
			}
			return Execute(command, bsonDocument);
		}

		public void Checkpoint()
		{
			_engine.Checkpoint();
		}

		public long Rebuild(RebuildOptions options = null)
		{
			return _engine.Rebuild(options ?? new RebuildOptions());
		}

		public BsonValue Pragma(string name)
		{
			return _engine.Pragma(name);
		}

		public BsonValue Pragma(string name, BsonValue value)
		{
			return _engine.Pragma(name, value);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		~LiteDatabase()
		{
			Dispose(disposing: false);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing && _disposeOnClose)
			{
				_engine.Dispose();
			}
		}
	}
	public class LiteQueryable<T> : ILiteQueryable<T>, ILiteQueryableResult<T>
	{
		protected readonly ILiteEngine _engine;

		protected readonly BsonMapper _mapper;

		protected readonly string _collection;

		protected readonly Query _query;

		private readonly bool _isSimpleType = Reflection.IsSimpleType(typeof(T));

		internal LiteQueryable(ILiteEngine engine, BsonMapper mapper, string collection, Query query)
		{
			_engine = engine;
			_mapper = mapper;
			_collection = collection;
			_query = query;
		}

		public ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path)
		{
			_query.Includes.Add(_mapper.GetExpression(path));
			return this;
		}

		public ILiteQueryable<T> Include(BsonExpression path)
		{
			_query.Includes.Add(path);
			return this;
		}

		public ILiteQueryable<T> Include(List<BsonExpression> paths)
		{
			_query.Includes.AddRange(paths);
			return this;
		}

		public ILiteQueryable<T> Where(BsonExpression predicate)
		{
			_query.Where.Add(predicate);
			return this;
		}

		public ILiteQueryable<T> Where(string predicate, BsonDocument parameters)
		{
			_query.Where.Add(BsonExpression.Create(predicate, parameters));
			return this;
		}

		public ILiteQueryable<T> Where(string predicate, params BsonValue[] args)
		{
			_query.Where.Add(BsonExpression.Create(predicate, args));
			return this;
		}

		public ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate)
		{
			return Where(_mapper.GetExpression(predicate));
		}

		public ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1)
		{
			if (_query.OrderBy != null)
			{
				throw new ArgumentException("ORDER BY already defined in this query builder");
			}
			_query.OrderBy = keySelector;
			_query.Order = order;
			return this;
		}

		public ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1)
		{
			return OrderBy(_mapper.GetExpression(keySelector), order);
		}

		public ILiteQueryable<T> OrderByDescending(BsonExpression keySelector)
		{
			return OrderBy(keySelector, -1);
		}

		public ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector)
		{
			return OrderBy(keySelector, -1);
		}

		public ILiteQueryable<T> GroupBy(BsonExpression keySelector)
		{
			if (_query.GroupBy != null)
			{
				throw new ArgumentException("GROUP BY already defined in this query");
			}
			_query.GroupBy = keySelector;
			return this;
		}

		public ILiteQueryable<T> Having(BsonExpression predicate)
		{
			if (_query.Having != null)
			{
				throw new ArgumentException("HAVING already defined in this query");
			}
			_query.Having = predicate;
			return this;
		}

		public ILiteQueryableResult<BsonDocument> Select(BsonExpression selector)
		{
			_query.Select = selector;
			return new LiteQueryable<BsonDocument>(_engine, _mapper, _collection, _query);
		}

		public ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector)
		{
			if (_query.GroupBy != null)
			{
				throw new ArgumentException("Use Select(BsonExpression selector) when using GroupBy query");
			}
			_query.Select = _mapper.GetExpression(selector);
			return new LiteQueryable<K>(_engine, _mapper, _collection, _query);
		}

		public ILiteQueryableResult<T> ForUpdate()
		{
			_query.ForUpdate = true;
			return this;
		}

		public ILiteQueryableResult<T> Offset(int offset)
		{
			_query.Offset = offset;
			return this;
		}

		public ILiteQueryableResult<T> Skip(int offset)
		{
			return Offset(offset);
		}

		public ILiteQueryableResult<T> Limit(int limit)
		{
			_query.Limit = limit;
			return this;
		}

		public IBsonDataReader ExecuteReader()
		{
			_query.ExplainPlan = false;
			return _engine.Query(_collection, _query);
		}

		public IEnumerable<BsonDocument> ToDocuments()
		{
			using IBsonDataReader reader = ExecuteReader();
			while (reader.Read())
			{
				yield return reader.Current as BsonDocument;
			}
		}

		public IEnumerable<T> ToEnumerable()
		{
			if (_isSimpleType)
			{
				return from x in ToDocuments()
					select x[x.Keys.First()] into x
					select (T)_mapper.Deserialize(typeof(T), x);
			}
			return from x in ToDocuments()
				select (T)_mapper.Deserialize(typeof(T), x);
		}

		public List<T> ToList()
		{
			return ToEnumerable().ToList();
		}

		public T[] ToArray()
		{
			return ToEnumerable().ToArray();
		}

		public BsonDocument GetPlan()
		{
			_query.ExplainPlan = true;
			return _engine.Query(_collection, _query).ToEnumerable().FirstOrDefault()?.AsDocument;
		}

		public T Single()
		{
			return ToEnumerable().Single();
		}

		public T SingleOrDefault()
		{
			return ToEnumerable().SingleOrDefault();
		}

		public T First()
		{
			return ToEnumerable().First();
		}

		public T FirstOrDefault()
		{
			return ToEnumerable().FirstOrDefault();
		}

		public int Count()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ count: COUNT(*._id) }");
				return ToDocuments().Single()["count"].AsInt32;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public long LongCount()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ count: COUNT(*._id) }");
				return ToDocuments().Single()["count"].AsInt64;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public bool Exists()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ exists: ANY(*._id) }");
				return ToDocuments().Single()["exists"].AsBoolean;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			_query.Into = newCollection;
			_query.IntoAutoId = autoId;
			using IBsonDataReader bsonDataReader = ExecuteReader();
			return bsonDataReader.Current.AsInt32;
		}
	}
	public class LiteRepository : ILiteRepository, IDisposable
	{
		private readonly ILiteDatabase _db;

		public ILiteDatabase Database => _db;

		public LiteRepository(ILiteDatabase database)
		{
			_db = database;
		}

		public LiteRepository(string connectionString, BsonMapper mapper = null)
		{
			_db = new LiteDatabase(connectionString, mapper);
		}

		public LiteRepository(ConnectionString connectionString, BsonMapper mapper = null)
		{
			_db = new LiteDatabase(connectionString, mapper);
		}

		public LiteRepository(Stream stream, BsonMapper mapper = null, Stream logStream = null)
		{
			_db = new LiteDatabase(stream, mapper, logStream);
		}

		public BsonValue Insert<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Insert(entity);
		}

		public int Insert<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Insert(entities);
		}

		public bool Update<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Update(entity);
		}

		public int Update<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Update(entities);
		}

		public bool Upsert<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Upsert(entity);
		}

		public int Upsert<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Upsert(entities);
		}

		public bool Delete<T>(BsonValue id, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Delete(id);
		}

		public int DeleteMany<T>(BsonExpression predicate, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).DeleteMany(predicate);
		}

		public int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).DeleteMany(predicate);
		}

		public ILiteQueryable<T> Query<T>(string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Query();
		}

		public bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(name, expression, unique);
		}

		public bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(expression, unique);
		}

		public bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(keySelector, unique);
		}

		public bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(name, keySelector, unique);
		}

		public T SingleById<T>(BsonValue id, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Query().Where("_id = @0", id)
				.Single();
		}

		public List<T> Fetch<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).ToList();
		}

		public List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).ToList();
		}

		public T First<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).First();
		}

		public T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).First();
		}

		public T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).FirstOrDefault();
		}

		public T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).FirstOrDefault();
		}

		public T Single<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).Single();
		}

		public T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).Single();
		}

		public T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).SingleOrDefault();
		}

		public T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).SingleOrDefault();
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		~LiteRepository()
		{
			Dispose(disposing: false);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				_db.Dispose();
			}
		}
	}
	public class BsonCtorAttribute : Attribute
	{
	}
	public class BsonFieldAttribute : Attribute
	{
		public string Name { get; set; }

		public BsonFieldAttribute(string name)
		{
			Name = name;
		}

		public BsonFieldAttribute()
		{
		}
	}
	public class BsonIdAttribute : Attribute
	{
		public bool AutoId { get; private set; }

		public BsonIdAttribute()
		{
			AutoId = true;
		}

		public BsonIdAttribute(bool autoId)
		{
			AutoId = autoId;
		}
	}
	public class BsonIgnoreAttribute : Attribute
	{
	}
	public class BsonRefAttribute : Attribute
	{
		public string Collection { get; set; }

		public BsonRefAttribute(string collection)
		{
			Collection = collection;
		}

		public BsonRefAttribute()
		{
			Collection = null;
		}
	}
	public class BsonMapper
	{
		public delegate BsonValue DeserializationCallback(BsonMapper sender, Type target, BsonValue value);

		private readonly Dictionary<Type, EntityMapper> _entities = new Dictionary<Type, EntityMapper>();

		private readonly ConcurrentDictionary<Type, Func<object, BsonValue>> _customSerializer = new ConcurrentDictionary<Type, Func<object, BsonValue>>();

		private readonly ConcurrentDictionary<Type, Func<BsonValue, object>> _customDeserializer = new ConcurrentDictionary<Type, Func<BsonValue, object>>();

		private readonly Func<Type, object> _typeInstantiator;

		private readonly ITypeNameBinder _typeNameBinder;

		public static BsonMapper Global = new BsonMapper();

		public Func<string, string> ResolveFieldName;

		public Action<Type, MemberInfo, MemberMapper> ResolveMember;

		public Func<Type, string> ResolveCollectionName;

		private readonly Regex _lowerCaseDelimiter = new Regex("(?!(^[A-Z]))([A-Z])", RegexOptions.Compiled);

		private readonly HashSet<Type> _bsonTypes = new HashSet<Type>
		{
			typeof(string),
			typeof(int),
			typeof(long),
			typeof(bool),
			typeof(Guid),
			typeof(DateTime),
			typeof(byte[]),
			typeof(ObjectId),
			typeof(double),
			typeof(decimal)
		};

		private readonly HashSet<Type> _basicTypes = new HashSet<Type>
		{
			typeof(short),
			typeof(ushort),
			typeof(uint),
			typeof(float),
			typeof(char),
			typeof(byte),
			typeof(sbyte)
		};

		public bool SerializeNullValues { get; set; }

		public bool TrimWhitespace { get; set; }

		public bool EmptyStringToNull { get; set; }

		public bool EnumAsInteger { get; set; }

		public bool IncludeFields { get; set; }

		public bool IncludeNonPublic { get; set; }

		public int MaxDepth { get; set; }

		public DeserializationCallback? OnDeserialization { get; set; }

		public BsonMapper(Func<Type, object> customTypeInstantiator = null, ITypeNameBinder typeNameBinder = null)
		{
			SerializeNullValues = false;
			TrimWhitespace = true;
			EmptyStringToNull = true;
			EnumAsInteger = false;
			ResolveFieldName = (string s) => s;
			ResolveMember = delegate
			{
			};
			ResolveCollectionName = (Type t) => (!Reflection.IsEnumerable(t)) ? t.Name : Reflection.GetListItemType(t).Name;
			IncludeFields = false;
			MaxDepth = 20;
			_typeInstantiator = customTypeInstantiator ?? ((Func<Type, object>)((Type t) => null));
			_typeNameBinder = typeNameBinder ?? DefaultTypeNameBinder.Instance;
			RegisterType((Uri uri) => uri.IsAbsoluteUri ? uri.AbsoluteUri : uri.ToString(), (BsonValue bson) => new Uri(bson.AsString));
			RegisterType((DateTimeOffset value) => new BsonValue(value.UtcDateTime), (BsonValue bson) => bson.AsDateTime.ToUniversalTime());
			RegisterType((TimeSpan value) => new BsonValue(value.Ticks), (BsonValue bson) => new TimeSpan(bson.AsInt64));
			RegisterType((Regex r) => (r.Options != 0) ? new BsonDocument
			{
				{
					"p",
					r.ToString()
				},
				{
					"o",
					(int)r.Options
				}
			} : new BsonValue(r.ToString()), (BsonValue value) => (!value.IsString) ? new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32) : new Regex(value));
		}

		public void RegisterType<T>(Func<T, BsonValue> serialize, Func<BsonValue, T> deserialize)
		{
			_customSerializer[typeof(T)] = (object o) => serialize((T)o);
			_customDeserializer[typeof(T)] = (BsonValue b) => deserialize(b);
		}

		public void RegisterType(Type type, Func<object, BsonValue> serialize, Func<BsonValue, object> deserialize)
		{
			_customSerializer[type] = (object o) => serialize(o);
			_customDeserializer[type] = (BsonValue b) => deserialize(b);
		}

		public EntityBuilder<T> Entity<T>()
		{
			return new EntityBuilder<T>(this, _typeNameBinder);
		}

		public BsonExpression GetExpression<T, K>(Expression<Func<T, K>> predicate)
		{
			return new LinqExpressionVisitor(this, predicate).Resolve(typeof(K) == typeof(bool));
		}

		public BsonExpression GetIndexExpression<T, K>(Expression<Func<T, K>> predicate)
		{
			return new LinqExpressionVisitor(this, predicate).Resolve(predicate: false);
		}

		public BsonMapper UseCamelCase()
		{
			ResolveFieldName = (string s) => char.ToLower(s[0]) + s.Substring(1);
			return this;
		}

		public BsonMapper UseLowerCaseDelimiter(char delimiter = '_')
		{
			ResolveFieldName = (string s) => _lowerCaseDelimiter.Replace(s, delimiter + "$2").ToLower();
			return this;
		}

		internal EntityMapper GetEntityMapper(Type type)
		{
			if (!_entities.TryGetValue(type, out var value))
			{
				lock (_entities)
				{
					if (!_entities.TryGetValue(type, out value))
					{
						return BuildAddEntityMapper(type);
					}
				}
			}
			return value;
		}

		protected virtual EntityMapper BuildAddEntityMapper(Type type)
		{
			EntityMapper entityMapper = new EntityMapper(type);
			_entities[type] = entityMapper;
			Type typeFromHandle = typeof(BsonIdAttribute);
			Type typeFromHandle2 = typeof(BsonIgnoreAttribute);
			Type typeFromHandle3 = typeof(BsonFieldAttribute);
			Type typeFromHandle4 = typeof(BsonRefAttribute);
			IEnumerable<MemberInfo> typeMembers = GetTypeMembers(type);
			MemberInfo idMember = GetIdMember(typeMembers);
			foreach (MemberInfo item in typeMembers)
			{
				if (!CustomAttributeExtensions.IsDefined(item, typeFromHandle2, inherit: true))
				{
					string name = ResolveFieldName(item.Name);
					BsonFieldAttribute bsonFieldAttribute = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle3, inherit: true).FirstOrDefault();
					if (bsonFieldAttribute != null && bsonFieldAttribute.Name != null)
					{
						name = bsonFieldAttribute.Name;
					}
					if (item == idMember)
					{
						name = "_id";
					}
					GenericGetter getter = Reflection.CreateGenericGetter(type, item);
					GenericSetter setter = Reflection.CreateGenericSetter(type, item);
					BsonIdAttribute bsonIdAttribute = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle, inherit: true).FirstOrDefault();
					Type type2 = ((item is PropertyInfo) ? (item as PropertyInfo).PropertyType : (item as FieldInfo).FieldType);
					bool flag = Reflection.IsEnumerable(type2);
					MemberMapper memberMapper = new MemberMapper
					{
						AutoId = (bsonIdAttribute?.AutoId ?? true),
						FieldName = name,
						MemberName = item.Name,
						DataType = type2,
						IsEnumerable = flag,
						UnderlyingType = (flag ? Reflection.GetListItemType(type2) : type2),
						Getter = getter,
						Setter = setter
					};
					BsonRefAttribute bsonRefAttribute = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle4, inherit: false).FirstOrDefault();
					if (bsonRefAttribute != null && item is PropertyInfo)
					{
						RegisterDbRef(this, memberMapper, _typeNameBinder, bsonRefAttribute.Collection ?? ResolveCollectionName((item as PropertyInfo).PropertyType));
					}
					ResolveMember?.Invoke(type, item, memberMapper);
					if (memberMapper.FieldName != null && !entityMapper.Members.Any((MemberMapper x) => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)) && !memberMapper.IsIgnore)
					{
						entityMapper.Members.Add(memberMapper);
					}
				}
			}
			return entityMapper;
		}

		protected virtual MemberInfo GetIdMember(IEnumerable<MemberInfo> members)
		{
			return Reflection.SelectMember(members, (MemberInfo x) => CustomAttributeExtensions.IsDefined(x, typeof(BsonIdAttribute), inherit: true), (MemberInfo x) => x.Name.Equals("Id", StringComparison.OrdinalIgnoreCase), (MemberInfo x) => x.Name.Equals(x.DeclaringType.Name + "Id", StringComparison.OrdinalIgnoreCase));
		}

		protected virtual IEnumerable<MemberInfo> GetTypeMembers(Type type)
		{
			List<MemberInfo> list = new List<MemberInfo>();
			BindingFlags bindingAttr = (IncludeNonPublic ? (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : (BindingFlags.Instance | BindingFlags.Public));
			list.AddRange((from x in type.GetProperties(bindingAttr)
				where x.CanRead && x.GetIndexParameters().Length == 0
				select x).Select((Func<PropertyInfo, MemberInfo>)((PropertyInfo x) => x)));
			if (IncludeFields)
			{
				list.AddRange((from x in type.GetFields(bindingAttr)
					where !x.Name.EndsWith("k__BackingField") && !x.IsStatic
					select x).Select((Func<FieldInfo, MemberInfo>)((FieldInfo x) => x)));
			}
			return list;
		}

		protected virtual CreateObject GetTypeCtor(EntityMapper mapper)
		{
			Type type = mapper.ForType;
			List<CreateObject> list = new List<CreateObject>();
			bool flag = false;
			ConstructorInfo[] constructors = type.GetConstructors();
			foreach (ConstructorInfo constructorInfo in constructors)
			{
				ParameterInfo[] parameters = constructorInfo.GetParameters();
				if (parameters.Length == 0)
				{
					flag = true;
					continue;
				}
				KeyValuePair<string, Type>[] paramMap = new KeyValuePair<string, Type>[parameters.Length];
				int j;
				for (j = 0; j < parameters.Length; j++)
				{
					ParameterInfo parameterInfo = parameters[j];
					MemberMapper memberMapper = null;
					foreach (MemberMapper member in mapper.Members)
					{
						if (member.MemberName.ToLower() == parameterInfo.Name.ToLower() && member.DataType == parameterInfo.ParameterType)
						{
							memberMapper = member;
							break;
						}
					}
					if (memberMapper == null)
					{
						break;
					}
					paramMap[j] = new KeyValuePair<string, Type>(memberMapper.FieldName, memberMapper.DataType);
				}
				if (j < parameters.Length)
				{
					continue;
				}
				CreateObject createObject = (BsonDocument value) => Activator.CreateInstance(type, paramMap.Select((KeyValuePair<string, Type> x) => Deserialize(x.Value, value[x.Key])).ToArray());
				if (constructorInfo.GetCustomAttribute<BsonCtorAttribute>() != null)
				{
					return createObject;
				}
				list.Add(createObject);
			}
			if (flag)
			{
				return null;
			}
			return list.FirstOrDefault();
		}

		internal static void RegisterDbRef(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			member.IsDbRef = true;
			if (member.IsEnumerable)
			{
				RegisterDbRefList(mapper, member, typeNameBinder, collection);
			}
			else
			{
				RegisterDbRefItem(mapper, member, typeNameBinder, collection);
			}
		}

		private static void RegisterDbRefItem(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			EntityMapper entity = mapper.GetEntityMapper(member.DataType);
			member.Serialize = delegate(object obj, BsonMapper m)
			{
				if (obj == null)
				{
					return BsonValue.Null;
				}
				object obj2 = (entity.Id ?? throw new LiteException(0, "There is no _id field mapped in your type: " + member.DataType.FullName)).Getter(obj);
				BsonDocument bsonDocument = new BsonDocument
				{
					["$id"] = m.Serialize(obj2.GetType(), obj2, 0),
					["$ref"] = collection
				};
				if (member.DataType != obj.GetType())
				{
					bsonDocument["$type"] = typeNameBinder.GetName(obj.GetType());
				}
				return bsonDocument;
			};
			member.Deserialize = delegate(BsonValue bson, BsonMapper m)
			{
				if (bson == null || !bson.IsDocument)
				{
					return null;
				}
				BsonDocument asDocument = bson.AsDocument;
				BsonValue value = asDocument["$id"];
				bool num = asDocument["$missing"] == true;
				bool flag = !asDocument.ContainsKey("$ref");
				if (num)
				{
					return null;
				}
				if (flag)
				{
					asDocument["_id"] = value;
					if (asDocument.ContainsKey("$type"))
					{
						asDocument["_type"] = bson["$type"];
					}
					return m.Deserialize(entity.ForType, asDocument);
				}
				return m.Deserialize(entity.ForType, asDocument.ContainsKey("$type") ? new BsonDocument
				{
					["_id"] = value,
					["_type"] = bson["$type"]
				} : new BsonDocument { ["_id"] = value });
			};
		}

		private static void RegisterDbRefList(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			EntityMapper entity = mapper.GetEntityMapper(member.UnderlyingType);
			member.Serialize = delegate(object list, BsonMapper m)
			{
				if (list == null)
				{
					return BsonValue.Null;
				}
				BsonArray bsonArray2 = new BsonArray();
				MemberMapper id = entity.Id;
				foreach (object item in (IEnumerable)list)
				{
					if (item != null)
					{
						object obj = id.Getter(item);
						BsonDocument bsonDocument2 = new BsonDocument
						{
							["$id"] = m.Serialize(obj.GetType(), obj, 0),
							["$ref"] = collection
						};
						if (member.UnderlyingType != item.GetType())
						{
							bsonDocument2["$type"] = typeNameBinder.GetName(item.GetType());
						}
						bsonArray2.Add(bsonDocument2);
					}
				}
				return bsonArray2;
			};
			member.Deserialize = delegate(BsonValue bson, BsonMapper m)
			{
				if (!bson.IsArray)
				{
					return null;
				}
				BsonArray asArray = bson.AsArray;
				if (asArray.Count == 0)
				{
					return m.Deserialize(member.DataType, asArray);
				}
				BsonArray bsonArray = new BsonArray();
				foreach (BsonValue item2 in asArray)
				{
					if (item2.IsDocument)
					{
						BsonDocument asDocument = item2.AsDocument;
						BsonValue value = asDocument["$id"];
						bool flag = asDocument["$missing"] == true;
						bool flag2 = !asDocument.ContainsKey("$ref");
						if (!flag)
						{
							if (flag2)
							{
								item2["_id"] = value;
								if (item2.AsDocument.ContainsKey("$type"))
								{
									item2["_type"] = item2["$type"];
								}
								bsonArray.Add(item2);
							}
							else
							{
								BsonDocument bsonDocument = new BsonDocument { ["_id"] = value };
								if (item2.AsDocument.ContainsKey("$type"))
								{
									bsonDocument["_type"] = item2["$type"];
								}
								bsonArray.Add(bsonDocument);
							}
						}
					}
				}
				return m.Deserialize(member.DataType, bsonArray);
			};
		}

		public virtual object ToObject(Type type, BsonDocument doc)
		{
			if (doc == null)
			{
				throw new ArgumentNullException("doc");
			}
			if (type == typeof(BsonDocument))
			{
				return doc;
			}
			return Deserialize(type, doc);
		}

		public virtual T ToObject<T>(BsonDocument doc)
		{
			return (T)ToObject(typeof(T), doc);
		}

		public T Deserialize<T>(BsonValue value)
		{
			if (value == null)
			{
				return default(T);
			}
			return (T)Deserialize(typeof(T), value);
		}

		public object Deserialize(Type type, BsonValue value)
		{
			if (OnDeserialization != null)
			{
				BsonValue bsonValue = OnDeserialization(this, type, value);
				if ((object)bsonValue != null)
				{
					value = bsonValue;
				}
			}
			if (value.IsNull)
			{
				return null;
			}
			if (Reflection.IsNullable(type))
			{
				type = Reflection.UnderlyingTypeOf(type);
			}
			if (_customDeserializer.TryGetValue(type, out var value2))
			{
				return value2(value);
			}
			TypeInfo typeInfo = type.GetTypeInfo();
			if (type == typeof(BsonValue))
			{
				return value;
			}
			if (type == typeof(BsonDocument))
			{
				return value.AsDocument;
			}
			if (type == typeof(BsonArray))
			{
				return value.AsArray;
			}
			if (_bsonTypes.Contains(type))
			{
				return value.RawValue;
			}
			if (_basicTypes.Contains(type))
			{
				return Convert.ChangeType(value.RawValue, type);
			}
			if (type == typeof(ulong))
			{
				return (ulong)value.AsInt64;
			}
			if (typeInfo.IsEnum)
			{
				if (value.IsString)
				{
					return Enum.Parse(type, value.AsString);
				}
				if (value.IsNumber)
				{
					return Enum.ToObject(type, value.AsInt32);
				}
			}
			else
			{
				if (value.IsArray)
				{
					if (type == typeof(object))
					{
						return DeserializeArray(typeof(object), value.AsArray);
					}
					if (type.IsArray)
					{
						return DeserializeArray(type.GetElementType(), value.AsArray);
					}
					return DeserializeList(type, value.AsArray);
				}
				if (value.IsDocument)
				{
					if (type.IsAnonymousType())
					{
						return DeserializeAnonymousType(type, value.AsDocument);
					}
					BsonDocument asDocument = value.AsDocument;
					if (asDocument.TryGetValue("_type", out var value3) && value3.IsString)
					{
						Type type2 = _typeNameBinder.GetType(value3.AsString);
						if (type2 == null)
						{
							throw LiteException.InvalidTypedName(value3.AsString);
						}
						if (!type.IsAssignableFrom(type2))
						{
							throw LiteException.DataTypeNotAssignable(type.FullName, type2.FullName);
						}
						type = type2;
					}
					else if (type == typeof(object))
					{
						type = typeof(Dictionary<string, object>);
					}
					EntityMapper entity = GetEntityMapper(type);
					if (entity.CreateInstance == null)
					{
						entity.CreateInstance = GetTypeCtor(entity) ?? ((CreateObject)((BsonDocument v) => Reflection.CreateInstance(entity.ForType)));
					}
					object obj = _typeInstantiator(type) ?? entity.CreateInstance(asDocument);
					if (obj is IDictionary dict)
					{
						if (obj.GetType().GetTypeInfo().IsGenericType)
						{
							Type k = type.GetGenericArguments()[0];
							Type t = type.GetGenericArguments()[1];
							DeserializeDictionary(k, t, dict, value.AsDocument);
						}
						else
						{
							DeserializeDictionary(typeof(object), typeof(object), dict, value.AsDocument);
						}
					}
					else
					{
						DeserializeObject(entity, obj, asDocument);
					}
					return obj;
				}
			}
			return value.RawValue;
		}

		private object DeserializeArray(Type type, BsonArray array)
		{
			Array array2 = Array.CreateInstance(type, array.Count);
			int num = 0;
			foreach (BsonValue item in array)
			{
				array2.SetValue(Deserialize(type, item), num++);
			}
			return array2;
		}

		private object DeserializeList(Type type, BsonArray value)
		{
			Type listItemType = Reflection.GetListItemType(type);
			IEnumerable enumerable = (IEnumerable)Reflection.CreateInstance(type);
			if (enumerable is IList list)
			{
				foreach (BsonValue item in value)
				{
					list.Add(Deserialize(listItemType, item));
				}
			}
			else
			{
				MethodInfo method = type.GetMethod("Add", new Type[1] { listItemType });
				foreach (BsonValue item2 in value)
				{
					method.Invoke(enumerable, new object[1] { Deserialize(listItemType, item2) });
				}
			}
			return enumerable;
		}

		private void DeserializeDictionary(Type K, Type T, IDictionary dict, BsonDocument value)
		{
			bool isEnum = K.GetTypeInfo().IsEnum;
			foreach (KeyValuePair<string, BsonValue> element in value.GetElements())
			{
				object key = (isEnum ? Enum.Parse(K, element.Key) : ((K == typeof(Uri)) ? new Uri(element.Key) : Convert.ChangeType(element.Key, K)));
				object value2 = Deserialize(T, element.Value);
				dict.Add(key, value2);
			}
		}

		private void DeserializeObject(EntityMapper entity, object obj, BsonDocument value)
		{
			foreach (MemberMapper item in entity.Members.Where((MemberMapper x) => x.Setter != null))
			{
				if (value.TryGetValue(item.FieldName, out var value2))
				{
					if (item.Deserialize != null)
					{
						item.Setter(obj, item.Deserialize(value2, this));
					}
					else
					{
						item.Setter(obj, Deserialize(item.DataType, value2));
					}
				}
			}
		}

		private object DeserializeAnonymousType(Type type, BsonDocument value)
		{
			List<object> list = new List<object>();
			ParameterInfo[] parameters = type.GetConstructors()[0].GetParameters();
			foreach (ParameterInfo parameterInfo in parameters)
			{
				object obj = Deserialize(parameterInfo.ParameterType, value[parameterInfo.Name]);
				if (obj == null && StringComparer.OrdinalIgnoreCase.Equals(parameterInfo.Name, "Id") && value.TryGetValue("_id", out var value2))
				{
					obj = Deserialize(parameterInfo.ParameterType, value2);
				}
				list.Add(obj);
			}
			return Activator.CreateInstance(type, list.ToArray());
		}

		public virtual BsonDocument ToDocument(Type type, object entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (entity is BsonDocument)
			{
				return (BsonDocument)entity;
			}
			return Serialize(type, entity, 0).AsDocument;
		}

		public virtual BsonDocument ToDocument<T>(T entity)
		{
			return ToDocument(typeof(T), entity)?.AsDocument;
		}

		public BsonValue Serialize<T>(T obj)
		{
			return Serialize(typeof(T), obj, 0);
		}

		public BsonValue Serialize(Type type, object obj)
		{
			return Serialize(type, obj, 0);
		}

		internal BsonValue Serialize(Type type, object obj, int depth)
		{
			if (++depth > MaxDepth)
			{
				throw LiteException.DocumentMaxDepth(MaxDepth, type);
			}
			if (obj == null)
			{
				return BsonValue.Null;
			}
			if (obj is BsonValue result)
			{
				return result;
			}
			if (_customSerializer.TryGetValue(type, out var value) || _customSerializer.TryGetValue(obj.GetType(), out value))
			{
				return value(obj);
			}
			if (obj is string)
			{
				string text = (TrimWhitespace ? (obj as string).Trim() : ((string)obj));
				if (EmptyStringToNull && text.Length == 0)
				{
					return BsonValue.Null;
				}
				return new BsonValue(text);
			}
			if (obj is int)
			{
				return new BsonValue((int)obj);
			}
			if (obj is long)
			{
				return new BsonValue((long)obj);
			}
			if (obj is double)
			{
				return new BsonValue((double)obj);
			}
			if (obj is decimal)
			{
				return new BsonValue((decimal)obj);
			}
			if (obj is byte[])
			{
				return new BsonValue((byte[])obj);
			}
			if (obj is ObjectId)
			{
				return new BsonValue((ObjectId)obj);
			}
			if (obj is Guid)
			{
				return new BsonValue((Guid)obj);
			}
			if (obj is bool)
			{
				return new BsonValue((bool)obj);
			}
			if (obj is DateTime)
			{
				return new BsonValue((DateTime)obj);
			}
			if (obj is short || obj is ushort || obj is byte || obj is sbyte)
			{
				return new BsonValue(Convert.ToInt32(obj));
			}
			if (obj is uint)
			{
				return new BsonValue(Convert.ToInt64(obj));
			}
			if (obj is ulong)
			{
				return new BsonValue((long)(ulong)obj);
			}
			if (obj is float)
			{
				return new BsonValue(Convert.ToDouble(obj));
			}
			if (obj is char)
			{
				return new BsonValue(obj.ToString());
			}
			if (obj is Enum)
			{
				if (EnumAsInteger)
				{
					return new BsonValue((int)obj);
				}
				return new BsonValue(obj.ToString());
			}
			if (obj is IDictionary dict)
			{
				if (type == typeof(object))
				{
					type = obj.GetType();
				}
				Type type2 = (type.GetTypeInfo().IsGenericType ? type.GetGenericArguments()[1] : typeof(object));
				return SerializeDictionary(type2, dict, depth);
			}
			if (obj is IEnumerable)
			{
				return SerializeArray(Reflection.GetListItemType(type), obj as IEnumerable, depth);
			}
			return SerializeObject(type, obj, depth);
		}

		private BsonArray SerializeArray(Type type, IEnumerable array, int depth)
		{
			BsonArray bsonArray = new BsonArray();
			foreach (object item in array)
			{
				bsonArray.Add(Serialize(type, item, depth));
			}
			return bsonArray;
		}

		private BsonDocument SerializeDictionary(Type type, IDictionary dict, int depth)
		{
			BsonDocument bsonDocument = new BsonDocument();
			foreach (object key in dict.Keys)
			{
				object obj = dict[key];
				string name = key.ToString();
				if (key is DateTime dateTime)
				{
					name = dateTime.ToString("o");
				}
				bsonDocument[name] = Serialize(type, obj, depth);
			}
			return bsonDocument;
		}

		private BsonDocument SerializeObject(Type type, object obj, int depth)
		{
			Type type2 = obj.GetType();
			BsonDocument bsonDocument = new BsonDocument();
			EntityMapper entityMapper = GetEntityMapper(type2);
			if (type != type2)
			{
				bsonDocument["_type"] = new BsonValue(_typeNameBinder.GetName(type2));
			}
			foreach (MemberMapper item in entityMapper.Members.Where((MemberMapper x) => x.Getter != null))
			{
				object obj2 = item.Getter(obj);
				if (obj2 != null || SerializeNullValues || !(item.FieldName != "_id"))
				{
					if (item.Serialize != null)
					{
						bsonDocument[item.FieldName] = item.Serialize(obj2, this);
					}
					else
					{
						bsonDocument[item.FieldName] = Serialize(item.DataType, obj2, depth);
					}
				}
			}
			return bsonDocument;
		}
	}
	public class EntityBuilder<T>
	{
		private readonly BsonMapper _mapper;

		private readonly EntityMapper _entity;

		private readonly ITypeNameBinder _typeNameBinder;

		internal EntityBuilder(BsonMapper mapper, ITypeNameBinder typeNameBinder)
		{
			_mapper = mapper;
			_typeNameBinder = typeNameBinder;
			_entity = mapper.GetEntityMapper(typeof(T));
		}

		public EntityBuilder<T> Ignore<K>(Expression<Func<T, K>> member)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				_entity.Members.Remove(p);
			});
		}

		public EntityBuilder<T> Field<K>(Expression<Func<T, K>> member, string field)
		{
			if (field.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("field");
			}
			return GetMember(member, delegate(MemberMapper p)
			{
				p.FieldName = field;
			});
		}

		public EntityBuilder<T> Id<K>(Expression<Func<T, K>> member, bool autoId = true)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				MemberMapper memberMapper = _entity.Members.FirstOrDefault((MemberMapper x) => x.FieldName == "_id");
				if (memberMapper != null)
				{
					memberMapper.FieldName = _mapper.ResolveFieldName(memberMapper.MemberName);
					memberMapper.AutoId = false;
				}
				p.FieldName = "_id";
				p.AutoId = autoId;
			});
		}

		public EntityBuilder<T> Ctor(Func<BsonDocument, T> createInstance)
		{
			_entity.CreateInstance = (BsonDocument v) => createInstance(v);
			return this;
		}

		public EntityBuilder<T> DbRef<K>(Expression<Func<T, K>> member, string collection = null)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				BsonMapper.RegisterDbRef(_mapper, p, _typeNameBinder, collection ?? _mapper.ResolveCollectionName(typeof(K)));
			});
		}

		private EntityBuilder<T> GetMember<TK, K>(Expression<Func<TK, K>> member, Action<MemberMapper> action)
		{
			if (member == null)
			{
				throw new ArgumentNullException("member");
			}
			MemberMapper member2 = _entity.GetMember(member);
			if (member2 == null)
			{
				throw new ArgumentNullException("Member '" + member.GetPath() + "' not found in type '" + _entity.ForType.Name + "' (use IncludeFields in BsonMapper)");
			}
			action(member2);
			return this;
		}
	}
	public class EntityMapper
	{
		public Type ForType { get; }

		public List<MemberMapper> Members { get; } = new List<MemberMapper>();


		public MemberMapper Id => Members.SingleOrDefault((MemberMapper x) => x.FieldName == "_id");

		public CreateObject CreateInstance { get; set; }

		public EntityMapper(Type forType)
		{
			ForType = forType;
		}

		public MemberMapper GetMember(Expression expr)
		{
			return Members.FirstOrDefault((MemberMapper x) => x.MemberName == expr.GetPath());
		}
	}
	internal class LinqExpressionVisitor : ExpressionVisitor
	{
		private static readonly Dictionary<Type, ITypeResolver> _resolver = new Dictionary<Type, ITypeResolver>
		{
			[typeof(BsonValue)] = new BsonValueResolver(),
			[typeof(BsonArray)] = new BsonValueResolver(),
			[typeof(BsonDocument)] = new BsonValueResolver(),
			[typeof(Convert)] = new ConvertResolver(),
			[typeof(DateTime)] = new DateTimeResolver(),
			[typeof(int)] = new NumberResolver("INT32"),
			[typeof(long)] = new NumberResolver("INT64"),
			[typeof(decimal)] = new NumberResolver("DECIMAL"),
			[typeof(double)] = new NumberResolver("DOUBLE"),
			[typeof(ICollection)] = new ICollectionResolver(),
			[typeof(Enumerable)] = new EnumerableResolver(),
			[typeof(Guid)] = new GuidResolver(),
			[typeof(Math)] = new MathResolver(),
			[typeof(Regex)] = new RegexResolver(),
			[typeof(ObjectId)] = new ObjectIdResolver(),
			[typeof(string)] = new StringResolver(),
			[typeof(Nullable)] = new NullableResolver()
		};

		private readonly BsonMapper _mapper;

		private readonly Expression _expr;

		private readonly ParameterExpression _rootParameter;

		private readonly BsonDocument _parameters = new BsonDocument();

		private int _paramIndex;

		private Type _dbRefType;

		private readonly StringBuilder _builder = new StringBuilder();

		private readonly Stack<Expression> _nodes = new Stack<Expression>();

		public LinqExpressionVisitor(BsonMapper mapper, Expression expr)
		{
			_mapper = mapper;
			_expr = expr;
			if (expr is LambdaExpression lambdaExpression)
			{
				_rootParameter = lambdaExpression.Parameters.First();
				return;
			}
			throw new NotSupportedException("Expression " + expr.ToString() + " must be a lambda expression");
		}

		public BsonExpression Resolve(bool predicate)
		{
			Visit(_expr);
			Constants.ENSURE(_nodes.Count == 0, "node stack must be empty when finish expression resolve");
			string text = _builder.ToString();
			try
			{
				BsonExpression bsonExpression = BsonExpression.Create(text, _parameters);
				if (predicate && (bsonExpression.Type == BsonExpressionType.Path || bsonExpression.Type == BsonExpressionType.Call || bsonExpression.Type == BsonExpressionType.Parameter))
				{
					text = "(" + text + " = true)";
					bsonExpression = BsonExpression.Create(text, _parameters);
				}
				return bsonExpression;
			}
			catch (Exception innerException)
			{
				throw new NotSupportedException("Invalid BsonExpression when converted from Linq expression: " + _expr.ToString() + " - `" + text + "`", innerException);
			}
		}

		protected override Expression VisitLambda<T>(Expression<T> node)
		{
			Expression result = base.VisitLambda(node);
			_builder.Length--;
			return result;
		}

		protected override Expression VisitInvocation(InvocationExpression node)
		{
			Expression result = base.VisitInvocation(node);
			_builder.Length--;
			return result;
		}

		protected override Expression VisitParameter(ParameterExpression node)
		{
			_builder.Append(_rootParameter.Equals(node) ? "$" : "@");
			return base.VisitParameter(node);
		}

		protected override Expression VisitMember(MemberExpression node)
		{
			bool flag = ParameterExpressionVisitor.Test(node);
			MemberInfo member = node.Member;
			if (TryGetResolver(member.DeclaringType, out var typeResolver))
			{
				string text = typeResolver.ResolveMember(member);
				if (text == null)
				{
					throw new NotSupportedException("Member " + member.Name + " are not support in " + member.DeclaringType.Name + " when convert to BsonExpression (" + node.ToString() + ").");
				}
				ResolvePattern(text, node.Expression, new Expression[0]);
			}
			else if (node.Expression != null)
			{
				_nodes.Push(node);
				base.Visit(node.Expression);
				if (flag)
				{
					string value = ResolveMember(member);
					_builder.Append(value);
				}
			}
			else
			{
				object value2 = Evaluate(node);
				base.Visit(Expression.Constant(value2));
			}
			if (_nodes.Count > 0)
			{
				_nodes.Pop();
			}
			return node;
		}

		protected override Expression VisitMethodCall(MethodCallExpression node)
		{
			if (IsMethodIndexEval(node, out var obj, out var idx))
			{
				Visit(obj);
				object obj2 = Evaluate(idx, typeof(string), typeof(int));
				if (obj2 is string)
				{
					_builder.Append(".");
					_builder.Append($"['{obj2}']");
				}
				else
				{
					_builder.Append($"[{obj2}]");
				}
				return node;
			}
			if (!TryGetResolver(node.Method.DeclaringType, out var typeResolver))
			{
				if (ParameterExpressionVisitor.Test(node))
				{
					throw new NotSupportedException("Method " + node.Method.Name + " not available to convert to BsonExpression (" + node.ToString() + ").");
				}
				object value = Evaluate(node);
				base.Visit(Expression.Constant(value));
				return node;
			}
			string text = typeResolver.ResolveMethod(node.Method);
			if (text == null)
			{
				throw new NotSupportedException("Method " + Reflection.MethodName(node.Method) + " in " + node.Method.DeclaringType.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ").");
			}
			ResolvePattern(text, node.Object, node.Arguments);
			return node;
		}

		protected override Expression VisitConstant(ConstantExpression node)
		{
			object value = node.Value;
			while (_nodes.Count > 0 && _nodes.Peek() is MemberExpression memberExpression)
			{
				if (memberExpression.Member is FieldInfo fieldInfo)
				{
					value = fieldInfo.GetValue(value);
				}
				else if (memberExpression.Member is PropertyInfo propertyInfo)
				{
					value = propertyInfo.GetValue(value);
				}
				_nodes.Pop();
			}
			Constants.ENSURE(_nodes.Count == 0, "counter stack must be zero to eval all properties/field over object");
			string text = "p" + _paramIndex++;
			_builder.AppendFormat("@" + text);
			Type type = value?.GetType();
			BsonValue value2 = ((type == null) ? BsonValue.Null : ((type == typeof(string)) ? new BsonValue((string)value) : _mapper.Serialize(value.GetType(), value)));
			_parameters[text] = value2;
			return node;
		}

		protected override Expression VisitUnary(UnaryExpression node)
		{
			if (node.NodeType == ExpressionType.Not)
			{
				if (node.Operand.NodeType == ExpressionType.MemberAccess)
				{
					_builder.Append("(");
					Visit(node.Operand);
					_builder.Append(" = false)");
				}
				else
				{
					_builder.Append("(");
					Visit(node.Operand);
					_builder.Append(")");
					_builder.Append(" = false");
				}
			}
			else if (node.NodeType == ExpressionType.Convert)
			{
				Type fromType = node.Operand.Type;
				Type type = node.Type;
				if ((fromType == typeof(double) || fromType == typeof(decimal)) && (type == typeof(int) || type == typeof(long)))
				{
					string methodName = "To" + type.Name.ToString();
					MethodInfo methodInfo = (from x in typeof(Convert).GetMethods()
						where x.Name == methodName
						where x.GetParameters().Length == 1 && x.GetParameters().Any((ParameterInfo z) => z.ParameterType == fromType)
						select x).FirstOrDefault();
					if (methodInfo == null)
					{
						throw new NotSupportedException("Cast from " + fromType.Name + " are not supported when convert to BsonExpression");
					}
					MethodCallExpression node2 = Expression.Call(null, methodInfo, node.Operand);
					VisitMethodCall(node2);
				}
				else
				{
					base.VisitUnary(node);
				}
			}
			else if (node.NodeType == ExpressionType.ArrayLength)
			{
				_builder.Append("LENGTH(");
				Visit(node.Operand);
				_builder.Append(")");
			}
			else
			{
				base.VisitUnary(node);
			}
			return node;
		}

		protected override Expression VisitNew(NewExpression node)
		{
			if (node.Members == null)
			{
				if (!TryGetResolver(node.Type, out var typeResolver))
				{
					throw new NotSupportedException($"New instance are not supported for {node.Type} when convert to BsonExpression ({node.ToString()}).");
				}
				string text = typeResolver.ResolveCtor(node.Constructor);
				if (text == null)
				{
					throw new NotSupportedException("Constructor for " + node.Type.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ").");
				}
				ResolvePattern(text, null, node.Arguments);
			}
			else
			{
				_builder.Append("{ ");
				for (int i = 0; i < node.Members.Count; i++)
				{
					MemberInfo memberInfo = node.Members[i];
					_builder.Append((i > 0) ? ", " : "");
					_builder.AppendFormat("'{0}': ", memberInfo.Name);
					Visit(node.Arguments[i]);
				}
				_builder.Append(" }");
			}
			return node;
		}

		protected override Expression VisitMemberInit(MemberInitExpression node)
		{
			if (node.NewExpression.Constructor.GetParameters().Length != 0)
			{
				throw new NotSupportedException($"New instance of {node.Type} are not supported because contains ctor with parameter. Try use only property initializers: `new {node.Type.Name} {{ PropA = 1, PropB == \"John\" }}`.");
			}
			_builder.Append("{");
			for (int i = 0; i < node.Bindings.Count; i++)
			{
				MemberAssignment memberAssignment = node.Bindings[i] as MemberAssignment;
				string text = ResolveMember(memberAssignment.Member);
				_builder.Append((i > 0) ? ", " : "");
				_builder.Append(text.Substring(1));
				_builder.Append(":");
				Visit(memberAssignment.Expression);
			}
			_builder.Append("}");
			return node;
		}

		protected override Expression VisitNewArray(NewArrayExpression node)
		{
			_builder.Append("[ ");
			for (int i = 0; i < node.Expressions.Count; i++)
			{
				_builder.Append((i > 0) ? ", " : "");
				Visit(node.Expressions[i]);
			}
			_builder.Append(" ]");
			return node;
		}

		protected override Expression VisitBinary(BinaryExpression node)
		{
			bool ensurePredicate = node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse;
			if (node.NodeType == ExpressionType.Coalesce)
			{
				return VisitCoalesce(node);
			}
			if (node.NodeType == ExpressionType.ArrayIndex)
			{
				return VisitArrayIndex(node);
			}
			string @operator = GetOperator(node.NodeType);
			_builder.Append("(");
			VisitAsPredicate(node.Left, ensurePredicate);
			_builder.Append(@operator);
			if (!_mapper.EnumAsInteger && node.Left.NodeType == ExpressionType.Convert && node.Left is UnaryExpression unaryExpression && unaryExpression.Operand.Type.GetTypeInfo().IsEnum && unaryExpression.Type == typeof(int))
			{
				VisitAsPredicate(Expression.Constant(Enum.GetName(unaryExpression.Operand.Type, Evaluate(node.Right))), ensurePredicate);
			}
			else
			{
				VisitAsPredicate(node.Right, ensurePredicate);
			}
			_builder.Append(")");
			return node;
		}

		protected override Expression VisitConditional(ConditionalExpression node)
		{
			_builder.Append("IIF(");
			Visit(node.Test);
			_builder.Append(", ");
			Visit(node.IfTrue);
			_builder.Append(", ");
			Visit(node.IfFalse);
			_builder.Append(")");
			return node;
		}

		private Expression VisitCoalesce(BinaryExpression node)
		{
			_builder.Append("COALESCE(");
			Visit(node.Left);
			_builder.Append(", ");
			Visit(node.Right);
			_builder.Append(")");
			return node;
		}

		private Expression VisitArrayIndex(BinaryExpression node)
		{
			Visit(node.Left);
			_builder.Append("[");
			object value = Evaluate(node.Right, typeof(int));
			_builder.Append(value);
			_builder.Append("]");
			return node;
		}

		private void ResolvePattern(string pattern, Expression obj, IList<Expression> args)
		{
			Tokenizer tokenizer = new Tokenizer(pattern);
			while (!tokenizer.EOF)
			{
				Token token = tokenizer.ReadToken(eatWhitespace: false);
				if (token.Type == TokenType.Hashtag)
				{
					Visit(obj);
				}
				else if (token.Type == TokenType.At && tokenizer.LookAhead(eatWhitespace: false).Type == TokenType.Int)
				{
					int index = Convert.ToInt32(tokenizer.ReadToken(eatWhitespace: false).Expect(TokenType.Int).Value);
					Visit(args[index]);
				}
				else if (token.Type == TokenType.Percent)
				{
					VisitEnumerablePredicate(args[1] as LambdaExpression);
				}
				else
				{
					_builder.Append((token.Type == TokenType.String) ? ("'" + token.Value + "'") : token.Value);
				}
			}
		}

		private void VisitEnumerablePredicate(LambdaExpression lambda)
		{
			Expression body = lambda.Body;
			if (body is BinaryExpression binaryExpression)
			{
				if (binaryExpression.Left.NodeType != ExpressionType.Parameter)
				{
					throw new LiteException(0, "Any/All requires simple parameter on left side. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`");
				}
				string @operator = GetOperator(binaryExpression.NodeType);
				_builder.Append(@operator);
				VisitAsPredicate(binaryExpression.Right, ensurePredicate: false);
				return;
			}
			if (body is MethodCallExpression methodCallExpression)
			{
				if (methodCallExpression.Object.NodeType != ExpressionType.Parameter)
				{
					throw new NotSupportedException("Any/All requires simple parameter on left side. Eg: `x.Customers.Select(c => c.Name).Any(n => n.StartsWith('J'))`");
				}
				if (!TryGetResolver(methodCallExpression.Method.DeclaringType, out var typeResolver))
				{
					throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call.");
				}
				string text = typeResolver.ResolveMethod(methodCallExpression.Method);
				if (text == null || !text.StartsWith("#"))
				{
					throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call.");
				}
				ResolvePattern(text.Substring(1), methodCallExpression.Object, methodCallExpression.Arguments);
				return;
			}
			throw new LiteException(0, "When using Any/All method test do only simple predicate variable. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`");
		}

		private string GetOperator(ExpressionType nodeType)
		{
			return nodeType switch
			{
				ExpressionType.Add => " + ", 
				ExpressionType.Multiply => " * ", 
				ExpressionType.Subtract => " - ", 
				ExpressionType.Divide => " / ", 
				ExpressionType.Equal => " = ", 
				ExpressionType.NotEqual => " != ", 
				ExpressionType.GreaterThan => " > ", 
				ExpressionType.GreaterThanOrEqual => " >= ", 
				ExpressionType.LessThan => " < ", 
				ExpressionType.LessThanOrEqual => " <= ", 
				ExpressionType.And => " AND ", 
				ExpressionType.AndAlso => " AND ", 
				ExpressionType.Or => " OR ", 
				ExpressionType.OrElse => " OR ", 
				_ => throw new NotSupportedException($"Operator not supported {nodeType}"), 
			};
		}

		private string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			bool flag = _dbRefType != null && member.DeclaringType.IsAssignableFrom(_dbRefType);
			MemberMapper memberMapper = _mapper.GetEntityMapper(member.DeclaringType).Members.FirstOrDefault((MemberMapper x) => x.MemberName == name);
			if (memberMapper == null)
			{
				throw new NotSupportedException($"Member {name} not found on BsonMapper for type {member.DeclaringType}.");
			}
			_dbRefType = (memberMapper.IsDbRef ? memberMapper.UnderlyingType : null);
			return "." + ((flag && memberMapper.FieldName == "_id") ? "$id" : memberMapper.FieldName);
		}

		private bool IsMethodIndexEval(MethodCallExpression node, out Expression obj, out Expression idx)
		{
			MethodInfo method = node.Method;
			_ = method.DeclaringType;
			ParameterInfo[] parameters = method.GetParameters();
			if (method.Name == "get_Item" && parameters.Length == 1 && (parameters[0].ParameterType == typeof(int) || parameters[0].ParameterType == typeof(string)))
			{
				obj = node.Object;
				idx = node.Arguments[0];
				return true;
			}
			obj = null;
			idx = null;
			return false;
		}

		private void VisitAsPredicate(Expression expr, bool ensurePredicate)
		{
			ensurePredicate = ensurePredicate && (expr.NodeType == ExpressionType.MemberAccess || expr.NodeType == ExpressionType.Call || expr.NodeType == ExpressionType.Invoke || expr.NodeType == ExpressionType.Constant);
			if (ensurePredicate)
			{
				_builder.Append("(");
				_builder.Append("(");
				base.Visit(expr);
				_builder.Append(")");
				_builder.Append(" = true)");
			}
			else
			{
				base.Visit(expr);
			}
		}

		private object Evaluate(Expression expr, params Type[] validTypes)
		{
			object value = null;
			if (expr.NodeType == ExpressionType.Constant)
			{
				ConstantExpression constantExpression = (ConstantExpression)expr;
				value = constantExpression.Value;
			}
			else
			{
				Delegate @delegate = Expression.Lambda(expr).Compile();
				value = @delegate.DynamicInvoke();
			}
			if (validTypes.Length != 0 && value == null)
			{
				throw new NotSupportedException($"Expression {expr} can't return null value");
			}
			if (validTypes.Length != 0 && !validTypes.Any((Type x) => x == value.GetType()))
			{
				throw new NotSupportedException(string.Format("Expression {0} must return on of this types: {1}", expr, string.Join(", ", validTypes.Select((Type x) => "`" + x.Name + "`"))));
			}
			return value;
		}

		private bool TryGetResolver(Type declaringType, out ITypeResolver typeResolver)
		{
			bool num = Reflection.IsCollection(declaringType);
			bool flag = Reflection.IsEnumerable(declaringType);
			bool flag2 = Reflection.IsNullable(declaringType);
			Type key = (num ? typeof(ICollection) : (flag ? typeof(Enumerable) : (flag2 ? typeof(Nullable) : declaringType)));
			return _resolver.TryGetValue(key, out typeResolver);
		}
	}
	internal class ParameterExpressionVisitor : ExpressionVisitor
	{
		public bool IsParameter { get; private set; }

		protected override Expression VisitParameter(ParameterExpression node)
		{
			IsParameter = true;
			return base.VisitParameter(node);
		}

		public static bool Test(Expression node)
		{
			ParameterExpressionVisitor parameterExpressionVisitor = new ParameterExpressionVisitor();
			parameterExpressionVisitor.Visit(node);
			return parameterExpressionVisitor.IsParameter;
		}
	}
	internal class BsonValueResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			switch (member.Name)
			{
			case "AsInt32":
			case "AsInt64":
			case "AsArray":
			case "AsDateTime":
			case "AsDocument":
			case "AsObjectId":
			case "AsString":
			case "AsBinary":
			case "AsDouble":
			case "AsBoolean":
			case "AsDecimal":
			case "AsGuid":
				return "#";
			case "IsNull":
				return "IS_NULL(#)";
			case "IsArray":
				return "IS_ARRAY(#)";
			case "IsDocument":
				return "IS_DOCUMENT(#)";
			case "IsInt32":
				return "IS_INT32(#)";
			case "IsInt64":
				return "IS_INT64(#)";
			case "IsDouble":
				return "IS_DOUBLE(#)";
			case "IsDecimal":
				return "IS_DECIMAL(#)";
			case "IsNumber":
				return "IS_NUMBER(#)";
			case "IsBinary":
				return "IS_BINARY(#)";
			case "IsBoolean":
				return "IS_BOOLEAN(#)";
			case "IsString":
				return "IS_STRING(#)";
			case "IsObjectId":
				return "IS_OBJECTID(#)";
			case "IsGuid":
				return "IS_GUID(#)";
			case "IsDateTime":
				return "IS_DATETIME(#)";
			case "IsMinValue":
				return "IS_MINVALUE(#)";
			case "IsMaxValue":
				return "IS_MAXVALUE(#)";
			default:
				return null;
			}
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class ConvertResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return method.Name switch
			{
				"ToInt32" => "INT32(@0)", 
				"ToInt64" => "INT64(@0)", 
				"ToDouble" => "DOUBLE(@0)", 
				"ToDecimal" => "DECIMAL(@0)", 
				"ToDateTime" => "DATE(@0)", 
				"FromBase64String" => "BINARY(@0)", 
				"ToBoolean" => "BOOL(@0)", 
				"ToString" => "STRING(@0)", 
				_ => null, 
			};
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class DateTimeResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			switch (method.Name)
			{
			case "AddYears":
				return "DATEADD('y', @0, #)";
			case "AddMonths":
				return "DATEADD('M', @0, #)";
			case "AddDays":
				return "DATEADD('d', @0, #)";
			case "AddHours":
				return "DATEADD('h', @0, #)";
			case "AddMinutes":
				return "DATEADD('m', @0, #)";
			case "AddSeconds":
				return "DATEADD('s', @0, #)";
			case "ToString":
			{
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length == 0)
				{
					return "STRING(#)";
				}
				if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
				{
					return "FORMAT(#, @0)";
				}
				break;
			}
			case "ToUniversalTime":
				return "TO_UTC(#)";
			case "Parse":
				return "DATETIME(@0)";
			case "Equals":
				return "# = @0";
			}
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			return member.Name switch
			{
				"Now" => "NOW()", 
				"UtcNow" => "NOW_UTC()", 
				"Today" => "TODAY()", 
				"Year" => "YEAR(#)", 
				"Month" => "MONTH(#)", 
				"Day" => "DAY(#)", 
				"Hour" => "HOUR(#)", 
				"Minute" => "MINUTE(#)", 
				"Second" => "SECOND(#)", 
				"Date" => "DATETIME(YEAR(#), MONTH(#), DAY(#))", 
				"ToLocalTime" => "TO_LOCAL(#)", 
				"ToUniversalTime" => "TO_UTC(#)", 
				_ => null, 
			};
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 3 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(int))
			{
				return "DATETIME(@0, @1, @2)";
			}
			return null;
		}
	}
	internal class EnumerableResolver : ITypeResolver
	{
		public virtual string ResolveMethod(MethodInfo method)
		{
			switch (Reflection.MethodName(method, 1))
			{
			case "AsEnumerable()":
				return "@0[*]";
			case "get_Item(int)":
				return "#[@0]";
			case "ElementAt(int)":
				return "@0[@1]";
			case "Single()":
			case "First()":
			case "SingleOrDefault()":
			case "FirstOrDefault()":
				return "@0[0]";
			case "Last()":
			case "LastOrDefault()":
				return "@0[-1]";
			case "Single(Func<T,TResult>)":
			case "First(Func<T,TResult>)":
			case "SingleOrDefault(Func<T,TResult>)":
			case "FirstOrDefault(Func<T,TResult>)":
				return "FIRST(FILTER(@0 => @1))";
			case "Last(Func<T,TResult>)":
			case "LastOrDefault(Func<T,TResult>)":
				return "LAST(FILTER(@0 => @1))";
			case "Where(Func<T,TResult>)":
				return "FILTER(@0 => @1)";
			case "Select(Func<T,TResult>)":
				return "MAP(@0 => @1)";
			case "Count()":
				return "COUNT(@0)";
			case "Sum()":
				return "SUM(@0)";
			case "Average()":
				return "AVG(@0)";
			case "Max()":
				return "MAX(@0)";
			case "Min()":
				return "MIN(@0)";
			case "Count(Func<T,TResult>)":
				return "COUNT(FILTER(@0 => @1))";
			case "Sum(Func<T,TResult>)":
				return "SUM(MAP(@0 => @1))";
			case "Average(Func<T,TResult>)":
				return "AVG(MAP(@0 => @1))";
			case "Max(Func<T,TResult>)":
				return "MAX(MAP(@0 => @1))";
			case "Min(Func<T,TResult>)":
				return "MIN(MAP(@0 => @1))";
			case "ToList()":
			case "ToArray()":
				return "ARRAY(@0)";
			case "Any(Func<T,TResult>)":
				return "@0 ANY %";
			case "All(Func<T,TResult>)":
				return "@0 ALL %";
			case "Any()":
				return "COUNT(@0) > 0";
			default:
				if (method.Name == "Contains")
				{
					return "@0 ANY = @1";
				}
				return null;
			}
		}

		public virtual string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Length"))
			{
				if (name == "Count")
				{
					return "COUNT(#)";
				}
				return null;
			}
			return "LENGTH(#)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class GuidResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return method.Name switch
			{
				"ToString" => "STRING(#)", 
				"NewGuid" => "GUID()", 
				"Parse" => "GUID(@0)", 
				"TryParse" => throw new NotSupportedException("There is no TryParse translate. Use Guid.Parse()"), 
				"Equals" => "# = @0", 
				_ => null, 
			};
		}

		public string ResolveMember(MemberInfo member)
		{
			if (member.Name == "Empty")
			{
				return "GUID('00000000-0000-0000-0000-000000000000')";
			}
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
			{
				return "GUID(@0)";
			}
			return null;
		}
	}
	internal class ICollectionResolver : EnumerableResolver
	{
		public override string ResolveMethod(MethodInfo method)
		{
			if (method.Name == "Contains")
			{
				return "# ANY = @0";
			}
			return base.ResolveMethod(method);
		}
	}
	internal interface ITypeResolver
	{
		string ResolveMethod(MethodInfo method);

		string ResolveMember(MemberInfo member);

		string ResolveCtor(ConstructorInfo ctor);
	}
	internal class MathResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			int num = method.GetParameters().Length;
			switch (method.Name)
			{
			case "Abs":
				return "ABS(@0)";
			case "Pow":
				return "POW(@0, @1)";
			case "Round":
				if (num != 2)
				{
					throw new ArgumentOutOfRangeException("Method Round need 2 arguments when convert to BsonExpression");
				}
				return "ROUND(@0, @1)";
			default:
				return null;
			}
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class NullableResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "HasValue"))
			{
				if (name == "Value")
				{
					return "#";
				}
				return null;
			}
			return "(IS_NULL(#) = false)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class NumberResolver : ITypeResolver
	{
		private readonly string _parseMethod;

		public NumberResolver(string parseMethod)
		{
			_parseMethod = parseMethod;
		}

		public string ResolveMethod(MethodInfo method)
		{
			switch (method.Name)
			{
			case "ToString":
			{
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length == 0)
				{
					return "STRING(#)";
				}
				if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
				{
					return "FORMAT(#, @0)";
				}
				break;
			}
			case "Parse":
				return _parseMethod + "(@0)";
			case "Equals":
				return "# = @0";
			}
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class ObjectIdResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			string name = method.Name;
			if (!(name == "ToString"))
			{
				if (name == "Equals")
				{
					return "# = @0";
				}
				return null;
			}
			return "STRING(#)";
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Empty"))
			{
				if (name == "CreationTime")
				{
					return "OID_CREATIONTIME(#)";
				}
				return null;
			}
			return "OBJECTID('000000000000000000000000')";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
			{
				return "OBJECTID(@0)";
			}
			return null;
		}
	}
	internal class RegexResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			string name = method.Name;
			if (!(name == "Split"))
			{
				if (name == "IsMatch")
				{
					return "IS_MATCH(@0, @1)";
				}
				return null;
			}
			return "SPLIT(@0, @1, true)";
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class StringResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			int num = method.GetParameters().Length;
			switch (method.Name)
			{
			case "Count":
				return "LENGTH(#)";
			case "Trim":
				return "TRIM(#)";
			case "TrimStart":
				return "LTRIM(#)";
			case "TrimEnd":
				return "RTRIM(#)";
			case "ToUpper":
				return "UPPER(#)";
			case "ToUpperInvariant":
				return "UPPER(#)";
			case "ToLower":
				return "LOWER(#)";
			case "ToLowerInvariant":
				return "LOWER(#)";
			case "Replace":
				return "REPLACE(#, @0, @1)";
			case "PadLeft":
				return "LPAD(#, @0, @1)";
			case "RightLeft":
				return "RPAD(#, @0, @1)";
			case "IndexOf":
				if (num != 1)
				{
					return "INDEXOF(#, @0, @1)";
				}
				return "INDEXOF(#, @0)";
			case "Substring":
				if (num != 1)
				{
					return "SUBSTRING(#, @0, @1)";
				}
				return "SUBSTRING(#, @0)";
			case "StartsWith":
				return "# LIKE (@0 + '%')";
			case "Contains":
				return "# LIKE ('%' + @0 + '%')";
			case "EndsWith":
				return "# LIKE ('%' + @0)";
			case "ToString":
				return "#";
			case "Equals":
				return "# = @0";
			case "IsNullOrEmpty":
				return "(LENGTH(@0) = 0)";
			case "IsNullOrWhiteSpace":
				return "(LENGTH(TRIM(@0)) = 0)";
			case "Format":
				throw new NotImplementedException();
			case "Join":
				throw new NotImplementedException();
			default:
				return null;
			}
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Length"))
			{
				if (name == "Empty")
				{
					return "''";
				}
				return null;
			}
			return "LENGTH(#)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	public class MemberMapper
	{
		public bool AutoId { get; set; }

		public string MemberName { get; set; }

		public Type DataType { get; set; }

		public string FieldName { get; set; }

		public GenericGetter Getter { get; set; }

		public GenericSetter Setter { get; set; }

		public Func<object, BsonMapper, BsonValue> Serialize { get; set; }

		public Func<BsonValue, BsonMapper, object> Deserialize { get; set; }

		public bool IsDbRef { get; set; }

		public bool IsEnumerable { get; set; }

		public Type UnderlyingType { get; set; }

		public bool IsIgnore { get; set; }
	}
	public delegate object CreateObject(BsonDocument value);
	public delegate void GenericSetter(object target, object value);
	public delegate object GenericGetter(object obj);
	internal class Reflection
	{
		private static readonly Dictionary<Type, CreateObject> _cacheCtor = new Dictionary<Type, CreateObject>();

		public static readonly Dictionary<Type, PropertyInfo> ConvertType = new Dictionary<Type, PropertyInfo>
		{
			[typeof(DateTime)] = typeof(BsonValue).GetProperty("AsDateTime"),
			[typeof(decimal)] = typeof(BsonValue).GetProperty("AsDecimal"),
			[typeof(double)] = typeof(BsonValue).GetProperty("AsDouble"),
			[typeof(long)] = typeof(BsonValue).GetProperty("AsInt64"),
			[typeof(int)] = typeof(BsonValue).GetProperty("AsInt32"),
			[typeof(bool)] = typeof(BsonValue).GetProperty("AsBoolean"),
			[typeof(byte[])] = typeof(BsonValue).GetProperty("AsBinary"),
			[typeof(BsonDocument)] = typeof(BsonValue).GetProperty("AsDocument"),
			[ty