Decompiled source of XPRising v0.4.10

XPRising.dll

Decompiled a month ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Text;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.CastleBuilding;
using ProjectM.Gameplay.Scripting;
using ProjectM.Gameplay.Systems;
using ProjectM.Network;
using ProjectM.Scripting;
using ProjectM.Shared;
using ProjectM.Tiles;
using Stunlock.Core;
using Stunlock.Network;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
using VampireCommandFramework;
using XPRising.Commands;
using XPRising.Components.RandomEncounters;
using XPRising.Configuration;
using XPRising.Extensions;
using XPRising.Hooks;
using XPRising.Models;
using XPRising.Models.RandomEncounters;
using XPRising.Systems;
using XPRising.Transport;
using XPRising.Utils;
using XPRising.Utils.Prefabs;
using XPRising.Utils.RandomEncounters;
using XPShared;
using XPShared.Services;
using XPShared.Transport;
using XPShared.Transport.Messages;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("XPRising")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("XPRising Mod")]
[assembly: AssemblyFileVersion("0.4.10.0")]
[assembly: AssemblyInformationalVersion("0.4.10+1.Branch.main.Sha.3a00a3be192f5367ac14e9e3d61c7e44d6b32d92.3a00a3be192f5367ac14e9e3d61c7e44d6b32d92")]
[assembly: AssemblyProduct("XPRising")]
[assembly: AssemblyTitle("XPRising")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.10.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 XPRising
{
	[BepInPlugin("XPRising", "XPRising", "0.4.10")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		public enum LogSystem
		{
			Alliance,
			Bloodline,
			Buff,
			Core,
			Death,
			Debug,
			Faction,
			Mastery,
			PowerUp,
			RandomEncounter,
			SquadSpawn,
			Wanted,
			Xp
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static ClientRegisterMessageHandler <0>__HandleClientRegistered;
		}

		public static Harmony harmony;

		public static bool IsInitialized = false;

		public static bool BloodlineSystemActive = false;

		public static bool ExperienceSystemActive = true;

		public static bool PlayerGroupsActive = true;

		public static int MaxPlayerGroupSize = 5;

		public static bool PowerUpCommandsActive = false;

		public static bool RandomEncountersSystemActive = false;

		public static bool WeaponMasterySystemActive = false;

		public static bool WantedSystemActive = true;

		public static bool WaypointsActive = false;

		public static int CommandLogPrivilegeLevel = 100;

		public static int DefaultTextSize = 10;

		private static ManualLogSource _logger;

		private static World _serverWorld;

		internal static Plugin Instance { get; private set; }

		public static bool IsDebug { get; private set; } = false;


		public static bool ShouldApplyBuffs
		{
			get
			{
				if (!ExperienceSystemActive && !BloodlineSystemActive && !WeaponMasterySystemActive)
				{
					return PowerUpCommandsActive;
				}
				return true;
			}
		}

		public static World Server
		{
			get
			{
				if (_serverWorld != null)
				{
					return _serverWorld;
				}
				_serverWorld = GetWorld("Server") ?? throw new Exception("There is no Server world (yet). Did you install a server mod on the client?");
				return _serverWorld;
			}
		}

		public static bool IsServer => Application.productName == "VRisingServer";

		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 void InitCoreConfig()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			BuffUtil.BuffGuid = ((BasePlugin)this).Config.Bind<int>("Core", "Buff GUID", ((PrefabGUID)(ref BuffUtil.BloodBuffVBlood0)).GuidHash, "The GUID of the buff that gets used when mastery, bloodline, etc changes.\nDefault is now boneguard set bonus 2, but you can set anything else too.\nThe only reason to change this is if it clashes with another mod.").Value;
			BuffUtil.AppliedBuff = new PrefabGUID(BuffUtil.BuffGuid);
			BuffUtil.LevelUpBuffId = ((BasePlugin)this).Config.Bind<int>("Core", "Level up Buff GUID", BuffUtil.LevelUpBuffId, "The GUID of the buff that is applied when levelling up.\nSet to 0 to disable.").Value;
			BuffUtil.LevelUpBuff = new PrefabGUID(BuffUtil.LevelUpBuffId);
			CommandLogPrivilegeLevel = ((BasePlugin)this).Config.Bind<int>("Core", "Command log privilege level", 100, "Mechanism to ensure logs commands that require privilege above specified amount are logged. Default value logs all \"admin\" commands. Set to 101 to not log any commands.").Value;
			DefaultTextSize = PlayerPreferences.ConvertTextToSize(((BasePlugin)this).Config.Bind<string>("Core", "Text size", "small", "Can be used to set the text size output by this mod. Expected values: tiny, small, normal.").Value);
			BloodlineSystemActive = ((BasePlugin)this).Config.Bind<bool>("System", "Enable Bloodline Mastery system", false, "Enable/disable the bloodline mastery system.").Value;
			ExperienceSystemActive = ((BasePlugin)this).Config.Bind<bool>("System", "Enable Experience system", true, "Enable/disable the experience system.").Value;
			PlayerGroupsActive = ((BasePlugin)this).Config.Bind<bool>("System", "Enable Player Groups", true, "Enable/disable the player group system.").Value;
			MaxPlayerGroupSize = ((BasePlugin)this).Config.Bind<int>("System", "Maximum player group size", 5, "Set a maximum value for player group size.").Value;
			WeaponMasterySystemActive = ((BasePlugin)this).Config.Bind<bool>("System", "Enable Weapon Mastery system", false, "Enable/disable the weapon mastery system.").Value;
			WantedSystemActive = ((BasePlugin)this).Config.Bind<bool>("System", "Enable Wanted system", false, "Enable/disable the wanted system.").Value;
			if (WaypointsActive)
			{
				WaypointCommands.WaypointLimit = ((BasePlugin)this).Config.Bind<int>("Config", "Waypoint Limit", 2, "Set a waypoint limit for per non-admin user.").Value;
			}
			((BasePlugin)this).Config.SaveOnConfigSet = true;
			ConfigEntry<int> val = ((BasePlugin)this).Config.Bind<int>("Auto-save", "Frequency", 2, "Request the frequency for auto-saving the database. Value is in minutes. Minimum is 2.");
			ConfigEntry<int> val2 = ((BasePlugin)this).Config.Bind<int>("Auto-save", "Backup", 0, "Enable and request the frequency for saving to the backup folder. Value is in minutes. 0 to disable.");
			if (val.Value < 2)
			{
				val.Value = 2;
			}
			if (val2.Value < 0)
			{
				val2.Value = 0;
			}
			AutoSaveSystem.AutoSaveFrequency = TimeSpan.FromMinutes(val.Value);
			AutoSaveSystem.BackupFrequency = ((val2.Value < 1) ? TimeSpan.Zero : TimeSpan.FromMinutes(val2.Value));
			Log(LogSystem.Core, (LogLevel)16, "Auto-save frequency set to " + AutoSaveSystem.AutoSaveFrequency, forceLog: true);
			string message = ((AutoSaveSystem.BackupFrequency == TimeSpan.Zero) ? "Auto-save backups disabled." : ("Auto-save backup frequency set to " + AutoSaveSystem.BackupFrequency));
			Log(LogSystem.Core, (LogLevel)16, message, forceLog: true);
		}

		public override void Load()
		{
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			_logger = ((BasePlugin)this).Log;
			if (!IsServer)
			{
				Log(LogSystem.Core, (LogLevel)4, "This is a server plugin. Not continuing to load on client.", forceLog: true);
				return;
			}
			string text = typeof(Plugin).Assembly.GetCustomAttribute<AssemblyConfigurationAttribute>()?.Configuration;
			IsDebug = text == "Debug";
			InitCoreConfig();
			Instance = this;
			CommandUtility.AddCommandType(typeof(AllianceCommands), PlayerGroupsActive);
			CommandUtility.AddCommandType(typeof(CacheCommands));
			CommandUtility.AddCommandType(typeof(ExperienceCommands), ExperienceSystemActive);
			CommandUtility.AddCommandType(typeof(MasteryCommands), WeaponMasterySystemActive || BloodlineSystemActive);
			CommandUtility.AddCommandType(typeof(PermissionCommands));
			CommandUtility.AddCommandType(typeof(PlayerInfoCommands));
			CommandUtility.AddCommandType(typeof(WantedCommands), WantedSystemActive);
			CommandUtility.AddCommandType(typeof(LocalisationCommands));
			if (IsDebug)
			{
				Log(LogSystem.Core, (LogLevel)16, "****** WARNING ******* Build configuration: " + text, forceLog: true);
				Log(LogSystem.Core, (LogLevel)16, "THIS IS ADDING SOME DEBUG COMMANDS. JUST SO THAT YOU ARE AWARE.", forceLog: true);
				PowerUpCommandsActive = true;
				RandomEncountersSystemActive = true;
				WaypointsActive = true;
				CommandUtility.AddCommandType(typeof(PowerUpCommands), PowerUpCommandsActive);
				CommandUtility.AddCommandType(typeof(RandomEncountersCommands), RandomEncountersSystemActive);
				CommandUtility.AddCommandType(typeof(WaypointCommands), WaypointsActive);
			}
			harmony = new Harmony("XPRising");
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			object obj = <>O.<0>__HandleClientRegistered;
			if (obj == null)
			{
				ClientRegisterMessageHandler val = ClientActionHandler.HandleClientRegistered;
				<>O.<0>__HandleClientRegistered = val;
				obj = (object)val;
			}
			ChatService.OnClientRegisterEvent += (ClientRegisterMessageHandler)obj;
			ChatService.RegisterType<ClientAction>((Action<ClientAction, ulong>)delegate(ClientAction message, ulong steamId)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				ClientActionHandler.HandleClientAction(Extensions.GetUser(Cache.SteamPlayerCache[steamId].UserEntity), message);
			});
			Log(LogSystem.Core, (LogLevel)16, "Plugin is loaded [version: 0.4.10]", forceLog: true);
		}

		public override bool Unload()
		{
			//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_0030: Expected O, but got Unknown
			((BasePlugin)this).Config.Clear();
			harmony.UnpatchSelf();
			object obj = <>O.<0>__HandleClientRegistered;
			if (obj == null)
			{
				ClientRegisterMessageHandler val = ClientActionHandler.HandleClientRegistered;
				<>O.<0>__HandleClientRegistered = val;
				obj = (object)val;
			}
			ChatService.OnClientRegisterEvent -= (ClientRegisterMessageHandler)obj;
			return true;
		}

		public static void Initialize()
		{
			Log(LogSystem.Core, (LogLevel)4, $"Trying to Initialize {"XPRising"}: isInitialized == {IsInitialized}", IsInitialized);
			if (IsInitialized)
			{
				return;
			}
			try
			{
				Log(LogSystem.Core, (LogLevel)16, "Initializing XPRising...", forceLog: true);
				Helper.Initialise();
				AutoSaveSystem.ConfigFolder = AutoSaveSystem.NormaliseConfigFolder(SettingsManager.ServerHostSettings.Name);
				int startingProgressionLevel = Server.GetExistingSystemManaged<ServerGameSettingsSystem>().Settings.StartingProgressionLevel;
				ExperienceSystem.StartingExp = ExperienceSystem.ConvertLevelToXp(startingProgressionLevel);
				Log(LogSystem.Xp, (LogLevel)16, $"Starting XP level set to {startingProgressionLevel} to match server settings", ExperienceSystemActive);
				DebugLoggingConfig.Initialize();
				L10N.Initialize();
				if (BloodlineSystemActive || WeaponMasterySystemActive)
				{
					XPRising.Configuration.GlobalMasteryConfig.Initialize();
				}
				if (ExperienceSystemActive)
				{
					ExperienceConfig.Initialize();
				}
				if (WantedSystemActive)
				{
					WantedConfig.Initialize();
				}
				Log(LogSystem.Core, (LogLevel)16, "Initialising player cache and internal database...");
				PlayerCache.CreatePlayerCache();
				AutoSaveSystem.LoadOrInitialiseDatabase();
				CommandUtility.ValidatedCommandPermissions(CommandUtility.GetAllCommands());
				Log(LogSystem.Core, (LogLevel)16, "Setting CommandRegistry middleware");
				CommandRegistry.Middlewares.Add((CommandMiddleware)(object)new CommandUtility.PermissionMiddleware());
				if (RandomEncountersSystemActive)
				{
					RandomEncounters.GameData_OnInitialize();
					RandomEncounters.EncounterTimer = new WorldTimer();
					RandomEncounters.StartEncounterTimer();
				}
				Log(LogSystem.Core, (LogLevel)16, "Finished initialising", forceLog: true);
				IsInitialized = true;
			}
			catch (Exception ex)
			{
				Log(LogSystem.Core, (LogLevel)2, "Initialisation failed! Error: " + ex.Message, forceLog: true);
				Log(LogSystem.Core, (LogLevel)2, ex.StackTrace ?? "", forceLog: true);
			}
		}

		public static void Log(LogSystem system, LogLevel logLevel, string message, bool forceLog = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (forceLog || DebugLoggingConfig.IsLogging(system))
			{
				_logger.Log(logLevel, (object)ToLogMessage(system, message));
			}
		}

		public static void Log(LogSystem system, LogLevel logLevel, Func<string> messageGenerator, bool forceLog = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (forceLog || DebugLoggingConfig.IsLogging(system))
			{
				_logger.Log(logLevel, (object)ToLogMessage(system, messageGenerator()));
			}
		}

		public static void Log(LogSystem system, LogLevel logLevel, IEnumerable<string> messages, bool forceLog = false)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!forceLog && !DebugLoggingConfig.IsLogging(system))
			{
				return;
			}
			foreach (string message in messages)
			{
				_logger.Log(logLevel, (object)ToLogMessage(system, message));
			}
		}

		private static string ToLogMessage(LogSystem logSystem, string message)
		{
			return $"{DateTime.Now:u}: [{Enum.GetName(logSystem)}] {message}";
		}
	}
	internal static class RandomEncounters
	{
		private const Plugin.LogSystem LogSystem = Plugin.LogSystem.RandomEncounter;

		public static WorldTimer EncounterTimer;

		public static void Load()
		{
		}

		internal static void GameData_OnInitialize()
		{
			Plugin.Log(Plugin.LogSystem.RandomEncounter, (LogLevel)16, "Loading main data RandomEncounters");
			DataFactory.Initialize();
			Plugin.Log(Plugin.LogSystem.RandomEncounter, (LogLevel)16, "Binding configuration RandomEncounters");
			RandomEncountersConfig.Initialize();
		}

		public static void StartEncounterTimer()
		{
			EncounterTimer.Start(delegate
			{
				Plugin.Log(Plugin.LogSystem.RandomEncounter, (LogLevel)16, "Starting an encounter.");
				RandomEncountersSystem.StartEncounter();
			}, delegate(object input)
			{
				if (!(input is int num))
				{
					Plugin.Log(Plugin.LogSystem.RandomEncounter, (LogLevel)2, "Encounter timer delay function parameter is not a valid integer");
					return TimeSpan.MaxValue;
				}
				if (num < 1)
				{
					num = 1;
				}
				int num2 = new Random().Next(RandomEncountersConfig.EncounterTimerMin.Value, RandomEncountersConfig.EncounterTimerMax.Value);
				Plugin.Log(Plugin.LogSystem.RandomEncounter, (LogLevel)16, $"Next encounter will start in {num2 / num} seconds.");
				return TimeSpan.FromSeconds(num2) / num;
			});
		}

		public static void Unload()
		{
			EncounterTimer?.Stop();
			GameFrame.Uninitialize();
			Plugin.Log(Plugin.LogSystem.RandomEncounter, (LogLevel)16, "RandomEncounters unloaded!");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "XPRising";

		public const string PLUGIN_NAME = "XPRising";

		public const string PLUGIN_VERSION = "0.4.10";
	}
}
namespace XPRising.Utils
{
	public class Alliance
	{
		public struct ClosePlayer
		{
			public Entity userEntity;

			public User userComponent;

			public int currentXp;

			public int playerLevel;

			public ulong steamID;

			public float distanceToEvent;

			public float3 playerPosition;

			public float3 triggerPosition;

			public bool isTrigger;
		}

		public struct PlayerGroup
		{
			public HashSet<Entity> Allies { get; }

			public HashSet<Entity> Enemies { get; }

			public DateTime TimeStamp { get; }

			public PlayerGroup()
			{
				Allies = new HashSet<Entity>();
				Enemies = new HashSet<Entity>();
				TimeStamp = DateTime.Now;
			}

			public L10N.LocalisableString PrintAllies()
			{
				//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_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				List<string> list = new List<string>();
				PlayerCharacter val = default(PlayerCharacter);
				foreach (Entity ally in Allies)
				{
					EntityManager entityManager = Plugin.Server.EntityManager;
					if (!((EntityManager)(ref entityManager)).TryGetComponentData<PlayerCharacter>(ally, ref val))
					{
						Plugin.Log(Plugin.LogSystem.Alliance, (LogLevel)2, "Player Character Component unavailable, but should be.");
					}
					else
					{
						list.Add(((object)(FixedString64Bytes)(ref val.Name)).ToString());
					}
				}
				if (list.Count == 0)
				{
					return L10N.Get(L10N.TemplateKey.AllianceGroupEmpty);
				}
				return L10N.Get(L10N.TemplateKey.AllianceGroupMembers).AddField("{members}", string.Join(", ", list));
			}
		}

		private static readonly int CacheAgeLimit = 30;

		private static EntityQuery _connectedPlayerCharactersQuery;

		private static bool ConvertToClosePlayer(Entity entity, float3 position, Plugin.LogSystem system, out ClosePlayer player)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0052: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = Plugin.Server.EntityManager;
			PlayerCharacter val = default(PlayerCharacter);
			EntityManagerDebug debug;
			if (!((EntityManager)(ref entityManager)).TryGetComponentData<PlayerCharacter>(entity, ref val))
			{
				entityManager = Plugin.Server.EntityManager;
				debug = ((EntityManager)(ref entityManager)).Debug;
				Plugin.Log(system, (LogLevel)16, "Player Character Component unavailable, available components are: " + ((EntityManagerDebug)(ref debug)).GetEntityInfo(entity));
				player = default(ClosePlayer);
				return false;
			}
			Entity userEntity = val.UserEntity;
			entityManager = Plugin.Server.EntityManager;
			User val2 = default(User);
			if (!((EntityManager)(ref entityManager)).TryGetComponentData<User>(userEntity, ref val2))
			{
				entityManager = Plugin.Server.EntityManager;
				debug = ((EntityManager)(ref entityManager)).Debug;
				Plugin.Log(system, (LogLevel)16, "User Component unavailable, available components from pc.UserEntity are: " + ((EntityManagerDebug)(ref debug)).GetEntityInfo(userEntity));
				player = default(ClosePlayer);
				return false;
			}
			ulong platformId = val2.PlatformId;
			int xp = ExperienceSystem.GetXp(platformId);
			int level = ExperienceSystem.GetLevel(platformId);
			player = new ClosePlayer
			{
				currentXp = xp,
				playerLevel = level,
				steamID = platformId,
				userEntity = userEntity,
				userComponent = val2,
				distanceToEvent = float.MaxValue,
				triggerPosition = position
			};
			return true;
		}

		public static List<ClosePlayer> GetClosePlayers(float3 position, Entity triggerEntity, float groupMaxDistance, bool areAllies, bool useGroup, Plugin.LogSystem system)
		{
			//IL_0041: 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_001e: 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)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_019b: 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)
			float num = groupMaxDistance * groupMaxDistance;
			Plugin.Log(system, (LogLevel)16, "Fetching allies...");
			List<ClosePlayer> list = new List<ClosePlayer>();
			if (!useGroup)
			{
				if (ConvertToClosePlayer(triggerEntity, position, system, out var player))
				{
					player.isTrigger = true;
					list.Add(player);
				}
			}
			else
			{
				GetPlayerClanAllies(triggerEntity, system, out var playerGroup);
				Plugin.Log(system, (LogLevel)16, "Getting close players");
				HashSet<Entity> hashSet = new HashSet<Entity>(areAllies ? playerGroup.Allies : playerGroup.Enemies);
				if (areAllies && Cache.AlliancePlayerToGroupId.TryGetValue(triggerEntity, out var value))
				{
					hashSet.UnionWith(Cache.AlliancePlayerGroups[value].Allies);
				}
				foreach (Entity item in hashSet)
				{
					Entity current = item;
					Plugin.Log(system, (LogLevel)16, "Iterating over players, entity is " + ((object)(Entity)(ref current)).GetHashCode());
					bool flag = ((Entity)(ref triggerEntity)).Equals(current);
					EntityManager entityManager = Plugin.Server.EntityManager;
					LocalToWorld componentData = ((EntityManager)(ref entityManager)).GetComponentData<LocalToWorld>(current);
					float3 position2 = ((LocalToWorld)(ref componentData)).Position;
					float num2 = 0f;
					if (!flag)
					{
						Plugin.Log(system, (LogLevel)16, "Got entity Position");
						num2 = math.distancesq(((float3)(ref position)).xz, ((float3)(ref position2)).xz);
						Plugin.Log(system, (LogLevel)16, "DistanceSq is " + num2 + ", Max DistanceSq is " + num);
						if (!(num2 <= num))
						{
							continue;
						}
					}
					Plugin.Log(system, (LogLevel)16, "Converting entity to player...");
					if (ConvertToClosePlayer(current, position2, system, out var player2))
					{
						player2.isTrigger = flag;
						player2.distanceToEvent = num2;
						player2.playerPosition = position2;
						list.Add(player2);
					}
				}
			}
			list.Sort((ClosePlayer a, ClosePlayer b) => a.distanceToEvent.CompareTo(b.distanceToEvent));
			Plugin.Log(system, (LogLevel)16, $"Close players fetched (are Allies: {areAllies}), Total player count of {list.Count}");
			return list.GetRange(0, Math.Min(Plugin.MaxPlayerGroupSize, list.Count));
		}

		public static void GetPlayerClanAllies(Entity playerCharacter, Plugin.LogSystem system, out PlayerGroup playerGroup)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: 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_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Unknown result type (might be due to invalid IL or missing references)
			//IL_048b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			if (Cache.AllianceAutoPlayerAllies.TryGetValue(playerCharacter, out playerGroup))
			{
				Plugin.Log(system, (LogLevel)16, $"Player found in cache, cache timestamp is {playerGroup.TimeStamp:u}");
				if ((DateTime.Now - playerGroup.TimeStamp).TotalSeconds < (double)CacheAgeLimit)
				{
					return;
				}
				Plugin.Log(system, (LogLevel)16, "Cache is too old, refreshing cached data");
			}
			playerGroup = new PlayerGroup();
			EntityManager entityManager = Plugin.Server.EntityManager;
			EntityManagerDebug debug;
			if (!((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(playerCharacter))
			{
				Plugin.Log(system, (LogLevel)16, $"Entity is not user: {playerCharacter}");
				entityManager = Plugin.Server.EntityManager;
				debug = ((EntityManager)(ref entityManager)).Debug;
				Plugin.Log(system, (LogLevel)16, "Components for Player Character are: " + ((EntityManagerDebug)(ref debug)).GetEntityInfo(playerCharacter));
				return;
			}
			bool flag = false;
			int num = 0;
			entityManager = Plugin.Server.EntityManager;
			Team val = default(Team);
			if (((EntityManager)(ref entityManager)).TryGetComponentData<Team>(playerCharacter, ref val))
			{
				Plugin.Log(system, (LogLevel)16, $"Player Character found team: {val.Value} - Faction Index: {val.FactionIndex}");
				flag = true;
				num = val.Value;
			}
			else
			{
				Plugin.Log(system, (LogLevel)16, "Player Character has no team: all other PCs are marked as enemies.");
			}
			Plugin.Log(system, (LogLevel)16, "Beginning To Parse Player Group");
			NativeArray<Entity> val2 = ((EntityQuery)(ref _connectedPlayerCharactersQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Plugin.Log(system, (LogLevel)16, $"got connected PC entities buffer of length {val2.Length}");
			Enumerator<Entity> enumerator = val2.GetEnumerator();
			Team val4 = default(Team);
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				Entity val3 = current;
				Plugin.Log(system, (LogLevel)16, "got Entity " + ((object)(Entity)(ref val3)).ToString());
				entityManager = Plugin.Server.EntityManager;
				if (((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(current))
				{
					val3 = current;
					Plugin.Log(system, (LogLevel)16, "Entity is User " + ((object)(Entity)(ref val3)).ToString());
					if (((Entity)(ref current)).Equals(playerCharacter))
					{
						Plugin.Log(system, (LogLevel)16, "Entity is self");
						playerGroup.Allies.Add(current);
						continue;
					}
					if (!flag)
					{
						Plugin.Log(system, (LogLevel)16, $"Entity defaults to enemy: {current}");
						playerGroup.Enemies.Add(current);
					}
					bool flag2 = false;
					try
					{
						Plugin.Log(system, (LogLevel)16, "Trying to get entity teams");
						entityManager = Plugin.Server.EntityManager;
						if (((EntityManager)(ref entityManager)).TryGetComponentData<Team>(current, ref val4))
						{
							Plugin.Log(system, (LogLevel)16, $"Team Value:{val4.Value} - Faction Index: {val4.FactionIndex}");
							flag2 = val4.Value == num;
						}
						else
						{
							Plugin.Log(system, (LogLevel)16, $"Could not get team for entity: {current}");
							entityManager = Plugin.Server.EntityManager;
							debug = ((EntityManager)(ref entityManager)).Debug;
							Plugin.Log(system, (LogLevel)16, "Components for entity are: " + ((EntityManagerDebug)(ref debug)).GetEntityInfo(current));
						}
					}
					catch (Exception ex)
					{
						Plugin.Log(system, (LogLevel)16, "GetPlayerTeams failed " + ex.Message);
					}
					if (flag2)
					{
						Plugin.Log(system, (LogLevel)16, $"Allies: {playerCharacter} - {current}");
						playerGroup.Allies.Add(current);
					}
					else
					{
						Plugin.Log(system, (LogLevel)16, $"Enemies: {playerCharacter} - {current}");
						playerGroup.Enemies.Add(current);
					}
				}
				else
				{
					Plugin.Log(system, (LogLevel)16, "No Associated User!");
				}
			}
			if (playerGroup.Allies.Count == 0)
			{
				playerGroup.Allies.Add(playerCharacter);
			}
			Cache.AllianceAutoPlayerAllies[playerCharacter] = playerGroup;
		}

		public static void GetLocalPlayers(Entity playerCharacter, Plugin.LogSystem system, out PlayerGroup playerGroup)
		{
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			playerGroup = new PlayerGroup();
			EntityManager entityManager = Plugin.Server.EntityManager;
			if (!((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(playerCharacter))
			{
				Plugin.Log(system, (LogLevel)16, $"Entity is not user: {playerCharacter}");
				return;
			}
			Plugin.Log(system, (LogLevel)16, "LP: Beginning To Parse Player Group");
			NativeArray<Entity> val = ((EntityQuery)(ref _connectedPlayerCharactersQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Plugin.Log(system, (LogLevel)16, $"LP: got connected PC entities buffer of length {val.Length}");
			Enumerator<Entity> enumerator = val.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				Entity val2 = current;
				Plugin.Log(system, (LogLevel)16, "got Entity " + ((object)(Entity)(ref val2)).ToString());
				entityManager = Plugin.Server.EntityManager;
				if (((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(current))
				{
					val2 = current;
					Plugin.Log(system, (LogLevel)16, "Entity is User " + ((object)(Entity)(ref val2)).ToString());
					if (((Entity)(ref current)).Equals(playerCharacter))
					{
						Plugin.Log(system, (LogLevel)16, "Entity is self");
						playerGroup.Allies.Add(current);
						continue;
					}
					Plugin.Log(system, (LogLevel)16, $"Adding player to group: {playerCharacter} - {current}");
					playerGroup.Allies.Add(current);
				}
				else
				{
					Plugin.Log(system, (LogLevel)16, "No Associated User!");
				}
			}
		}

		public static void RemoveUserOnLogout(Entity playerCharacter, string playerName)
		{
			//IL_0005: 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_0033: 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_0044: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			Cache.AlliancePendingInvites.Remove(playerCharacter);
			if (!Cache.AlliancePlayerToGroupId.Remove(playerCharacter, out var value) || !Cache.AlliancePlayerGroups.TryGetValue(value, out var value2))
			{
				return;
			}
			value2.Allies.Remove(playerCharacter);
			EntityManager entityManager = Plugin.Server.EntityManager;
			foreach (Entity ally in value2.Allies)
			{
				Entity userEntity = ((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(ally).UserEntity;
				L10N.LocalisableString message = L10N.Get(L10N.TemplateKey.AllianceGroupLoggedOut).AddField("{playerName}", playerName);
				Output.SendMessage(userEntity, message);
			}
		}

		static Alliance()
		{
			//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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//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_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_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)
			EntityManager entityManager = Plugin.Server.EntityManager;
			EntityQueryDesc[] array = new EntityQueryDesc[1];
			EntityQueryDesc val = new EntityQueryDesc();
			val.All = Il2CppStructArray<ComponentType>.op_Implicit((ComponentType[])(object)new ComponentType[2]
			{
				ComponentType.ReadOnly<PlayerCharacter>(),
				ComponentType.ReadOnly<IsConnected>()
			});
			val.Options = (EntityQueryOptions)2;
			array[0] = val;
			_connectedPlayerCharactersQuery = ((EntityManager)(ref entityManager)).CreateEntityQuery((EntityQueryDesc[])(object)array);
		}
	}
	public static class AutoSaveSystem
	{
		private enum LoadMethod
		{
			Both,
			Main,
			Backup,
			None
		}

		public static string ConfigFolder = "XPRising";

		public static readonly string BasePath = Paths.ConfigPath ?? Path.Combine("BepInEx", "config");

		private static Regex _folderValidation = new Regex("([^\\w]+)");

		private const string PowerUpJson = "powerUp.json";

		private const string WaypointsJson = "waypoints.json";

		private const string PlayerLogoutJson = "playerLogout.json";

		private const string PlayerExperienceJson = "playerExperience.json";

		private const string PlayerAbilityPointsJson = "playerAbilityPoints.json";

		private const string PlayerLevelStatsJson = "playerLevelStats.json";

		private const string ExperienceClassStatsJson = "experienceClassStats.json";

		private const string CommandPermissionJson = "commandPermission.json";

		private const string UserPermissionJson = "userPermission.json";

		private const string PlayerMasteryJson = "playerMasteryStats.json";

		private const string GlobalMasteryConfigJson = "globalMasteryConfig.json";

		private const string PlayerPreferencesJson = "playerPreferences.json";

		private const string PlayerWantedLevelJson = "playerWantedLevel.json";

		private static DateTime _timeSinceLastAutoSave = DateTime.Now;

		private static DateTime _timeSinceLastBackupSave = DateTime.Now;

		private static readonly TimeSpan TimeBuffer = TimeSpan.FromSeconds(30.0);

		public static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
		{
			PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
			WriteIndented = false,
			IncludeFields = true,
			DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
			Converters = 
			{
				(JsonConverter)new PrefabGuidConverter(),
				(JsonConverter)new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
			}
		};

		public static readonly JsonSerializerOptions PrettyJsonOptions = new JsonSerializerOptions
		{
			PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
			WriteIndented = true,
			IncludeFields = true,
			DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
			Converters = 
			{
				(JsonConverter)new PrefabGuidConverter(),
				(JsonConverter)new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
			}
		};

		public static string ConfigPath => Path.Combine(BasePath, ConfigFolder);

		public static string SavesPath => Path.Combine(BasePath, ConfigFolder, "Data");

		public static string BackupsPath => Path.Combine(BasePath, ConfigFolder, SavesPath, "Backup");

		public static TimeSpan AutoSaveFrequency { get; set; } = TimeSpan.FromMinutes(2.0);


		public static TimeSpan BackupFrequency { get; set; } = TimeSpan.Zero;


		public static string NormaliseConfigFolder(string serverName)
		{
			return _folderValidation.Replace("XPRising_" + serverName.Trim(), "_");
		}

		public static bool SaveDatabase(bool forceSave, bool forceBackup = false)
		{
			if (!Plugin.IsInitialized)
			{
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)2, "Attempted to save the DB without properly initialising the DB. Cancelling the save as this would overwrite any existing config with blank data.", forceLog: true);
				return false;
			}
			bool flag = false;
			DateTime now = DateTime.Now;
			bool flag2 = now - _timeSinceLastAutoSave > AutoSaveFrequency;
			if (forceSave || flag2)
			{
				string message = (forceSave ? "Saving DB..." : "Auto-saving DB...");
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, message, forceSave);
				flag |= !InternalSaveDatabase(SavesPath);
				_timeSinceLastAutoSave = now - TimeBuffer;
			}
			bool flag3 = !BackupFrequency.Equals(TimeSpan.Zero) && now - _timeSinceLastBackupSave > BackupFrequency;
			if (forceBackup || flag3)
			{
				string message2 = (forceSave ? "Saving DB backup..." : "Auto-saving DB backup...");
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, message2, forceSave);
				flag |= !InternalSaveDatabase(BackupsPath);
				_timeSinceLastBackupSave = now - TimeBuffer;
			}
			return !flag;
		}

		private static bool InternalSaveDatabase(string saveFolder)
		{
			bool flag = false;
			flag |= !SaveDB(saveFolder, "commandPermission.json", Database.CommandPermission, PrettyJsonOptions);
			flag |= !SaveDB(saveFolder, "userPermission.json", Database.UserPermission, PrettyJsonOptions);
			flag |= !SaveDB(saveFolder, "playerPreferences.json", Database.PlayerPreferences, JsonOptions);
			flag |= !SaveDB(saveFolder, "playerLogout.json", Database.PlayerLogout, JsonOptions);
			if (Plugin.WaypointsActive)
			{
				flag |= !SaveDB(saveFolder, "waypoints.json", Database.Waypoints, JsonOptions);
			}
			if (Plugin.PowerUpCommandsActive)
			{
				flag |= !SaveDB(saveFolder, "powerUp.json", Database.PowerUpList, JsonOptions);
			}
			if (Plugin.ExperienceSystemActive)
			{
				flag |= !SaveDB(saveFolder, "playerExperience.json", Database.PlayerExperience, JsonOptions);
				flag |= !SaveDB(saveFolder, "playerAbilityPoints.json", Database.PlayerAbilityIncrease, JsonOptions);
				flag |= !SaveDB(saveFolder, "playerLevelStats.json", Database.PlayerLevelStats, JsonOptions);
				flag |= !SaveDB(saveFolder, "experienceClassStats.json", Database.ExperienceClassStats, PrettyJsonOptions);
			}
			if (Plugin.WantedSystemActive)
			{
				flag |= !SaveDB(saveFolder, "playerWantedLevel.json", Database.PlayerHeat, JsonOptions);
			}
			if (Plugin.WeaponMasterySystemActive || Plugin.BloodlineSystemActive)
			{
				flag |= !SaveDB(saveFolder, "playerMasteryStats.json", Database.PlayerMastery, JsonOptions);
			}
			Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, "All databases saved to: " + saveFolder);
			return !flag;
		}

		public static void LoadOrInitialiseDatabase()
		{
			InternalLoadDatabase(useInitialiser: true, LoadMethod.Both);
		}

		public static bool LoadDatabase(bool loadBackup)
		{
			return InternalLoadDatabase(useInitialiser: false, (!loadBackup) ? LoadMethod.Main : LoadMethod.Backup);
		}

		public static bool WipeDatabase()
		{
			return InternalLoadDatabase(useInitialiser: true, LoadMethod.None);
		}

		private static bool InternalLoadDatabase(bool useInitialiser, LoadMethod loadMethod)
		{
			bool flag = false;
			flag |= !LoadDB("commandPermission.json", loadMethod, useInitialiser, ref Database.CommandPermission, PermissionSystem.DefaultCommandPermissions);
			flag |= !LoadDB("userPermission.json", loadMethod, useInitialiser, ref Database.UserPermission);
			flag |= !LoadDB("playerPreferences.json", loadMethod, useInitialiser, ref Database.PlayerPreferences);
			flag |= !LoadDB("playerLogout.json", loadMethod, useInitialiser, ref Database.PlayerLogout);
			if (Plugin.WaypointsActive)
			{
				flag |= !LoadDB("waypoints.json", loadMethod, useInitialiser, ref Database.Waypoints);
			}
			if (Plugin.PowerUpCommandsActive)
			{
				flag |= !LoadDB("powerUp.json", loadMethod, useInitialiser, ref Database.PowerUpList);
			}
			if (Plugin.ExperienceSystemActive)
			{
				flag |= !LoadDB("playerExperience.json", loadMethod, useInitialiser, ref Database.PlayerExperience);
				flag |= !LoadDB("playerAbilityPoints.json", loadMethod, useInitialiser, ref Database.PlayerAbilityIncrease);
				flag |= !LoadDB("playerLevelStats.json", loadMethod, useInitialiser, ref Database.PlayerLevelStats);
				flag |= !LoadDB("experienceClassStats.json", loadMethod, useInitialiser, ref Database.ExperienceClassStats, ExperienceSystem.DefaultExperienceClassStats);
			}
			if (Plugin.WantedSystemActive)
			{
				flag |= !LoadDB("playerWantedLevel.json", loadMethod, useInitialiser, ref Database.PlayerHeat);
				foreach (var (num2, playerHeatData2) in Database.PlayerHeat)
				{
					Plugin.Log(Plugin.LogSystem.Wanted, (LogLevel)2, $"starting cooldown timer for {num2}. Has {playerHeatData2.heat.Count} factions in heat");
					playerHeatData2.StartCooldownTimer(num2);
				}
			}
			if (Plugin.WeaponMasterySystemActive || Plugin.BloodlineSystemActive)
			{
				flag |= !LoadDB("playerMasteryStats.json", loadMethod, useInitialiser, ref Database.PlayerMastery);
			}
			if (Plugin.WeaponMasterySystemActive || Plugin.BloodlineSystemActive || Plugin.ExperienceSystemActive)
			{
				Plugin.Log(Plugin.LogSystem.Mastery, (LogLevel)16, "Confirming custom preset file exists");
				ConfirmFile(SavesPath, "globalMasteryConfig.json", () => JsonSerializer.Serialize(GlobalMasterySystem.DefaultMasteryConfig(), PrettyJsonOptions));
				XPRising.Models.GlobalMasteryConfig currentRef = new XPRising.Models.GlobalMasteryConfig();
				flag |= LoadDB("globalMasteryConfig.json", loadMethod, useInitialiser, ref currentRef, GlobalMasterySystem.DefaultMasteryConfig);
				if (GlobalMasterySystem.MasteryConfigPreset != GlobalMasterySystem.CustomPreset)
				{
					Plugin.Log(Plugin.LogSystem.Mastery, (LogLevel)16, "Ensuring '" + GlobalMasterySystem.MasteryConfigPreset + "' preset file is being written.");
					XPRising.Models.GlobalMasteryConfig preset = GlobalMasterySystem.DefaultMasteryConfig();
					preset.XpBuffConfig = currentRef.XpBuffConfig;
					EnsureFile(SavesPath, "globalMasteryConfig.json", () => JsonSerializer.Serialize(preset, PrettyJsonOptions));
					currentRef = preset;
				}
				GlobalMasterySystem.SetMasteryConfig(currentRef);
			}
			Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, "All database data is now loaded.", forceLog: true);
			return !flag;
		}

		private static bool SaveDB<TData>(string saveFolder, string specificFile, TData data, JsonSerializerOptions options)
		{
			try
			{
				File.WriteAllText(Path.Combine(saveFolder, specificFile), JsonSerializer.Serialize(data, options));
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, specificFile + " Saved.");
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)2, "Could not save DB " + specificFile + ": " + ex.Message, forceLog: true);
				return false;
			}
		}

		private static bool LoadDB<TData>(string specificFile, LoadMethod loadMethod, bool useInitialiser, ref TData currentRef, Func<TData> initialiser = null) where TData : class, new()
		{
			switch (loadMethod)
			{
			case LoadMethod.Main:
				if (LoadDB(SavesPath, specificFile, ref currentRef))
				{
					return true;
				}
				break;
			case LoadMethod.Backup:
				if (LoadDB(BackupsPath, specificFile, ref currentRef))
				{
					return true;
				}
				break;
			default:
				if (LoadDB(SavesPath, specificFile, ref currentRef) || LoadDB(BackupsPath, specificFile, ref currentRef))
				{
					return true;
				}
				break;
			case LoadMethod.None:
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, "Initialising DB for " + specificFile);
				currentRef = ((initialiser == null) ? new TData() : initialiser());
				return true;
			}
			if (!useInitialiser)
			{
				return false;
			}
			Plugin.Log(Plugin.LogSystem.Core, (LogLevel)4, "Initialising DB for " + specificFile);
			currentRef = ((initialiser == null) ? new TData() : initialiser());
			return false;
		}

		private static bool LoadDB<TData>(string folder, string specificFile, ref TData data) where TData : class, new()
		{
			Type typeFromHandle = typeof(TData);
			bool flag = typeFromHandle.IsGenericType && (typeFromHandle.GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>)) || typeFromHandle.GetGenericTypeDefinition().IsAssignableFrom(typeof(HashSet<>)));
			string defaultContents = (flag ? "[]" : "{}");
			try
			{
				string text = File.ReadAllText(ConfirmFile(folder, specificFile, () => defaultContents));
				data = JsonSerializer.Deserialize<TData>(text, JsonOptions);
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, "DB loaded from " + specificFile);
				return !defaultContents.Equals(text);
			}
			catch (Exception ex)
			{
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)2, "Could not load " + specificFile + ": " + ex.Message, forceLog: true);
				return false;
			}
		}

		public static string ConfirmFile(string address, string file, Func<string> defaultContents = null)
		{
			try
			{
				Directory.CreateDirectory(address);
			}
			catch (Exception ex)
			{
				throw new Exception("Error creating directory at " + address + "\n Error is: " + ex.Message);
			}
			string text = Path.Combine(address, file);
			try
			{
				if (!File.Exists(text))
				{
					File.WriteAllText(text, (defaultContents == null) ? "" : defaultContents());
				}
			}
			catch (Exception ex2)
			{
				throw new Exception("Error creating file at " + text + "\n Error is: " + ex2.Message);
			}
			return text;
		}

		public static string EnsureFile(string address, string file, Func<string> contents = null)
		{
			try
			{
				Directory.CreateDirectory(address);
			}
			catch (Exception ex)
			{
				throw new Exception("Error creating directory at " + address + "\n Error is: " + ex.Message);
			}
			string text = Path.Combine(address, file);
			try
			{
				File.WriteAllText(text, (contents == null) ? "" : contents());
				return text;
			}
			catch (Exception ex2)
			{
				throw new Exception("Error creating file at " + text + "\n Error is: " + ex2.Message);
			}
		}
	}
	public class PrefabGuidConverter : JsonConverter<PrefabGUID>
	{
		public override PrefabGUID Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return new PrefabGUID(reader.GetInt32());
		}

		public override void Write(Utf8JsonWriter writer, PrefabGUID guid, JsonSerializerOptions options)
		{
			writer.WriteNumberValue(((PrefabGUID)(ref guid)).GuidHash);
		}
	}
	public static class BuffUtil
	{
		public static PrefabGUID SeverePunishmentDebuff = new PrefabGUID(1582196539);

		public static PrefabGUID MinorPunishmentDebuff = new PrefabGUID(-1701323826);

		public static PrefabGUID HostileMarkBuff = new PrefabGUID(-106492795);

		public static int LevelUpBuffId = -1133938228;

		public static PrefabGUID LevelUpBuff = new PrefabGUID(LevelUpBuffId);

		public static PrefabGUID HolyNuke = new PrefabGUID(-1807398295);

		public static PrefabGUID PigTransformDebuff = new PrefabGUID(1356064917);

		public static PrefabGUID BloodBuffVBlood0 = new PrefabGUID(20081801);

		public static int BuffGuid = 20081801;

		public static PrefabGUID AppliedBuff = BloodBuffVBlood0;

		private static readonly Dictionary<ulong, FrameTimer> FrameTimers = new Dictionary<ulong, FrameTimer>();

		public static ModifyUnitStatBuff_DOTS MakeBuff(UnitStatType type, double strength)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			//IL_002c: 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_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_0010: Unknown result type (might be due to invalid IL or missing references)
			ModificationType modificationType = (ModificationType)3;
			if (Helper.multiplierStats.Contains(type))
			{
				modificationType = (ModificationType)4;
			}
			ModifyUnitStatBuff_DOTS result = default(ModifyUnitStatBuff_DOTS);
			result.StatType = type;
			result.Value = (float)strength;
			result.ModificationType = modificationType;
			result.Modifier = 1f;
			result.Id = ModificationId.NewId(0);
			return result;
		}

		public static double CalcBuffValue(double strength, double effectiveness, double rate, UnitStatType type)
		{
			effectiveness = Math.Max(effectiveness, 1.0);
			return strength * rate * effectiveness;
		}

		public static void ApplyBuff(Entity User, Entity Char, PrefabGUID GUID)
		{
			//IL_000c: 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_0015: 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)
			//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_0026: 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_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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			DebugEventsSystem existingSystemManaged = Plugin.Server.GetExistingSystemManaged<DebugEventsSystem>();
			FromCharacter val = new FromCharacter
			{
				User = User,
				Character = Char
			};
			ApplyBuffDebugEvent val2 = new ApplyBuffDebugEvent
			{
				BuffPrefabGUID = GUID
			};
			existingSystemManaged.ApplyBuff(val, val2);
		}

		public static void RemoveBuff(Entity Char, PrefabGUID GUID)
		{
			//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_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_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_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_003f: Unknown result type (might be due to invalid IL or missing references)
			Entity val = default(Entity);
			if (BuffUtility.HasBuff<EntityManager>(Plugin.Server.EntityManager, Char, PrefabIdentifier.op_Implicit(GUID)) && BuffUtility.TryGetBuff<EntityManager>(Plugin.Server.EntityManager, Char, PrefabIdentifier.op_Implicit(GUID), ref val))
			{
				EntityManager entityManager = Plugin.Server.EntityManager;
				((EntityManager)(ref entityManager)).AddComponent<DestroyTag>(val);
			}
		}

		public static bool HasBuff(Entity player, PrefabGUID BuffGUID)
		{
			//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_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)
			return BuffUtility.HasBuff<EntityManager>(Plugin.Server.EntityManager, player, PrefabIdentifier.op_Implicit(BuffGUID));
		}

		public static bool IsItemEquipBuff(PrefabGUID prefabGuid)
		{
			switch ((Items)((PrefabGUID)(ref prefabGuid)).GuidHash)
			{
			case Items.Item_EquipBuff_MagicSource_T06_Unholy:
			case Items.Item_EquipBuff_MagicSource_T06_Frost:
			case Items.Item_EquipBuff_MagicSource_T06_Blood:
			case Items.Item_EquipBuff_MagicSource_T08_Unholy:
			case Items.Item_EquipBuff_MagicSource_T06_Storm:
			case Items.Item_EquipBuff_MagicSource_Soulshard_Dracula:
			case Items.Item_EquipBuff_MagicSource_BloodKey_T01:
			case Items.Item_EquipBuff_MagicSource_T08_Blood:
			case Items.Item_EquipBuff_MagicSource_T08_Chaos:
			case Items.Item_EquipBuff_MagicSource_Soulshard_Morgana:
			case Items.Item_EquipBuff_MagicSource_T06_Chaos:
			case Items.Item_EquipBuff_MagicSource_Soulshard_Solarus:
			case Items.Item_EquipBuff_Shared_General:
			case Items.Item_EquipBuff_MagicSource_Soulshard_TheMonster:
			case Items.Item_EquipBuff_MagicSource_T08_Frost:
			case Items.Item_EquipBuff_MagicSource_T06_Illusion:
			case Items.Item_EquipBuff_MagicSource_Soulshard_Manticore:
			case Items.Item_EquipBuff_MagicSource_T08_Storm:
			case Items.Item_EquipBuff_MagicSource_T08_Illusion:
			case Items.Item_EquipBuff_MagicSource_General:
				return true;
			default:
				if (Enum.IsDefined((EquipBuffs)((PrefabGUID)(ref prefabGuid)).GuidHash))
				{
					return true;
				}
				return false;
			}
		}

		public static void ApplyStatBuffOnDelay(User userData, Entity user, Entity character)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0015: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			if (FrameTimers.TryGetValue(userData.PlatformId, out var timer))
			{
				timer.Start();
				return;
			}
			FrameTimer val = new FrameTimer();
			val.Initialise((Action)delegate
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				ApplyBuff(user, character, AppliedBuff);
				if (FrameTimers.Remove(userData.PlatformId, out timer))
				{
					timer.Stop();
				}
			}, TimeSpan.FromMilliseconds(200.0), 1).Start();
			FrameTimers.Add(userData.PlatformId, val);
		}
	}
	public static class CommandUtility
	{
		public class PermissionMiddleware : CommandMiddleware
		{
			public override bool CanExecute(ICommandContext ctx, CommandAttribute command, MethodInfo method)
			{
				Type? declaringType = method.DeclaringType;
				object obj;
				if ((object)declaringType == null)
				{
					obj = null;
				}
				else
				{
					CommandGroupAttribute? customAttribute = ((MemberInfo)declaringType).GetCustomAttribute<CommandGroupAttribute>();
					obj = ((customAttribute != null) ? customAttribute.Name : null);
				}
				if (obj == null)
				{
					obj = "";
				}
				string text = CommandAttributesToPermissionKey((string)obj, command.Name, RequiredArgumentCount(method.GetParameters()));
				if (!Database.CommandPermission.TryGetValue(text, out var value))
				{
					if (Plugin.IsDebug)
					{
						ctx.Reply("DEBUG: COMMAND NOT FOUND " + text);
					}
					return true;
				}
				ulong steamIDFromName = PlayerCache.GetSteamIDFromName(ctx.Name);
				bool flag = (ctx.IsAdmin ? PermissionSystem.HighestPrivilege : Database.UserPermission.GetValueOrDefault(steamIDFromName, PermissionSystem.LowestPrivilege)) >= value;
				if (value >= Plugin.CommandLogPrivilegeLevel)
				{
					Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, $"COMMAND AUDIT: [{ctx.Name}, {text}, {(flag ? "Granted" : "Denied")}]", forceLog: true);
				}
				if (flag)
				{
					return true;
				}
				ctx.Reply("<color=" + Color.Red + ">[permission denied]</color> " + text);
				return false;
			}
		}

		public struct Command
		{
			public string PermissionKey;

			public string Name;

			public string ShortHand;

			public string Usage;

			public string Description;

			public bool IsAdmin;

			public int PrivilegeLevel;

			public Command(string permissionKey, string name, string shortHand, string usage, string description, bool isAdmin, int privilegeLevel)
			{
				PermissionKey = permissionKey;
				Name = name;
				ShortHand = shortHand;
				Usage = usage;
				Description = description;
				IsAdmin = isAdmin;
				PrivilegeLevel = privilegeLevel;
			}
		}

		private static readonly List<Type> LoadedCommandTypes = new List<Type>();

		private static string CommandAttributesToPermissionKey(string groupName, string commandName, int argCount)
		{
			if (string.IsNullOrEmpty(commandName))
			{
				return "";
			}
			string text = ((argCount == 0) ? "" : $"[{argCount}]");
			return string.Join(" ", new string[3] { groupName, commandName, text }.Where((string s) => !string.IsNullOrEmpty(s)));
		}

		private static int RequiredArgumentCount(ParameterInfo[] args)
		{
			return args.Skip(1).Count((ParameterInfo p) => !p.IsOptional);
		}

		private static int DefaultPrivilege(bool isAdmin)
		{
			if (!isAdmin)
			{
				return PermissionSystem.LowestPrivilege;
			}
			return PermissionSystem.HighestPrivilege;
		}

		public static void AddCommandType(Type type, bool register = true)
		{
			LoadedCommandTypes.Add(type);
			if (register)
			{
				CommandRegistry.RegisterCommandType(type);
			}
		}

		public static IOrderedEnumerable<Command> GetAllCommands(bool fullAssembly = false)
		{
			object source = (fullAssembly ? ((object)Assembly.GetCallingAssembly().GetTypes()) : ((object)LoadedCommandTypes.ToArray()));
			LazyDictionary<string, int> defaultPermissions = PermissionSystem.DefaultCommandPermissions();
			return from c in ((IEnumerable<Type>)source).Select(delegate(Type t)
				{
					CommandGroupAttribute customAttribute = ((MemberInfo)t).GetCustomAttribute<CommandGroupAttribute>();
					string groupName = ((customAttribute != null) ? customAttribute.Name : null) ?? "";
					string groupShortHand = ((customAttribute != null) ? customAttribute.ShortHand : null) ?? "";
					return (from m in t.GetMethods()
						select new Tuple<CommandAttribute, ParameterInfo[]>(((MemberInfo)m).GetCustomAttribute<CommandAttribute>(), m.GetParameters()) into m
						where m.Item1 != null
						select m).Select(delegate(Tuple<CommandAttribute, ParameterInfo[]> m)
					{
						string groupName2 = (string.IsNullOrEmpty(groupShortHand) ? groupName : groupShortHand);
						CommandAttribute item = m.Item1;
						int argCount = RequiredArgumentCount(m.Item2);
						string text = CommandAttributesToPermissionKey(groupName, item.Name, argCount);
						return new Command(text, CommandAttributesToPermissionKey(groupName, item.Name, 0), CommandAttributesToPermissionKey(groupName2, item.ShortHand, 0), item.Usage?.Replace("|", "\\|") ?? "", item.Description?.Replace("|", "&#124;") ?? "", item.AdminOnly, defaultPermissions.GetValueOrDefault(text, DefaultPrivilege(item.AdminOnly)));
					});
				}).SelectMany((IEnumerable<Command> s) => s)
				orderby c.PermissionKey
				select c;
		}

		public static void ValidatedCommandPermissions(IEnumerable<Command> commands)
		{
			Dictionary<string, bool> commandsDictionary = commands.ToDictionary((Command command) => command.PermissionKey, (Command command) => command.IsAdmin);
			foreach (string item in Database.CommandPermission.Keys.Where((string permission) => !commandsDictionary.ContainsKey(permission)))
			{
				Plugin.Log(Plugin.LogSystem.Core, (LogLevel)8, "Removing old permission: " + item);
				Database.CommandPermission.Remove(item);
			}
			LazyDictionary<string, int> lazyDictionary = PermissionSystem.DefaultCommandPermissions();
			foreach (KeyValuePair<string, bool> item2 in commandsDictionary)
			{
				if (Database.CommandPermission.TryAdd(item2.Key, DefaultPrivilege(item2.Value)))
				{
					Plugin.Log(Plugin.LogSystem.Core, (LogLevel)8, "Added new permission: " + item2.Key);
				}
				if (!lazyDictionary.ContainsKey(item2.Key))
				{
					Plugin.Log(Plugin.LogSystem.Core, (LogLevel)4, "Default permissions do not include: " + item2.Key + "\nRegenerate the default command permissions (and maybe Command.md).", forceLog: true);
				}
				if (item2.Key.StartsWith(".") && Plugin.IsDebug)
				{
					Plugin.Log(Plugin.LogSystem.Debug, (LogLevel)2, "Command " + item2.Key + " starts with a '.'. This is likely an error as VCF handles that bit.");
				}
			}
			Plugin.Log(Plugin.LogSystem.Core, (LogLevel)16, "Permissions have been validated");
		}

		private static string PadCommandString(int index, string command, int width)
		{
			if (string.IsNullOrEmpty(command))
			{
				return "".PadRight(width);
			}
			switch (index)
			{
			case 0:
			case 1:
				return ("`." + command + "`").PadRight(width);
			case 2:
			case 5:
				return ("`" + command + "`").PadRight(width);
			case 4:
			{
				int totalWidth = (width - 1) / 2 + 1;
				return (command.Equals("True") ? "☑" : "☐").PadLeft(totalWidth).PadRight(width);
			}
			default:
				return command.PadRight(width);
			}
		}

		public static void GenerateCommandMd(IEnumerable<Command> commands)
		{
			string[] source = new string[6] { "Command", "Short hand", "Usage", "Description", "Admin", "Level" };
			int[] seed = source.Select((string s) => s.Length).ToArray();
			int[] columnWidths = commands.Aggregate(seed, delegate(int[] acc, Command command)
			{
				acc[0] = Math.Max(acc[0], command.Name.Length + 3);
				acc[1] = Math.Max(acc[1], command.ShortHand.Length + 3);
				acc[2] = Math.Max(acc[2], command.Usage.Length + 2);
				acc[3] = Math.Max(acc[3], command.Description.Length);
				acc[4] = Math.Max(acc[4], command.IsAdmin.ToString().Length);
				acc[5] = Math.Max(acc[5], command.PrivilegeLevel.ToString().Length + 2);
				return acc;
			});
			Func<Command, int, string> getColumnData = (Command command, int i) => i switch
			{
				0 => command.Name, 
				1 => command.ShortHand, 
				2 => command.Usage, 
				3 => command.Description, 
				4 => command.IsAdmin.ToString(), 
				5 => command.PrivilegeLevel.ToString(), 
				_ => "", 
			};
			string contents = "To regenerate this table, uncomment the `GenerateCommandMd` function in `Plugin.ValidateCommandPermissions`. Then check the LogOutput.log in the server after starting.\nUsage arguments: <> are required, [] are optional\n\n| " + string.Join(" | ", source.Select((string s, int i) => s.PadRight(columnWidths[i]))) + " |\n|-" + string.Join("-|-", columnWidths.Select((int width) => "-".PadRight(width, '-'))) + "-|\n" + string.Join("\n", commands.Select((Command command) => "| " + string.Join(" | ", columnWidths.Select((int width, int i) => PadCommandString(i, getColumnData(command, i), width))) + " |"));
			File.WriteAllText(Path.Combine(AutoSaveSystem.ConfigPath, "Command.md"), contents);
		}

		public static void GenerateDefaultCommandPermissions(IEnumerable<Command> commands)
		{
			IEnumerable<string> values = commands.Select((Command command) => $"{{\"{command.PermissionKey}\", {command.PrivilegeLevel}}}");
			File.WriteAllText(Path.Combine(AutoSaveSystem.ConfigPath, "PermissionSystem.DefaultCommandPermissions.txt"), "{\n\t" + string.Join(",\n\t", values) + "\n}");
		}
	}
	public static class Cache
	{
		public static readonly LazyDictionary<FixedString64Bytes, PlayerData> NamePlayerCache = new LazyDictionary<FixedString64Bytes, PlayerData>();

		public static readonly LazyDictionary<ulong, PlayerData> SteamPlayerCache = new LazyDictionary<ulong, PlayerData>();

		public static readonly LazyDictionary<ulong, bool> PlayerClientUICache = new LazyDictionary<ulong, bool>();

		public static LazyDictionary<ulong, DateTime> playerCombatStart = new LazyDictionary<ulong, DateTime>();

		public static LazyDictionary<ulong, DateTime> playerCombatEnd = new LazyDictionary<ulong, DateTime>();

		public static LazyDictionary<ulong, float> player_level = new LazyDictionary<ulong, float>();

		public static LazyDictionary<Entity, Guid> AlliancePlayerToGroupId = new LazyDictionary<Entity, Guid>();

		public static LazyDictionary<Guid, Alliance.PlayerGroup> AlliancePlayerGroups = new LazyDictionary<Guid, Alliance.PlayerGroup>();

		public static LazyDictionary<Entity, Alliance.PlayerGroup> AllianceAutoPlayerAllies = new LazyDictionary<Entity, Alliance.PlayerGroup>();

		public static LazyDictionary<Entity, HashSet<AlliancePendingInvite>> AlliancePendingInvites = new LazyDictionary<Entity, HashSet<AlliancePendingInvite>>();

		public static LazyDictionary<Entity, LazyDictionary<UnitStatType, float>> PlayerToStatBonuses = new LazyDictionary<Entity, LazyDictionary<UnitStatType, float>>();

		public static SizedDictionaryAsync<float, SpawnNpcListen> spawnNPC_Listen = new SizedDictionaryAsync<float, SpawnNpcListen>(500);

		public static DateTime GetCombatStart(ulong steamID)
		{
			if (!playerCombatStart.TryGetValue(steamID, out var value))
			{
				return DateTime.MinValue;
			}
			return value;
		}

		public static DateTime GetCombatEnd(ulong steamID)
		{
			if (!playerCombatEnd.TryGetValue(steamID, out var value))
			{
				return DateTime.MinValue;
			}
			return value;
		}

		public static bool PlayerInCombat(ulong steamID)
		{
			return GetCombatStart(steamID) > GetCombatEnd(steamID);
		}

		public static bool PlayerHasUINotifications(ulong steamID)
		{
			bool value;
			return PlayerClientUICache.TryGetValue(steamID, out value) && value;
		}
	}
	public static class Database
	{
		public static LazyDictionary<ulong, PlayerPreferences> PlayerPreferences = new LazyDictionary<ulong, PlayerPreferences>();

		public static LazyDictionary<string, WaypointData> Waypoints = new LazyDictionary<string, WaypointData>();

		public static LazyDictionary<ulong, int> UserPermission = new LazyDictionary<ulong, int>();

		public static LazyDictionary<string, int> CommandPermission = new LazyDictionary<string, int>();

		public static LazyDictionary<ulong, PowerUpData> PowerUpList = new LazyDictionary<ulong, PowerUpData>();

		public static LazyDictionary<ulong, int> PlayerExperience = new LazyDictionary<ulong, int>();

		public static LazyDictionary<ulong, PlayerHeatData> PlayerHeat = new LazyDictionary<ulong, PlayerHeatData>();

		public static LazyDictionary<ulong, int> PlayerAbilityIncrease = new LazyDictionary<ulong, int>();

		public static LazyDictionary<ulong, LazyDictionary<UnitStatType, float>> PlayerLevelStats = new LazyDictionary<ulong, LazyDictionary<UnitStatType, float>>();

		public static LazyDictionary<string, LazyDictionary<UnitStatType, float>> ExperienceClassStats = new LazyDictionary<string, LazyDictionary<UnitStatType, float>>();

		public static LazyDictionary<ulong, DateTime> PlayerLogout = new LazyDictionary<ulong, DateTime>();

		public static LazyDictionary<ulong, LazyDictionary<GlobalMasterySystem.MasteryType, MasteryData>> PlayerMastery = new LazyDictionary<ulong, LazyDictionary<GlobalMasterySystem.MasteryType, MasteryData>>();
	}
	public static class DebugTool
	{
		private static string MaybeAddSpace(string input)
		{
			if (input.Length <= 0)
			{
				return input;
			}
			return input.TrimEnd() + " ";
		}

		private static string DebugEntity(Entity entity)
		{
			//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_0012: 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)
			EntityManager entityManager = Plugin.Server.EntityManager;
			EntityManagerDebug debug = ((EntityManager)(ref entityManager)).Debug;
			return ((EntityManagerDebug)(ref debug)).GetEntityInfo(entity);
		}

		private static string DumpEntity(Entity entity, bool fullDump = true)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder val = new StringBuilder();
			EntityDebuggingUtility.DumpEntity(Plugin.Server, entity, fullDump, val);
			return ((Object)val).ToString();
		}

		public static PrefabGUID GetAndLogPrefabGuid(Entity entity, string logPrefix = "", Plugin.LogSystem logSystem = Plugin.LogSystem.Debug, bool forceLog = false)
		{
			//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)
			PrefabGUID prefabGUID = Helper.GetPrefabGUID(entity);
			LogPrefabGuid(prefabGUID, logPrefix, logSystem, forceLog);
			return prefabGUID;
		}

		public static void LogPrefabGuid(PrefabGUID guid, string logPrefix = "", Plugin.LogSystem logSystem = Plugin.LogSystem.Debug, bool forceLog = false)
		{
			//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)
			Plugin.Log(logSystem, (LogLevel)16, () => $"{MaybeAddSpace(logPrefix)}Prefab: {GetPrefabName(guid)} ({((PrefabGUID)(ref guid)).GuidHash})", forceLog);
		}

		public static void LogEntity(Entity entity, string logPrefix = "", Plugin.LogSystem logSystem = Plugin.LogSystem.Debug, bool forceLog = false)
		{
			//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)
			Plugin.Log(logSystem, (LogLevel)16, () => $"{MaybeAddSpace(logPrefix)}{entity} - {GetPrefabName(entity)}", forceLog);
		}

		public static void LogDebugEntity(Entity entity, string logPrefix = "", Plugin.LogSystem logSystem = Plugin.LogSystem.Debug, bool forceLog = false)
		{
			//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)
			Plugin.Log(logSystem, (LogLevel)16, () => $"{MaybeAddSpace(logPrefix)}Entity: {entity} ({DebugEntity(entity)})", forceLog);
		}

		public static void LogFullEntityDebugInfo(Entity entity, string logPrefix = "", bool forceLog = false)
		{
			//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)
			Plugin.Log(Plugin.LogSystem.Debug, (LogLevel)16, () => $"{MaybeAddSpace(logPrefix)}Debug entity: {entity}\n{DumpEntity(entity)}", forceLog);
		}

		private static IEnumerable<string> BufferToEnumerable<T>(DynamicBuffer<T> buffer, Func<T, string> valueToString, string logPrefix = "")
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < buffer.Length; i++)
			{
				T arg = buffer[i];
				yield return $"{MaybeAddSpace(logPrefix)}B[{i}]: {valueToString(arg)}";
			}
		}

		public static void LogStatsBuffer(DynamicBuffer<ModifyUnitStatBuff_DOTS> buffer, string logPrefix = "", Plugin.LogSystem logSystem = Plugin.LogSystem.Debug, bool forceLog = false)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Func<ModifyUnitStatBuff_DOTS, string> valueToString = (ModifyUnitStatBuff_DOTS data) => $"{data.StatType} {data.Value} {data.ModificationType} {data.Id.Id} {data.Priority} {data.ValueByStacks} {data.IncreaseByStacks}";
			Plugin.Log(logSystem, (LogLevel)16, BufferToEnumerable(buffer, valueToString, logPrefix), forceLog);
		}

		public static void LogBuffBuffer(DynamicBuffer<BuffBuffer> buffer, string logPrefix = "", Plugin.LogSystem logSystem = Plugin.LogSystem.Debug, bool forceLog = false)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Func<BuffBuffer, string> valueToString = (BuffBuffer data) => "Prefab: " + GetPrefabName(data.PrefabGuid) + "\nDebug BuffBuffer:" + DumpEntity(data.Entity, fullDump: false);
			Plugin.Log(logSystem, (LogLevel)16, BufferToEnumerable(buffer, valueToString, logPrefix), forceLog);
		}

		public static string GetPrefabName(PrefabGUID hashCode)
		{
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			PrefabCollectionSystem existingSystemManaged = Plugin.Server.GetExistingSystemManaged<PrefabCollectionSystem>();
			string result = "Nonexistent";
			if (((PrefabGUID)(ref hashCode)).GuidHash == 0)
			{
				return result;
			}
			try
			{
				PrefabLookupMap prefabLookupMap = existingSystemManaged._PrefabLookupMap;
				return ((PrefabLookupMap)(ref prefabLookupMap)).GetName(hashCode);
			}
			catch
			{
				return "NoPrefabName";
			}
		}

		public static string GetPrefabName(Entity entity)
		{
			//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)
			return GetPrefabName(Helper.GetPrefabGUID(entity));
		}
	}
	public static class FactionHeat
	{
		public static readonly Faction[] ActiveFactions = new Faction[8]
		{
			Faction.Bandits,
			Faction.Blackfangs,
			Faction.Critters,
			Faction.Gloomrot,
			Faction.Legion,
			Faction.Militia,
			Faction.Undead,
			Faction.Werewolf
		};

		public static readonly string[] ColourGradient = new string[6] { "fef001", "ffce03", "fd9a01", "fd6104", "ff2c05", "f00505" };

		public static readonly int[] HeatLevels = new int[6] { 150, 250, 500, 1000, 1500, 3000 };

		private static readonly HashSet<Units> ExtraHeatUnits = new HashSet<Units>(FactionUnits.farmNonHostile.Select((FactionUnits.Unit u) => u.type).Union(FactionUnits.farmFood.Select((FactionUnits.Unit u) => u.type)).Union(FactionUnits.otherNonHostile.Select((FactionUnits.Unit u) => u.type)));

		public static void GetActiveFactionHeatValue(Faction faction, Units victim, bool isVBlood, out int heatValue, out Faction activeFaction)
		{
			switch (faction)
			{
			case Faction.Traders_T01:
				heatValue = 300;
				activeFaction = Faction.Bandits;
				break;
			case Faction.Bandits:
				heatValue = 10;
				activeFaction = Faction.Bandits;
				break;
			case Faction.Blackfangs_Livith:
			case Faction.Blackfangs:
				heatValue = 10;
				activeFaction = Faction.Blackfangs;
				break;
			case Faction.Militia:
				heatValue = 10;
				activeFaction = Faction.Militia;
				break;
			case Faction.ChurchOfLum_SpotShapeshiftVampire:
				heatValue = 25;
				activeFaction = Faction.Militia;
				break;
			case Faction.Traders_T02:
				heatValue = 300;
				activeFaction = Faction.Militia;
				break;
			case Faction.ChurchOfLum:
				heatValue = 15;
				activeFaction = Faction.Militia;
				break;
			case Faction.World_Prisoners:
				heatValue = 10;
				activeFaction = Faction.Militia;
				break;
			case Faction.Gloomrot:
				heatValue = 10;
				activeFaction = Faction.Gloomrot;
				break;
			case Faction.Legion:
				heatValue = 10;
				activeFaction = Faction.Legion;
				break;
			case Faction.Wolves:
			case Faction.Critters:
			case Faction.Bear:
				heatValue = 10;
				activeFaction = Faction.Critters;
				break;
			case Faction.Undead:
				heatValue = 5;
				activeFaction = Faction.Undead;
				break;
			case Faction.Werewolf:
			case Faction.WerewolfHuman:
				heatValue = 20;
				activeFaction = Faction.Werewolf;
				break;
			case Faction.VampireHunters:
				heatValue = 3;
				activeFaction = Faction.VampireHunters;
				break;
			case Faction.CorruptedBloodBuffSpawns:
			case Faction.Spiders:
			case Faction.Ignored:
			case Faction.Plants:
			case Faction.Players_Shapeshift_Human:
			case Faction.Spiders_Shapeshifted:
			case Faction.Wendigo:
			case Faction.Players_Castle_Prisoners:
			case Faction.Mutants:
			case Faction.Unknown:
			case Faction.Corrupted:
			case Faction.ChurchOfLum_Slaves:
			case Faction.ChurchOfLum_Slaves_Rioters:
			case Faction.Players:
			case Faction.Elementals:
			case Faction.Cursed:
			case Faction.NatureSpirit:
			case Faction.Harpy:
			case Faction.Players_Mutant:
				heatValue = 0;
				activeFaction = Faction.Unknown;
				break;
			default:
				Plugin.Log(Plugin.LogSystem.Wanted, (LogLevel)4, "Faction not handled for GetActiveFactionHeatValue: " + Enum.GetName(faction));
				heatValue = 0;
				activeFaction = Faction.Unknown;
				break;
			}
			if (isVBlood)
			{
				heatValue *= WantedSystem.vBloodMultiplier;
			}
			else if (ExtraHeatUnits.Contains(victim))
			{
				heatValue = (int)((double)heatValue * 1.5);
			}
		}

		public static string GetFactionStatus(Faction faction, int heat)
		{
			string seed = Enum.GetName(faction) + ": ";
			return HeatLevels.Aggregate(seed, (string current, int t) => current + ((heat < t) ? "☆" : "★"));
		}

		public static int GetWantedLevel(int heat)
		{
			for (int i = 0; i < HeatLevels.Length; i++)
			{
				if (HeatLevels[i] > heat)
				{
					return i;
				}
			}
			return HeatLevels.Length;
		}

		public static void Ambush(Entity userEntity, float3 position, Faction faction, int wantedLevel)
		{
			//IL_000a: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			if (wantedLevel >= 1)
			{
				EntityManager entityManager = Plugin.Server.EntityManager;
				string replacement = SquadList.SpawnSquad(ExperienceSystem.GetLevel(((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity).PlatformId), position, faction, wantedLevel);
				L10N.LocalisableString message = L10N.Get(L10N.TemplateKey.WantedFactionHeatStatus).AddField("{colour}", ColourGradient[wantedLevel - 1]).AddField("{squadMessage}", replacement);
				Output.SendMessage(userEntity, message);
			}
		}

		public static void Ambush(float3 position, List<Alliance.ClosePlayer> closeAllies, Faction faction, int wantedLevel)
		{
			//IL_0037: 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_00b2: 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)
			if (wantedLevel < 1 || closeAllies.Count == 0)
			{
				return;
			}
			string text = SquadList.SpawnSquad(closeAllies.MaxBy((Alliance.ClosePlayer ally) => ally.playerLevel).playerLevel, position, faction, wantedLevel);
			foreach (Alliance.ClosePlayer closeAlly in closeAllies)
			{
				L10N.LocalisableString message = L10N.Get(L10N.TemplateKey.WantedFactionHeatStatus).AddField("{colour}", ColourGradient[wantedLevel - 1]).AddField("{squadMessage}", text);
				if (Cache.PlayerHasUINotifications(closeAlly.userComponent.PlatformId))
				{
					Utils.ServerSendNotification(closeAlly.userComponent, "Ambush!", text, (LogLevel)16, "#" + ColourGradient[wantedLevel - 1]);
				}
				else
				{
					Output.SendMessage(closeAlly.userEntity, message);
				}
			}
		}
	}
	public static class FactionUnits
	{
		public struct Unit
		{
			public Units type { get; }

			public int level { get; }

			public int value { get; }

			public Unit(Units type, int level, int value)
			{
				this.type = type;
				this.level = level;
				this.value = value;
			}
		}

		private static Unit[] bandit_units = new Unit[11]
		{
			new Unit(Units.CHAR_Bandit_Rascal, 10, 1),
			new Unit(Units.CHAR_Bandit_Scout, 10, 1),
			new Unit(Units.CHAR_Bandit_Wolf, 14, 1),
			new Unit(Units.CHAR_Bandit_Hunter, 16, 2),
			new Unit(Units.CHAR_Bandit_Thug, 16, 2),
			new Unit(Units.CHAR_Bandit_Thief, 18, 3),
			new Unit(Units.CHAR_Bandit_Mugger, 20, 3),
			new Unit(Units.CHAR_Bandit_Trapper, 20, 3),
			new Unit(Units.CHAR_Bandit_Deadeye, 26, 4),
			new Unit(Units.CHAR_Bandit_Stalker, 30, 4),
			new Unit(Units.CHAR_Bandit_Bomber, 32, 4)
		};

		private static Unit[] church = new Unit[14]
		{
			new Unit(Units.CHAR_ChurchOfLight_Miner_Standard, 42, 1),
			new Unit(Units.CHAR_ChurchOfLight_Archer, 56, 1),
			new Unit(Units.CHAR_ChurchOfLight_SlaveRuffian, 60, 1),
			new Unit(Units.CHAR_ChurchOfLight_Cleric, 62, 2),
			new Unit(Units.CHAR_ChurchOfLight_Footman, 62, 2),
			new Unit(Units.CHAR_ChurchOfLight_Rifleman, 62, 2),
			new Unit(Units.CHAR_ChurchOfLight_SlaveMaster_Enforcer, 64, 3),
			new Unit(Units.CHAR_ChurchOfLight_SlaveMaster_Sentry, 64, 3),
			new Unit(Units.CHAR_ChurchOfLight_Knight_2H, 68, 3),
			new Unit(Units.CHAR_ChurchOfLight_Knight_Shield, 68, 3),
			new Unit(Units.CHAR_ChurchOfLight_CardinalAide, 70, 4),
			new Unit(Units.CHAR_ChurchOfLight_Lightweaver, 72, 4),
			new Unit(Units.CHAR_ChurchOfLight_Paladin, 74, 4),
			new Unit(Units.CHAR_ChurchOfLight_Priest, 74, 4)
		};

		private static Unit[] church_elite = new Unit[1]
		{
			new Unit(Units.CHAR_Paladin_DivineAngel, 80, 5)
		};

		private static Unit[] church_extra = new Unit[1]
		{
			new Unit(Units.CHAR_Militia_EyeOfGod, 0, 1)
		};

		private static Unit[] cultist_units = new Unit[3]
		{
			new Unit(Units.CHAR_Scarecrow, 54, 1),
			new Unit(Units.CHAR_Cultist_Pyromancer, 60, 2),
			new Unit(Units.CHAR_Cultist_Slicer, 60, 2)
		};

		private static Unit[] cursed_units = new Unit[13]
		{
			new Unit(Units.CHAR_Cursed_MonsterToad, 61, 1),
			new Unit(Units.CHAR_Cursed_ToadSpitter, 61, 1),
			new Unit(Units.CHAR_Cursed_Witch_Exploding_Mosquito, 61, 1),
			new Unit(Units.CHAR_Cursed_MonsterToad_Minion, 62, 1),
			new Unit(Units.CHAR_Cursed_Mosquito, 62, 1),
			new Unit(Units.CHAR_Cursed_Wolf, 62, 1),
			new Unit(Units.CHAR_Cursed_WormTerror, 62, 2),
			new Unit(Units.CHAR_Cursed_Bear_Standard, 64, 2),
			new Unit(Units.CHAR_Cursed_Nightlurker, 64, 2),
			new Unit(Units.CHAR_Cursed_Witch, 72, 3),
			new Unit(Units.CHAR_Cursed_Bear_Spirit, 80, 3),
			new Unit(Units.CHAR_Cursed_Wolf_Spirit, 80, 3),
			new Unit(Units.CHAR_Cursed_MountainBeast_SpiritDouble, 83, 5)
		};

		private static Unit[] farmlands = new Unit[8]
		{
			new Unit(Units.CHAR_Farmlands_HostileVillager_Female_FryingPan, 28, 1),
			new Unit(Units.CHAR_Farmlands_HostileVillager_Female_Pitchfork, 28, 1),
			new Unit(Units.CHAR_Farmlands_HostileVillager_Male_Club, 28, 1),
			new Unit(Units.CHAR_Farmlands_HostileVillager_Male_Shovel, 28, 1),
			new Unit(Units.CHAR_Farmlands_HostileVillager_Male_Torch, 28, 1),
			new Unit(Units.CHAR_Farmlands_HostileVillager_Male_Unarmed, 28, 1),
			new Unit(Units.CHAR_Farmlands_Woodcutter_Standard, 34, 1),
			new Unit(Units.CHAR_Farmland_Wolf, 40, 1)
		};

		public static Unit[] farmNonHostile = new Unit[4]
		{
			new Unit(Units.CHAR_Farmlands_Villager_Female_Sister, 20, 1),
			new Unit(Units.CHAR_Farmlands_Villager_Female, 26, 1),
			new Unit(Units.CHAR_Farmlands_Villager_Male, 26, 1),
			new Unit(Units.CHAR_Farmlands_Farmer, 34, 1)
		};

		public static Unit[] farmFood = new Unit[6]
		{
			new Unit(Units.CHAR_Farmlands_SheepOld, 10, 1),
			new Unit(Units.CHAR_Farmlands_SmallPig, 20, 1),
			new Unit(Units.CHAR_Farmlands_Pig, 24, 1),
			new Unit(Units.CHAR_Farmlands_Cow, 30, 1),
			new Unit(Units.CHAR_Farmlands_Sheep, 36, 1),
			new Unit(Units.CHAR_Farmlands_Ram, 38, 1)
		};

		public static Unit[] otherNonHostile = new Unit[4]
		{
			new Unit(Units.CHAR_ChurchOfLight_Villager_Female, 1, 1),
			new Unit(Units.CHAR_ChurchOfLight_Villager_Male, 1, 1),
			new Unit(Units.CHAR_Gloomrot_Villager_Female, 1, 1),
			new Unit(Units.CHAR_Gloomrot_Villager_Male, 1, 1)
		};

		private static Unit[] forest = new Unit[8]
		{
			new Unit(Units.CHAR_Forest_Wolf, 10, 1),
			new Unit(Units.CHAR_Forest_AngryMoose, 16, 2),
			new Unit(Units.CHAR_Forest_Bear_Standard, 18, 2),
			new Unit(Units.CHAR_Forest_Crow, 14, 1),
			new Unit(Units.CHAR_Ocean_Blowfish, 26, 1),
			new Unit(Units.CHAR_Ocean_Piranha, 26, 1),
			new Unit(Units.CHAR_SeaSerpent, 27, 1),
			new Unit(Units.CHAR_SeaSerpent_Hard, 28, 2)
		};

		private static Unit[] gloomrot = new Unit[14]
		{
			new Unit(Units.CHAR_Gloomrot_Pyro, 56, 1),
			new Unit(Units.CHAR_Gloomrot_Batoon, 58, 1),
			new Unit(Units.CHAR_Gloomrot_Railgunner, 58, 1),
			new Unit(Units.CHAR_Gloomrot_Tazer, 58, 1),
			new Unit(Units.CHAR_Gloomrot_Technician, 58, 1),
			new Unit(Units.CHAR_Gloomrot_Technician_Labworker, 58, 1),
			new Unit(Units.CHAR_Gloomrot_TractorBeamer, 58, 1),
			new Unit(Units.CHAR_Gloomrot_SentryOfficer, 60, 2),
			new Unit(Units.CHAR_Gloomrot_SentryTurret, 60, 1),
			new Unit(Units.CHAR_Gloomrot_SpiderTank_Driller, 60, 2),
			new Unit(Units.CHAR_Gloomrot_AceIncinerator, 74, 2),
			new Unit(Units.CHAR_Gloomrot_SpiderTank_LightningRod, 74, 4),
			new Unit(Units.CHAR_Gloomrot_SpiderTank_Gattler, 77, 4),
			new Unit(Units.CHAR_Gloomrot_SpiderTank_Zapper, 77, 4)
		};

		private static Unit[] harpy = new Unit[4]
		{
			new Unit(Units.CHAR_Harpy_Dasher, 66, 1),
			new Unit(Units.CHAR_Harpy_FeatherDuster, 66, 1),
			new Unit(Units.CHAR_Harpy_Sorceress, 68, 1),
			new Unit(Units.CHAR_Harpy_Scratcher, 70, 1)
		};

		private static Unit[] militia_units = new Unit[14]
		{
			new Unit(Units.CHAR_Militia_Hound, 36, 1),
			new Unit(Units.CHAR_Militia_Light, 36, 1),
			new Unit(Units.CHAR_Militia_Rider, 36, 1),
			new Unit(Units.CHAR_Militia_Torchbearer, 36, 2),
			new Unit(Units.CHAR_Militia_InkCrawler, 38, 2),
			new Unit(Units.CHAR_Militia_Guard, 40, 1),
			new Unit(Units.CHAR_Militia_Longbowman, 42, 3),
			new Unit(Units.CHAR_Militia_Nun, 42, 3),
			new Unit(Units.CHAR_Militia_Horseman_Mount, 43, 2),
			new Unit(Units.CHAR_Militia_Bomber, 47, 1),
			new Unit(Units.CHAR_Militia_Miner_Standard, 50, 1),
			new Unit(Units.CHAR_Militia_Heavy, 54, 3),
			new Unit(Units.CHAR_Militia_Devoted, 56, 2),
			new Unit(Units.CHAR_Militia_Crossbow, 70, 2)
		};

		private static Unit[] vhunter = new Unit[3]
		{
			new Unit(Units.CHAR_VHunter_Leader_VBlood, 44, 5),
			new Unit(Units.CHAR_VHunter_Jade_VBlood, 57, 5),
			new Unit(Units.CHAR_VHunter_CastleMan, 65, 5)
		};

		private static Unit[] wtf = new Unit[1]
		{
			new Unit(Units.CHAR_ChurchOfLight_Sommelier_BarrelMinion, 50, 1)
		};

		private static Unit[] spiders = new Unit[7]
		{
			new Unit(Units.CHAR_Spider_Forestling, 20, 1),
			new Unit(Units.CHAR_Spider_Forest, 26, 1),
			new Unit(Units.CHAR_Spider_Baneling, 56, 1),
			new Unit(Units.CHAR_Spider_Spiderling, 56, 1),
			new Unit(Units.CHAR_Spider_Melee, 58, 2),
			new Unit(Units.CHAR_Spider_Range, 58, 2),
			new Unit(Units.CHAR_Spider_Broodmother, 60, 4)
		};

		private static Unit[] golems = new Unit[8]
		{
			new Unit(Units.CHAR_IronGolem, 36, 1),
			new Unit(Units.CHAR_StoneGolem, 36, 1),
			new Unit(Units.CHAR_CopperGolem, 42, 1),
			new Unit(Units.CHAR_RockElemental, 50, 1),
			new Unit(Units.CHAR_Treant, 57, 1),
			new Unit(Units.CHAR_IceElemental, 60, 1),
			new Unit(Units.CHAR_EmeryElemental, 76, 1),
			new Unit(Units.CHAR_EmeryGolem, 80, 1)
		};

		private static Unit[] mutants = new Unit[5]
		{
			new Unit(Units.CHAR_Mutant_RatHorror, 58, 1),
			new Unit(Units.CHAR_Mutant_FleshGolem, 60, 2),
			new Unit(Units.CHAR_Mutant_Wolf, 64, 1),
			new Unit(Units.CHAR_Mutant_Spitter, 70, 2),
			new Unit(Units.CHAR_Mutant_Bear_Standard, 74, 2)
		};

		private static Unit[] undead_minions = new Unit[41]
		{
			new Unit(Units.CHAR_Undead_SkeletonSoldier_TombSummon, 1, 1),
			new Unit(Units.CHAR_Undead_SkeletonSoldier_Withered, 1, 1),
			new Unit(Units.CHAR_Undead_SkeletonCrossbow_Graveyard, 2, 1),
			new Unit(Units.CHAR_Undead_RottingGhoul, 4, 1),
			new Unit(Units.CHAR_Undead_ArmoredSkeletonCrossbow_Farbane, 18, 1),
			new Unit(Units.CHAR_Undead_SkeletonCrossbow_GolemMinion, 18, 1),
			new Unit(Units.CHAR_Undead_SkeletonCrossbow_Farbane_OLD, 20, 1),
			new Unit(Units.CHAR_Undead_SkeletonSoldier_Armored_Farbane, 20, 1),
			new Unit(Units.CHAR_Undead_SkeletonSoldier_GolemMinion, 20, 1),
			new Unit(Units.CHAR_Undead_SkeletonApprentice, 22, 1),
			new Unit(Units.CHAR_Undead_UndyingGhoul, 25, 2),
			new Unit(Units.CHAR_Graveyard_Crow, 27, 1),
			new Unit(Units.CHAR_Undead_Priest, 27, 3),
			new Unit(Units.CHAR_Undead_Ghoul_TombSummon, 30, 1),
			new Unit(Units.CHAR_Undead_FlyingSkull, 32, 2),
			new Unit(Units.CHAR_Undead_Assassin, 35, 3),
			new Unit(Units.CHAR_Undead_ArmoredSkeletonCrossbow_Dunley, 38, 1),
			new Unit(Units.CHAR_Undead_SkeletonGolem, 38, 3),
			new Unit(Units.CHAR_Undead_Ghoul_Armored_Farmlands, 40, 2),
			new Unit(Units.CHAR_Undead_SkeletonSoldier_Armored_Dunley, 40, 2),
			new Unit(Units.CHAR_Undead_SkeletonSoldier_Infiltrator, 40, 1),
			new Unit(Units.CHAR_Undead_Guardian, 42, 2),
			new Unit(Units.CHAR_Undead_Necromancer, 46, 3),
			new Unit(Units.CHAR_Undead_Necromancer_TombSummon, 46, 3),
			new Unit(Units.CHAR_Undead_SkeletonMage, 44, 3),
			new Unit(Units.CHAR_Vampire_Withered, 52, 1),
			new Unit(Units.CHAR_Undead_CursedSmith_FloatingWeapon_Axe, 60, 3),
			new Unit(Units.CHAR_Undead_CursedSmith_FloatingWeapon_Base, 60, 3),
			new Unit(Units.CHAR_Undead_CursedSmith_FloatingWeapon_Mace, 60, 3),
			new Unit(Units.CHAR_Undead_CursedSmith_FloatingWeapon_Slashers, 60, 3),
			new Unit(Units.CHAR_Undead_CursedSmith_FloatingWeapon_Spear, 60, 3),
			new Unit(Units.CHAR_Undead_CursedSmith_FloatingWeapon_Sword, 60, 3),
			new Unit(Units.CHAR_Undead_ShadowSoldier, 60, 2),
			new Unit(Units.CHAR_Undead_SkeletonSoldier_Base, 60, 1),
			new Unit(Units.CHAR_Undead_GhostMilitia_Crossbow, 63, 2),
			new Unit(Units.CHAR_Undead_GhostMilitia_Light, 63, 2),
			new Unit(Units.CHAR_Undead_ZealousCultist_Ghost, 64, 1),
			new Unit(Units.CHAR_Undead_GhostAssassin, 65, 3),
			new Unit(Units.CHAR_Undead_GhostBanshee, 65, 3),
			new Unit(Units.CHAR_Undead_GhostBanshee_TombSummon, 65, 3),
			new Unit(Units.CHAR_Undead_GhostGuardian, 65, 3)
		};

		private static Unit[] werewolves = new Unit[1]
		{
			new Unit(Units.CHAR_Farmlands_HostileVillager_Werewo