Decompiled source of GTFuckingXP v2.8.0

EndskApi.dll

Decompiled 2 days ago
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
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.Json;
using System.Text.Json.Serialization;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BoosterImplants;
using CellMenu;
using EndskApi.Api;
using EndskApi.Enums.EnemyKill;
using EndskApi.Enums.Menus;
using EndskApi.Information.Configs;
using EndskApi.Information.EnemyKill;
using EndskApi.Information.Menus;
using EndskApi.Information.WeaponSwitcher;
using EndskApi.Manager;
using EndskApi.Manager.Internal;
using EndskApi.Patches.Checkpoint;
using EndskApi.Patches.EndLevel;
using EndskApi.Patches.Enemy;
using EndskApi.Patches.Init;
using EndskApi.Patches.StartLevel;
using EndskApi.Scripts;
using Enemies;
using GTFO.API;
using GameData;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("EndskApi")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+git33620c7-dirty-master.33620c7e9766136dea115db87926bb0ec5e6969c")]
[assembly: AssemblyProduct("EndskApi")]
[assembly: AssemblyTitle("EndskApi")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
}
namespace EndskApi
{
	[BepInPlugin("Endskill.EndskApi", "EndskApi", "1.3.1")]
	public class BepInExLoader : BasePlugin
	{
		public const string MODNAME = "EndskApi";

		public const string AUTHOR = "Endskill";

		public const string GUID = "Endskill.EndskApi";

		public const string VERSION = "1.3.1";

		public static Harmony Harmony { get; private set; }

		public static ConfigFile ConfigLoader { get; private set; }

		public override void Load()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			LogManager.SetLogger(((BasePlugin)this).Log);
			LogManager._debugMessagesActive = ((BasePlugin)this).Config.Bind<bool>("Dev Settings", "DebugMessages", false, "This settings activates/deactivates debug messages in the console for this specific plugin.").Value;
			ConfigLoader = ((BasePlugin)this).Config;
			ClassInjector.RegisterTypeInIl2Cpp<BaseMenu>();
			ClassInjector.RegisterTypeInIl2Cpp<MainMenu>();
			Harmony = new Harmony("Endskill.EndskApi");
		}
	}
	[GeneratedCode("VersionInfoGenerator", "2.1.3+git35c0c2a-master")]
	[CompilerGenerated]
	internal static class VersionInfo
	{
		public const string RootNamespace = "EndskApi";

		public const string Version = "1.0.0";

		public const string VersionPrerelease = null;

		public const string VersionMetadata = "git33620c7-dirty-master";

		public const string SemVer = "1.0.0+git33620c7-dirty-master";

		public const string GitRevShort = "33620c7-dirty";

		public const string GitRevLong = "33620c7e9766136dea115db87926bb0ec5e6969c-dirty";

		public const string GitBranch = "master";

		public const string GitTag = null;

		public const int GitCommitsSinceTag = 0;

		public const bool GitIsDirty = true;
	}
}
namespace EndskApi.Util
{
	public static class MtfoUtils
	{
		public static string CustomPath { get; private set; }

		public static string Version { get; private set; }

		public static bool PluginExists { get; private set; }

		static MtfoUtils()
		{
			CustomPath = string.Empty;
			Version = string.Empty;
			PluginExists = false;
			if (!((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("com.dak.MTFO", out var info))
			{
				return;
			}
			PluginExists = true;
			try
			{
				Assembly? assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly x) => !x.IsDynamic && x.Location == info.Location);
				if (assembly == null)
				{
					throw new Exception("couldn't locate the MTFO assembly");
				}
				Type[] types = assembly.GetTypes();
				Type type = types.FirstOrDefault((Type x) => x.Name == "ConfigManager");
				Type? type2 = types.FirstOrDefault((Type x) => x.Name == "MTFO");
				if (type2 == null)
				{
					throw new Exception("couldn't locate MTFO's EntryPoint");
				}
				if (type == null)
				{
					throw new Exception("couldn't locate MTFO's ConfigManager");
				}
				FieldInfo? field = type2.GetField("VERSION", BindingFlags.Static | BindingFlags.Public);
				FieldInfo field2 = type.GetField("CustomPath", BindingFlags.Static | BindingFlags.Public);
				if (field == null)
				{
					throw new Exception("couldn't locate MTFO's Version");
				}
				if (field2 == null)
				{
					throw new Exception("couldn't locate MTFO's CustomPath");
				}
				CustomPath = (string)field2.GetValue(null);
				Version = (string)field.GetValue(null);
				types.FirstOrDefault((Type x) => x.Name == "HotReloader");
			}
			catch (Exception ex)
			{
				LogManager.Error(ex.ToString());
			}
		}
	}
}
namespace EndskApi.Scripts
{
	public class BaseMenu : MonoBehaviour
	{
		protected static string _currentGeomorph;

		protected static bool _guiInitialized = false;

		protected static GUIStyle _normalStyle;

		protected static GUIStyle _titleStyle;

		protected static readonly float _menuX = 30f;

		protected static readonly float _menuY = (float)(Screen.height / 2) - 100f;

		protected MenuStates _currentState;

		protected List<Tool> _tools;

		public string PageTitle { get; set; }

		protected static string PageTitlePostfix { get; set; } = "";

		public BaseMenu(IntPtr intPtr)
			: base(intPtr)
		{
			_tools = new List<Tool>();
		}

		protected virtual void Update()
		{
			if (_currentState != MenuStates.Deactivated)
			{
				DefaultCheatsInputCheck();
			}
		}

		protected virtual void OnGUI()
		{
			if (_currentState == MenuStates.Active)
			{
				CreateUi(_tools, PageTitle);
			}
		}

		public virtual void SetState(MenuStates newState)
		{
			_currentState = newState;
			if (newState == MenuStates.Deactivated)
			{
				((Behaviour)this).enabled = false;
			}
			else
			{
				((Behaviour)this).enabled = true;
			}
		}

		protected void DefaultCheatsInputCheck()
		{
			foreach (Tool tool in _tools)
			{
				if (tool.CheckInput.CheckKeyDown())
				{
					tool.UseTool(tool);
				}
			}
		}

		[HideFromIl2Cpp]
		public static void CreateUi(List<Tool> cheats, string pageTitle)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//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_0049: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (!_guiInitialized)
			{
				_titleStyle = new GUIStyle(GUI.skin.GetStyle("label"))
				{
					fontSize = 22
				};
				_normalStyle = new GUIStyle(GUI.skin.GetStyle("label"))
				{
					fontSize = 20
				};
				_guiInitialized = true;
			}
			GUI.contentColor = Color.white;
			GUI.Label(new Rect(_menuX, _menuY - 25f, 400f, 30f), _currentGeomorph, _normalStyle);
			GUI.Label(new Rect(_menuX, _menuY, 400f, 30f), pageTitle + PageTitlePostfix, _titleStyle);
			float num = 25f;
			foreach (Tool cheat in cheats)
			{
				GUI.Label(new Rect(_menuX, _menuY + num, 400f, 30f), cheat.ToString(), _normalStyle);
				num += 22f;
			}
		}

		[HideFromIl2Cpp]
		protected void ToggleTool(Tool cheat)
		{
			cheat.Toggle();
		}
	}
	internal class MainMenu : BaseMenu
	{
		private Dictionary<Tool, BaseMenu> _toolToMenuMap;

		private List<BaseMenu> _unknownMenus;

		private List<IExtendedTool> _middleMouseClickTools = new List<IExtendedTool>();

		private List<IExtendedTool> _timedTools = new List<IExtendedTool>();

		private List<Tool> _hiddenTools = new List<Tool>();

		private float _lastToolActive = Time.time;

		private (uint enemyId, string enemyName)[] _enemyNamesIdMap;

		private int _currentEnemyIndex;

		private int _keypadCounter;

		[HideFromIl2Cpp]
		internal static MainMenu Instance { get; private set; }

		public int CurrentEnemyIndex
		{
			get
			{
				return _currentEnemyIndex;
			}
			set
			{
				if (value >= _enemyNamesIdMap.Count() || value < 0)
				{
					value = _currentEnemyIndex;
				}
				_currentEnemyIndex = value;
				BaseMenu.PageTitlePostfix = ": " + _enemyNamesIdMap[value].enemyName;
			}
		}

		public MainMenu(IntPtr intPtr)
			: base(intPtr)
		{
			base.PageTitle = "MainMenu";
			_toolToMenuMap = new Dictionary<Tool, BaseMenu>();
			_unknownMenus = new List<BaseMenu>();
			_currentState = MenuStates.HiddenAndActive;
			Instance = this;
		}

		public void Awake()
		{
			Il2CppArrayBase<EnemyDataBlock> allBlocks = GameDataBlockBase<EnemyDataBlock>.GetAllBlocks();
			_enemyNamesIdMap = new(uint, string)[allBlocks.Count];
			for (int i = 0; i < allBlocks.Count; i++)
			{
				_enemyNamesIdMap[i] = (enemyId: ((GameDataBlockBase<EnemyDataBlock>)(object)allBlocks[i]).persistentID, enemyName: ((GameDataBlockBase<EnemyDataBlock>)(object)allBlocks[i]).name);
			}
			CurrentEnemyIndex = 0;
		}

		[HideFromIl2Cpp]
		public void ActivateUnknownMenu<TScript>(TScript menu) where TScript : BaseMenu
		{
			MenuToggleUpdated(null, newToggle: false);
			_currentState = MenuStates.HiddenAndActive;
			_unknownMenus.Add(menu);
		}

		[HideFromIl2Cpp]
		public void AddPage(string ToolName, BaseMenu menu)
		{
			AddPage(new Tool(ToolName, GetFreeKeypadInput(), isToggle: false, base.ToggleTool, MenuToggleUpdated), menu);
		}

		[HideFromIl2Cpp]
		public void AddPage(Tool Tool, BaseMenu menu)
		{
			_toolToMenuMap.Add(Tool, menu);
			_tools.Add(Tool);
			_currentState = MenuStates.Active;
		}

		[HideFromIl2Cpp]
		public void AddMiddleMouseClickTool(IExtendedTool Tool)
		{
			_middleMouseClickTools.Add(Tool);
		}

		[HideFromIl2Cpp]
		public void RemoveMiddleMouseClickTool(IExtendedTool Tool)
		{
			_middleMouseClickTools.Remove(Tool);
		}

		[HideFromIl2Cpp]
		public void AddTimedTool(IExtendedTool tool)
		{
			_timedTools.Add(tool);
		}

		[HideFromIl2Cpp]
		public void RemoveTimedTool(IExtendedTool tool)
		{
			_timedTools.Remove(tool);
		}

		[HideFromIl2Cpp]
		public void AddHiddenTool(Tool tool)
		{
			_hiddenTools.Add(tool);
		}

		[HideFromIl2Cpp]
		public void RemoveHiddenTool(Tool tool)
		{
			_hiddenTools.Remove(tool);
		}

		protected override void Update()
		{
			if (Input.GetKeyDown((KeyCode)277))
			{
				if (_currentState == MenuStates.Active || _currentState == MenuStates.HiddenAndActive)
				{
					_currentState = MenuStates.Deactivated;
				}
				else
				{
					_currentState = MenuStates.Active;
				}
				foreach (KeyValuePair<Tool, BaseMenu> item in _toolToMenuMap)
				{
					item.Key.CurrentToggleState = false;
					item.Value.SetState(MenuStates.Deactivated);
				}
			}
			if (_currentState != MenuStates.Deactivated)
			{
				foreach (Tool hiddenTool in _hiddenTools)
				{
					if (hiddenTool.CheckInput.CheckKeyDown())
					{
						hiddenTool.UseTool(hiddenTool);
					}
				}
			}
			base.Update();
			MainMenuSpecificUpdate();
		}

		private void MainMenuSpecificUpdate()
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Invalid comparison between Unknown and I4
			if (Input.GetKeyDown((KeyCode)275))
			{
				CurrentEnemyIndex++;
			}
			if (Input.GetKeyDown((KeyCode)276))
			{
				CurrentEnemyIndex--;
			}
			if (Input.GetMouseButtonDown(2))
			{
				foreach (IExtendedTool middleMouseClickTool in _middleMouseClickTools)
				{
					middleMouseClickTool.ExtraToolAction(GetInformationPackage(middleMouseClickTool.InformationId));
				}
			}
			if (!(_lastToolActive < Time.time))
			{
				return;
			}
			foreach (IExtendedTool timedTool in _timedTools)
			{
				timedTool.ExtraToolAction(GetInformationPackage(timedTool.InformationId));
			}
			if ((int)GameStateManager.CurrentStateName == 10)
			{
				BaseMenu._currentGeomorph = ((Object)((Agent)PlayerManager.GetLocalPlayerAgent()).CourseNode.m_area.m_geomorph).name;
			}
			else
			{
				BaseMenu._currentGeomorph = "";
			}
			_lastToolActive = Time.time + 0.25f;
		}

		[HideFromIl2Cpp]
		private object GetInformationPackage(InformationId id)
		{
			return id switch
			{
				InformationId.None => null, 
				InformationId.EnemyId => _enemyNamesIdMap[CurrentEnemyIndex], 
				_ => null, 
			};
		}

		[HideFromIl2Cpp]
		private void MenuToggleUpdated(Tool Tool, bool newToggle)
		{
			foreach (BaseMenu unknownMenu in _unknownMenus)
			{
				unknownMenu.SetState(MenuStates.Deactivated);
			}
			_unknownMenus.Clear();
			foreach (KeyValuePair<Tool, BaseMenu> item in _toolToMenuMap)
			{
				if (item.Key.Equals(Tool))
				{
					item.Value.SetState((!newToggle) ? MenuStates.Deactivated : MenuStates.Active);
					item.Key.CurrentToggleState = newToggle;
				}
				else
				{
					item.Key.CurrentToggleState = false;
					item.Value.SetState(MenuStates.Deactivated);
				}
			}
			_currentState = (_toolToMenuMap.Any<KeyValuePair<Tool, BaseMenu>>((KeyValuePair<Tool, BaseMenu> it) => it.Key.CurrentToggleState) ? MenuStates.HiddenAndActive : MenuStates.Active);
		}

		[HideFromIl2Cpp]
		private InputTool GetFreeKeypadInput()
		{
			_keypadCounter++;
			switch (_keypadCounter)
			{
			case 1:
				return MenuInputProvider.KeyPad1;
			case 2:
				return MenuInputProvider.KeyPad2;
			case 3:
				return MenuInputProvider.KeyPad3;
			case 4:
				return MenuInputProvider.KeyPad4;
			case 5:
				return MenuInputProvider.KeyPad5;
			case 6:
				return MenuInputProvider.KeyPad6;
			case 7:
				return MenuInputProvider.KeyPad7;
			case 8:
				return MenuInputProvider.KeyPad8;
			case 9:
				return MenuInputProvider.KeyPad9;
			default:
				LogManager.Error("There are no free Keypad keys, for the added Menu page!\nPlease ask @Endskill#4992 to finally do his Page system.");
				throw new IndexOutOfRangeException("There are no free keypad keys to add this specific page.");
			}
		}
	}
}
namespace EndskApi.Patches.StartLevel
{
	[HarmonyPatch(typeof(GS_InLevel))]
	internal class GsInLevelPatches
	{
		[HarmonyPatch("Enter")]
		[HarmonyPostfix]
		public static void EnterLevelPostfix()
		{
			LevelApi.InvokeStartLevelCallbacks();
		}
	}
}
namespace EndskApi.Patches.Init
{
	[HarmonyPatch(typeof(GuiManager))]
	internal class GUIManagerPatches
	{
		[HarmonyPatch("Setup")]
		[HarmonyPrefix]
		[HarmonyWrapSafe]
		public static void SetupPrefix()
		{
			InitApi.InvokeInitCallbacks();
		}
	}
	[HarmonyPatch(typeof(CM_PageRundown_New))]
	internal class PageRundownNewPatches
	{
		[HarmonyPatch("PlaceRundown")]
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		public static void PlaceRundownPostFix()
		{
			InitApi.InvokeInitCallbacks();
		}
	}
}
namespace EndskApi.Patches.Enemy
{
	[HarmonyBefore(new string[] { "Endskill.EndskApi", "com.dak.DamageNumbers" })]
	[HarmonyPatch(typeof(Dam_EnemyDamageBase))]
	internal class EnemyDamageBasePatches
	{
		[HarmonyPatch("ReceiveMeleeDamage")]
		[HarmonyPrefix]
		public static void MeleePrefix(Dam_EnemyDamageBase __instance, ref pFullDamageData data)
		{
			EnemyDamageBasePatchApi.InvokeReceiveMeleePrefix(__instance, ref data);
		}

		[HarmonyPatch("ReceiveMeleeDamage")]
		[HarmonyPostfix]
		public static void MeleePostfix(Dam_EnemyDamageBase __instance, ref pFullDamageData data)
		{
			EnemyDamageBasePatchApi.InvokeReceiveMeleePostfix(__instance, ref data);
		}

		[HarmonyPatch("ReceiveBulletDamage")]
		[HarmonyPrefix]
		public static void BulletPrefix(Dam_EnemyDamageBase __instance, ref pBulletDamageData data)
		{
			EnemyDamageBasePatchApi.InvokeReceiveBulletPrefix(__instance, ref data);
		}

		[HarmonyPatch("ReceiveBulletDamage")]
		[HarmonyPostfix]
		public static void BulletPostfix(Dam_EnemyDamageBase __instance, ref pBulletDamageData data)
		{
			EnemyDamageBasePatchApi.InvokeReceiveBulletPostfix(__instance, ref data);
		}

		[HarmonyPatch("ReceiveExplosionDamage")]
		[HarmonyPrefix]
		public static void ExplosionPrefix(Dam_EnemyDamageBase __instance, ref pExplosionDamageData data)
		{
			EnemyDamageBasePatchApi.InvokeReceiveExplosionPrefix(__instance, ref data);
		}

		[HarmonyPatch("ReceiveExplosionDamage")]
		[HarmonyPostfix]
		public static void ExplosionPostfix(Dam_EnemyDamageBase __instance, ref pExplosionDamageData data)
		{
			EnemyDamageBasePatchApi.InvokeReceiveExplosionPostfix(__instance, ref data);
		}
	}
	[HarmonyPatch]
	internal static class EnemyTagPatches
	{
		private static bool _inBotTag;

		[HarmonyPatch(typeof(EnemyScanner), "BotTag")]
		[HarmonyPrefix]
		private static void Pre_BotTag()
		{
			_inBotTag = true;
		}

		[HarmonyPatch(typeof(EnemyScanner), "BotTag")]
		[HarmonyPostfix]
		private static void Post_BotTag()
		{
			_inBotTag = false;
		}

		[HarmonyPatch(typeof(ToolSyncManager), "WantToTagEnemy")]
		[HarmonyPostfix]
		private static void Post_TagEnemy(EnemyAgent enemy)
		{
			if (!_inBotTag)
			{
				NetworkManager.SendBiotag(enemy);
			}
		}
	}
	[HarmonyPatch(typeof(MineDeployerInstance_Detonate_Explosive))]
	internal static class MineDeployerExplosivePatches
	{
		public static PlayerAgent? CachedAgent { get; private set; }

		[HarmonyPatch("DoExplode")]
		[HarmonyPrefix]
		public static void ExplodePrefix(MineDeployerInstance_Detonate_Explosive __instance)
		{
			CachedAgent = __instance.m_core.Owner;
		}

		[HarmonyPatch("DoExplode")]
		[HarmonyPostfix]
		public static void ExplodePostfix()
		{
			CachedAgent = null;
		}
	}
}
namespace EndskApi.Patches.EndLevel
{
	[HarmonyPatch(typeof(GS_AfterLevel))]
	public class GsAfterLevelPatches
	{
		[HarmonyPatch("CleanupAfterExpedition")]
		[HarmonyPrefix]
		public static void CleanupPrefix()
		{
			LevelApi.InvokeEndLevelCallbacks();
		}
	}
}
namespace EndskApi.Patches.Checkpoint
{
	[HarmonyPatch(typeof(CheckpointManager))]
	internal static class CheckpointManagerPatches
	{
		private static Vector3 _lastCheckpointPos = Vector3.zero;

		[HarmonyPatch("OnStateChange")]
		[HarmonyPostfix]
		public static void OnCheckpointStateChange(pCheckpointState newState)
		{
			//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_0007: Invalid comparison between Unknown and I4
			//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_0033: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			if ((int)newState.lastInteraction == 1 && _lastCheckpointPos != newState.doorLockPosition)
			{
				_lastCheckpointPos = newState.doorLockPosition;
				CheckpointApi.InvokeCheckpointReachedCallbacks();
			}
			else if ((int)newState.lastInteraction == 2)
			{
				CheckpointApi.InvokeCheckpointReloadedCallbacks();
			}
		}

		[HarmonyPatch("OnLevelCleanup")]
		[HarmonyPostfix]
		public static void OnLevelCleanupPostfix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			_lastCheckpointPos = Vector3.zero;
			CheckpointApi.InvokeCheckpointCleanupCallbacks();
			NetworkManager.SendCheckpointCleanups();
		}
	}
}
namespace EndskApi.Manager
{
	public static class LogManager
	{
		private static ManualLogSource logger;

		internal static bool _debugMessagesActive;

		internal static void SetLogger(ManualLogSource log)
		{
			logger = log;
		}

		public static void Verbose(object msg)
		{
			if (_debugMessagesActive)
			{
				logger.LogInfo(msg);
			}
		}

		public static void Debug(object msg)
		{
			if (_debugMessagesActive)
			{
				logger.LogDebug(msg);
			}
		}

		public static void Message(object msg)
		{
			if (_debugMessagesActive)
			{
				logger.LogMessage(msg);
			}
		}

		public static void Error(object msg)
		{
			logger.LogError(msg);
		}

		public static void Warn(object msg)
		{
			logger.LogWarning(msg);
		}
	}
	public static class MenuInputProvider
	{
		private static MenuRebinding _bindings;

		public static InputTool F1 => new InputTool(_bindings.F1, $": [{_bindings.F1}]");

		public static InputTool F2 => new InputTool(_bindings.F2, $": [{_bindings.F2}]");

		public static InputTool F3 => new InputTool(_bindings.F3, $": [{_bindings.F3}]");

		public static InputTool F4 => new InputTool(_bindings.F4, $": [{_bindings.F4}]");

		public static InputTool F5 => new InputTool(_bindings.F5, $": [{_bindings.F5}]");

		public static InputTool F6 => new InputTool(_bindings.F6, $": [{_bindings.F6}]");

		public static InputTool F7 => new InputTool(_bindings.F7, $": [{_bindings.F7}]");

		public static InputTool F8 => new InputTool(_bindings.F8, $": [{_bindings.F8}]");

		public static InputTool F9 => new InputTool(_bindings.F9, $": [{_bindings.F9}]");

		public static InputTool F10 => new InputTool(_bindings.F10, $": [{_bindings.F10}]");

		public static InputTool KeyPad1 => new InputTool(_bindings.Keypad1, $": [{_bindings.Keypad1}]");

		public static InputTool KeyPad2 => new InputTool(_bindings.Keypad2, $": [{_bindings.Keypad2}]");

		public static InputTool KeyPad3 => new InputTool(_bindings.Keypad3, $": [{_bindings.Keypad3}]");

		public static InputTool KeyPad4 => new InputTool(_bindings.Keypad4, $": [{_bindings.Keypad4}]");

		public static InputTool KeyPad5 => new InputTool(_bindings.Keypad5, $": [{_bindings.Keypad5}]");

		public static InputTool KeyPad6 => new InputTool(_bindings.Keypad6, $": [{_bindings.Keypad6}]");

		public static InputTool KeyPad7 => new InputTool(_bindings.Keypad7, $": [{_bindings.Keypad7}]");

		public static InputTool KeyPad8 => new InputTool(_bindings.Keypad8, $": [{_bindings.Keypad8}]");

		public static InputTool KeyPad9 => new InputTool(_bindings.Keypad9, $": [{_bindings.Keypad9}]");

		static MenuInputProvider()
		{
			JsonSerializerOptions options = new JsonSerializerOptions
			{
				Converters = { (JsonConverter)new JsonStringEnumConverter() }
			};
			_bindings = JsonSerializer.Deserialize<MenuRebinding>(BepInExLoader.ConfigLoader.Bind<string>("MenuApi", "KeyBindings", "{\"F1\":\"F1\",\"F2\":\"F2\",\"F3\":\"F3\",\"F4\":\"F4\",\"F5\":\"F5\",\"F6\":\"F6\",\"F7\":\"F7\",\"F8\":\"F8\",\"F9\":\"F9\",\"F10\":\"None\",\"Keypad1\":\"Keypad1\",\"Keypad2\":\"Keypad2\",\"Keypad3\":\"Keypad3\",\"Keypad4\":\"Keypad4\",\"Keypad5\":\"Keypad5\",\"Keypad6\":\"Keypad6\",\"Keypad7\":\"Keypad7\",\"Keypad8\":\"Keypad8\",\"Keypad9\":\"Keypad9\"}", "You can remap keys here.").Value, options);
		}
	}
}
namespace EndskApi.Manager.Internal
{
	public class InformationCache
	{
		private readonly Dictionary<string, Dictionary<object, object>> _cache;

		public static InformationCache Instance { get; } = new InformationCache();

		public InformationCache()
		{
			_cache = new Dictionary<string, Dictionary<object, object>>();
		}

		public void SaveInformation(object key, object info, string mod)
		{
			GetCacheOfMod(mod)[key] = info;
		}

		public T GetInformation<T>(object key, string mod)
		{
			if (GetCacheOfMod(mod).TryGetValue(key, out object value))
			{
				if (value is T)
				{
					return (T)value;
				}
				throw new KeyNotFoundException($"Tried to get information with key {key}, but it is type {value.GetType().Name}, not type {typeof(T).Name}");
			}
			LogManager.Error($"There was no information with the key {key}");
			throw new KeyNotFoundException($"There was no information with the key {key}!");
		}

		public bool TryGetInformation<T>(object key, out T info, string mod, bool logNotFound = true)
		{
			if (GetCacheOfMod(mod).TryGetValue(key, out object value))
			{
				if (value is T val)
				{
					info = val;
					return true;
				}
				LogManager.Warn($"Tried to get information with key {key}, but it is type {value.GetType().Name}, not type {typeof(T).Name}");
				info = default(T);
				return false;
			}
			if (logNotFound)
			{
				LogManager.Warn($"There was no informaiton with the key {key}");
			}
			info = default(T);
			return false;
		}

		public void RemoveInformation(object key, string mod)
		{
			if (TryGetCacheOfMod(mod, out Dictionary<object, object> cache))
			{
				cache.Remove(key);
			}
		}

		public bool ContainsKey(object key, string mod)
		{
			if (TryGetCacheOfMod(mod, out Dictionary<object, object> cache))
			{
				return cache.ContainsKey(key);
			}
			return false;
		}

		private Dictionary<object, object> GetCacheOfMod(string mod)
		{
			if (!_cache.TryGetValue(mod, out Dictionary<object, object> value))
			{
				value = new Dictionary<object, object>();
				_cache[mod] = value;
			}
			return value;
		}

		private bool TryGetCacheOfMod(string mod, out Dictionary<object, object> cache)
		{
			return _cache.TryGetValue(mod, out cache);
		}
	}
	internal static class NetworkManager
	{
		[StructLayout(LayoutKind.Sequential, Size = 1)]
		internal struct DummyStruct
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		internal struct EquipGearStruct
		{
		}

		private const string _sendCheckpointReachedKey = "CheckpointHasBeenReached";

		private const string _sendCheckpointCleanupKey = "CheckpointCleanup";

		private const string _sendBiotagKey = "BiotagApplied";

		public static void Setup()
		{
			NetworkAPI.RegisterEvent<DummyStruct>("CheckpointCleanup", (Action<ulong, DummyStruct>)ReceiveCheckpointCleanup);
			NetworkAPI.RegisterEvent<DummyStruct>("CheckpointHasBeenReached", (Action<ulong, DummyStruct>)ReceiveCheckpointReached);
			NetworkAPI.RegisterEvent<pEnemyAgent>("BiotagApplied", (Action<ulong, pEnemyAgent>)ReceiveBiotag);
		}

		private static void ReceiveCheckpointReached(ulong snetPlayer, DummyStruct _)
		{
			CheckpointApi.InvokeCheckpointReachedCallbacks();
		}

		private static void ReceiveCheckpointCleanup(ulong snetPlayer, DummyStruct _)
		{
			CheckpointApi.InvokeCheckpointCleanupCallbacks();
		}

		private static void ReceiveBiotag(ulong lookup, pEnemyAgent packet)
		{
			EnemyAgent val = default(EnemyAgent);
			SNet_Player val2 = default(SNet_Player);
			if (((pEnemyAgent)(ref packet)).TryGet(ref val) && ((Agent)val).Alive && SNet.TryGetPlayer(lookup, ref val2))
			{
				EnemyKillApi.RegisterBiotag(val, ((Il2CppObjectBase)val2.PlayerAgent).Cast<PlayerAgent>());
			}
		}

		public static void SendCheckpointReached()
		{
			NetworkAPI.InvokeEvent<DummyStruct>("CheckpointHasBeenReached", default(DummyStruct), (SNet_ChannelType)2);
		}

		public static void SendCheckpointCleanups()
		{
			NetworkAPI.InvokeEvent<DummyStruct>("CheckpointCleanup", default(DummyStruct), (SNet_ChannelType)2);
		}

		public static void SendBiotag(EnemyAgent enemy)
		{
			//IL_0002: 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)
			pEnemyAgent val = default(pEnemyAgent);
			((pEnemyAgent)(ref val)).Set(enemy);
			NetworkAPI.InvokeEvent<pEnemyAgent>("BiotagApplied", val, SNet.Master, (SNet_ChannelType)2);
		}

		public static void SendEquipGear(GearInfo info)
		{
		}
	}
}
namespace EndskApi.Information.WeaponSwitcher
{
	public class GearInfo
	{
		public InventorySlotAmmo InventorySlotAmmo { get; set; }

		public InventorySlot Slot { get; set; }

		public AmmoType AmmoType { get; set; }

		public GearIDRange GearId { get; set; }

		public int AmmunitionInMagazine { get; set; }

		public GearInfo(GearIDRange gearId, int ammunitionInMagazine, InventorySlotAmmo inventorySlotAmmo)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			GearId = gearId;
			AmmunitionInMagazine = ammunitionInMagazine;
			InventorySlotAmmo = inventorySlotAmmo;
			AmmoType = inventorySlotAmmo.AmmoType;
			Slot = inventorySlotAmmo.Slot;
		}
	}
}
namespace EndskApi.Information.Menus
{
	public interface IExtendedTool
	{
		Action<object> ExtraToolAction { get; set; }

		InformationId InformationId { get; set; }
	}
	public class InputTool
	{
		public KeyCode InputKey { get; set; }

		public string Postfix { get; set; }

		public InputTool(KeyCode inputKey, string postfix)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			InputKey = inputKey;
			Postfix = postfix;
		}

		public virtual bool CheckKeyDown()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return Input.GetKeyDown(InputKey);
		}

		public virtual bool CheckKey()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return Input.GetKey(InputKey);
		}
	}
	public class Tool
	{
		public string Text { get; set; }

		public string TextPostfix { get; set; }

		public InputTool CheckInput { get; }

		public Action<Tool> UseTool { get; set; }

		public Action<Tool, bool> OnToggleUpdate { get; set; }

		public bool IsToggle { get; set; }

		public bool CurrentToggleState { get; set; }

		public object Extra { get; set; }

		public Tool()
		{
		}

		public Tool(string text, InputTool input, Action<Tool, bool> onToggleUpdate, bool startState)
		{
			Text = text;
			CheckInput = input;
			IsToggle = true;
			UseTool = ToggleTool;
			OnToggleUpdate = onToggleUpdate;
			CurrentToggleState = startState;
		}

		public Tool(string text, InputTool input, bool isToggle, Action<Tool> useCheat, Action<Tool, bool> onToggleUpdate = null, bool currentToggleState = false)
		{
			Text = text;
			CheckInput = input;
			IsToggle = isToggle;
			UseTool = useCheat;
			OnToggleUpdate = onToggleUpdate;
			CurrentToggleState = currentToggleState;
		}

		public void Toggle()
		{
			CurrentToggleState = !CurrentToggleState;
			OnToggleUpdate?.Invoke(this, CurrentToggleState);
		}

		public override string ToString()
		{
			if (IsToggle)
			{
				return $"{Text}{TextPostfix}{CheckInput.Postfix} {(CurrentToggleState ? "ON" : "OFF")}";
			}
			return Text + TextPostfix + CheckInput.Postfix;
		}

		private static void ToggleTool(Tool tool)
		{
			tool.Toggle();
		}
	}
	public class ToolExtended : Tool, IExtendedTool
	{
		public Action<object> ExtraToolAction { get; set; }

		public InformationId InformationId { get; set; }

		public ToolExtended(string text, InputTool input, bool isToggle, Action<Tool> useCheat, Action<object> extraCheatAction, Action<Tool, bool> onToggleUpdate = null, bool currentToggleState = false, InformationId infoId = InformationId.None)
			: base(text, input, isToggle, useCheat, onToggleUpdate, currentToggleState)
		{
			ExtraToolAction = extraCheatAction;
			InformationId = infoId;
		}

		public override string ToString()
		{
			return base.ToString();
		}
	}
}
namespace EndskApi.Information.EnemyKill
{
	public class EnemyKillDistribution
	{
		public EnemyAgent KilledEnemyAgent { get; set; }

		public Dictionary<int, float> DamageDistributions { get; set; }

		public HashSet<int> TaggedBy { get; set; }

		public PlayerAgent? LastHitDealtBy { get; set; }

		public LastHitType lastHitType { get; set; }

		public EnemyKillDistribution(EnemyAgent agentToKill)
		{
			KilledEnemyAgent = agentToKill;
			DamageDistributions = new Dictionary<int, float>();
			TaggedBy = new HashSet<int>();
		}

		public void AddPlayerTagged(PlayerAgent agent)
		{
			TaggedBy.Add(agent.PlayerSlotIndex);
		}

		public void AddDamageDealtByPlayerAgent(PlayerAgent agent, float damage)
		{
			if (!DamageDistributions.TryGetValue(agent.PlayerSlotIndex, out var value))
			{
				DamageDistributions.Add(agent.PlayerSlotIndex, damage);
			}
			else
			{
				DamageDistributions[agent.PlayerSlotIndex] = value + damage;
			}
		}

		public bool DidSnetBiotag(SNet_Player player)
		{
			return TaggedBy.Contains(player.PlayerSlotIndex());
		}

		public float GetDamageDealtBySnet(SNet_Player player)
		{
			int key = player.PlayerSlotIndex();
			if (DamageDistributions.TryGetValue(key, out var value))
			{
				return value;
			}
			return 0f;
		}
	}
	public class DamageDistribution
	{
		public int PlayerSlotIndex { get; set; }

		public float DamageDealt { get; set; }

		public DamageDistribution(int slotIndex, float damage)
		{
			PlayerSlotIndex = slotIndex;
			DamageDealt = damage;
		}
	}
}
namespace EndskApi.Information.Configs
{
	public class MenuRebinding
	{
		public KeyCode F1 { get; set; }

		public KeyCode F2 { get; set; }

		public KeyCode F3 { get; set; }

		public KeyCode F4 { get; set; }

		public KeyCode F5 { get; set; }

		public KeyCode F6 { get; set; }

		public KeyCode F7 { get; set; }

		public KeyCode F8 { get; set; }

		public KeyCode F9 { get; set; }

		public KeyCode F10 { get; set; }

		public KeyCode Keypad1 { get; set; }

		public KeyCode Keypad2 { get; set; }

		public KeyCode Keypad3 { get; set; }

		public KeyCode Keypad4 { get; set; }

		public KeyCode Keypad5 { get; set; }

		public KeyCode Keypad6 { get; set; }

		public KeyCode Keypad7 { get; set; }

		public KeyCode Keypad8 { get; set; }

		public KeyCode Keypad9 { get; set; }

		public MenuRebinding()
		{
			F1 = (KeyCode)282;
			F2 = (KeyCode)283;
			F3 = (KeyCode)284;
			F4 = (KeyCode)285;
			F5 = (KeyCode)286;
			F6 = (KeyCode)287;
			F7 = (KeyCode)288;
			F8 = (KeyCode)289;
			F9 = (KeyCode)290;
			Keypad1 = (KeyCode)257;
			Keypad2 = (KeyCode)258;
			Keypad3 = (KeyCode)259;
			Keypad4 = (KeyCode)260;
			Keypad5 = (KeyCode)261;
			Keypad6 = (KeyCode)262;
			Keypad7 = (KeyCode)263;
			Keypad8 = (KeyCode)264;
			Keypad9 = (KeyCode)265;
		}
	}
}
namespace EndskApi.Information.BoosterInfo
{
	public class BoosterCondition
	{
		public string Name { get; set; }

		public string ShortName { get; set; }

		public BoosterCondition Condition { get; set; }
	}
	public class BoosterEffect
	{
		public string Name { get; set; }

		public string ShortName { get; set; }

		public AgentModifier Effect { get; set; }

		public float Value { get; set; }

		public BoosterEffect(string name, string shortName, AgentModifier effect, float value)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			Name = name;
			ShortName = shortName;
			Effect = effect;
			Value = value;
		}
	}
	public interface IBooster
	{
		object Category { get; set; }

		List<BoosterEffect> BoosterEffects { get; set; }

		List<BoosterCondition> BoosterConditions { get; set; }
	}
}
namespace EndskApi.Enums.Menus
{
	public enum InformationId
	{
		None,
		EnemyId
	}
	public enum MenuStates
	{
		Active,
		HiddenAndActive,
		Deactivated
	}
}
namespace EndskApi.Enums.EnemyKill
{
	public enum LastHitType
	{
		Melee,
		ShootyWeapon,
		Explosion
	}
}
namespace EndskApi.Enums.Booster
{
	public enum CustomBoosterCategory
	{
		Muted,
		Bold,
		Aggressive,
		NotAccessible
	}
	public enum CustomBoosterModifiers
	{
		None = 0,
		RegenerationCap = 1,
		RegenerationSpeed = 2,
		HealSupport = 3,
		ReviveSpeedSupport = 4,
		ReviveStartHealthSupport = 5,
		MeleeResistance = 6,
		ProjectileResistance = 7,
		InfectionResistance = 8,
		PistolDamage = 50,
		SMGDamage = 51,
		DMRDamage = 52,
		AssaultRifleDamage = 53,
		CarbineDamage = 54,
		AutoPistolDamage = 55,
		HELDamage = 56,
		ShotgunDamage = 58,
		RevolverDamage = 59,
		SniperDamage = 60,
		BurstCannonDamage = 61,
		MachineGunDamage = 62,
		MachinePistolDamage = 63,
		RifleDamage = 64,
		BurstRifleDamage = 65,
		DoubleTapRifle = 66,
		BullpupRifleDamage = 67,
		CombatShotgunDamage = 68,
		ChokeModShotgunDamage = 69,
		StandardWeaponDamage = 70,
		SpecialWeaponDamage = 71,
		GlueStrength = 100,
		GlueEfficiency = 101,
		SentryGunSpeed = 102,
		SentryGunDamage = 103,
		SentryGunLongRangeDamage = 104,
		SentryGunShortRangeDamage = 105,
		TripMineDamage = 106,
		ScannerRechargeSpeed = 107,
		AmmoSupport = 108,
		HackingProficiency = 150,
		ComputerProcessingSpeed = 151,
		InitialAmmoStandard = 152,
		InitialAmmoSpecial = 153,
		InitialAmmoTool = 154,
		FogRepellerEffect = 155,
		GlowstickEffect = 156,
		BioscanSpeed = 157,
		MeleeDamage = 200
	}
}
namespace EndskApi.Api
{
	public static class CacheApi
	{
		private const string GlobalCache = "GlobalCache";

		internal const string InternalCache = "EndskApi";

		private static readonly InformationCache _informationCache;

		static CacheApi()
		{
			_informationCache = InformationCache.Instance;
		}

		public static void SaveInformation(object key, object info, string mod = "GlobalCache")
		{
			_informationCache.SaveInformation(key, info, mod);
		}

		public static void SaveInstance<T>(T info, string mod = "GlobalCache")
		{
			SaveInformation(typeof(T), info, mod);
		}

		public static T GetInformation<T>(object key, string mod = "GlobalCache")
		{
			return _informationCache.GetInformation<T>(key, mod);
		}

		public static T GetInstance<T>(string mod = "GlobalCache")
		{
			return GetInformation<T>(typeof(T), mod);
		}

		public static bool TryGetInformation<T>(object key, out T information, string mod = "GlobalCache", bool logNotFound = true)
		{
			return _informationCache.TryGetInformation<T>(key, out information, mod, logNotFound);
		}

		public static bool TryGetInstance<T>(out T information, string mod = "GlobalCache", bool logNotFound = true)
		{
			return _informationCache.TryGetInformation<T>(typeof(T), out information, mod, logNotFound);
		}

		public static void RemoveInformation(object key, string mod = "GlobalCache")
		{
			_informationCache.RemoveInformation(key, mod);
		}

		public static void RemoveInstance<T>(string mod = "GlobalCache")
		{
			RemoveInformation(typeof(T), mod);
		}

		public static bool ContainsKey(object key, string mod = "GlobalCache")
		{
			return _informationCache.ContainsKey(key, mod);
		}

		public static InformationCache GetInformationCache()
		{
			return _informationCache;
		}
	}
	public static class CheckpointApi
	{
		private const string CheckpointReachedKey = "CheckpointReachedKey";

		private const string CheckpointReloadedKey = "CheckpointReloadedKey";

		private const string CleanupCheckpointKey = "CheckpointCleanupKey";

		static CheckpointApi()
		{
			BepInExLoader.Harmony.PatchAll(typeof(CheckpointManagerPatches));
			NetworkManager.Setup();
		}

		public static void AddCheckpointReachedCallback(Action callBack)
		{
			if (!CacheApi.TryGetInformation<List<Action>>("CheckpointReachedKey", out var information, "EndskApi", logNotFound: false))
			{
				information = new List<Action>();
				CacheApi.SaveInformation("CheckpointReachedKey", information, "EndskApi");
			}
			information.Add(callBack);
		}

		public static void AddCheckpointReloadedCallback(Action callBack)
		{
			if (!CacheApi.TryGetInformation<List<Action>>("CheckpointReloadedKey", out var information, "EndskApi", logNotFound: false))
			{
				information = new List<Action>();
				CacheApi.SaveInformation("CheckpointReloadedKey", information, "EndskApi");
			}
			information.Add(callBack);
		}

		public static void AddCheckpointCleanupCallback(Action callBack)
		{
			if (!CacheApi.TryGetInformation<List<Action>>("CheckpointCleanupKey", out var information, "EndskApi", logNotFound: false))
			{
				information = new List<Action>();
				CacheApi.SaveInformation("CheckpointCleanupKey", information, "EndskApi");
			}
			information.Add(callBack);
		}

		public static void RemoveCheckpointReachedCallback(Action callBack)
		{
			if (CacheApi.TryGetInformation<List<Action>>("CheckpointReachedKey", out var information, "EndskApi", logNotFound: false))
			{
				information.Remove(callBack);
			}
		}

		public static void RemoveCheckpointReloadedCallback(Action callBack)
		{
			if (CacheApi.TryGetInformation<List<Action>>("CheckpointReloadedKey", out var information, "EndskApi", logNotFound: false))
			{
				information.Remove(callBack);
			}
		}

		public static void RemoveCheckpointCleanupCallback(Action callBack)
		{
			if (CacheApi.TryGetInformation<List<Action>>("CheckpointCleanupKey", out var information, "EndskApi", logNotFound: false))
			{
				information.Remove(callBack);
			}
		}

		internal static void InvokeCheckpointReachedCallbacks()
		{
			if (!CacheApi.TryGetInformation<List<Action>>("CheckpointReachedKey", out var information, "EndskApi", logNotFound: false))
			{
				return;
			}
			foreach (Action item in information)
			{
				item();
			}
		}

		internal static void InvokeCheckpointReloadedCallbacks()
		{
			if (!CacheApi.TryGetInformation<List<Action>>("CheckpointReloadedKey", out var information, "EndskApi", logNotFound: false))
			{
				return;
			}
			foreach (Action item in information)
			{
				item();
			}
		}

		internal static void InvokeCheckpointCleanupCallbacks()
		{
			if (!CacheApi.TryGetInformation<List<Action>>("CheckpointCleanupKey", out var information, "EndskApi", logNotFound: false))
			{
				return;
			}
			foreach (Action item in information)
			{
				item();
			}
		}
	}
	public static class EnemyDamageBasePatchApi
	{
		public delegate void ReceiveMeleeDamage(Dam_EnemyDamageBase instance, ref pFullDamageData data);

		public delegate void ReceiveBulletDamage(Dam_EnemyDamageBase instance, ref pBulletDamageData data);

		public delegate void ReceiveExplosionDamage(Dam_EnemyDamageBase instance, PlayerAgent? source, ref pExplosionDamageData data);

		public delegate void ProcessReceivedDamage(Dam_EnemyDamageBase instance, ref float damage, Agent damageSource, ref Vector3 position, ref Vector3 direction, ref ES_HitreactType hitreact, ref bool tryForceHitreact, ref int limbID, ref float staggerDamageMulti, ref DamageNoiseLevel damageNoiseLevel);

		private static bool _setup;

		internal static List<(double, ReceiveMeleeDamage)> MeleePrefixCallbacks
		{
			get
			{
				return CacheApi.GetInstance<List<(double, ReceiveMeleeDamage)>>("EndskApi");
			}
			set
			{
				CacheApi.SaveInstance(value, "EndskApi");
			}
		}

		internal static List<(double, ReceiveMeleeDamage)> MeleePostfixCallbacks
		{
			get
			{
				return CacheApi.GetInstance<List<(double, ReceiveMeleeDamage)>>();
			}
			set
			{
				CacheApi.SaveInstance(value);
			}
		}

		internal static List<(double, ReceiveBulletDamage)> BulletPrefixCallbacks
		{
			get
			{
				return CacheApi.GetInstance<List<(double, ReceiveBulletDamage)>>("EndskApi");
			}
			set
			{
				CacheApi.SaveInstance(value, "EndskApi");
			}
		}

		internal static List<(double, ReceiveBulletDamage)> BulletPostfixCallbacks
		{
			get
			{
				return CacheApi.GetInstance<List<(double, ReceiveBulletDamage)>>();
			}
			set
			{
				CacheApi.SaveInstance(value);
			}
		}

		internal static List<(double, ReceiveExplosionDamage)> ExplosionPrefixCallbacks
		{
			get
			{
				return CacheApi.GetInstance<List<(double, ReceiveExplosionDamage)>>("EndskApi");
			}
			set
			{
				CacheApi.SaveInstance(value, "EndskApi");
			}
		}

		internal static List<(double, ReceiveExplosionDamage)> ExplosionPostfixCallbacks
		{
			get
			{
				return CacheApi.GetInstance<List<(double, ReceiveExplosionDamage)>>();
			}
			set
			{
				CacheApi.SaveInstance(value);
			}
		}

		internal static void Setup()
		{
			if (!_setup)
			{
				BepInExLoader.Harmony.PatchAll(typeof(EnemyDamageBasePatches));
				BepInExLoader.Harmony.PatchAll(typeof(MineDeployerExplosivePatches));
				BepInExLoader.Harmony.PatchAll(typeof(EnemyTagPatches));
				MeleePrefixCallbacks = new List<(double, ReceiveMeleeDamage)>();
				MeleePostfixCallbacks = new List<(double, ReceiveMeleeDamage)>();
				BulletPrefixCallbacks = new List<(double, ReceiveBulletDamage)>();
				BulletPostfixCallbacks = new List<(double, ReceiveBulletDamage)>();
				ExplosionPrefixCallbacks = new List<(double, ReceiveExplosionDamage)>();
				ExplosionPostfixCallbacks = new List<(double, ReceiveExplosionDamage)>();
				_setup = true;
			}
		}

		public static void AddReceiveMeleePrefix(double priority, ReceiveMeleeDamage method)
		{
			Setup();
			MeleePrefixCallbacks.Add((priority, method));
			MeleePrefixCallbacks = new List<(double, ReceiveMeleeDamage)>(MeleePrefixCallbacks.OrderBy<(double, ReceiveMeleeDamage), double>(((double, ReceiveMeleeDamage) x) => x.Item1));
		}

		public static void AddReceiveMeleePostfix(double priority, ReceiveMeleeDamage method)
		{
			Setup();
			MeleePostfixCallbacks.Add((priority, method));
			MeleePostfixCallbacks = new List<(double, ReceiveMeleeDamage)>(MeleePostfixCallbacks.OrderBy<(double, ReceiveMeleeDamage), double>(((double, ReceiveMeleeDamage) x) => x.Item1));
		}

		public static void AddReceiveBulletPrefix(double priority, ReceiveBulletDamage method)
		{
			Setup();
			BulletPrefixCallbacks.Add((priority, method));
			BulletPrefixCallbacks = new List<(double, ReceiveBulletDamage)>(BulletPrefixCallbacks.OrderBy<(double, ReceiveBulletDamage), double>(((double, ReceiveBulletDamage) x) => x.Item1));
		}

		public static void AddReceiveBulletPostfix(double priority, ReceiveBulletDamage method)
		{
			Setup();
			BulletPostfixCallbacks.Add((priority, method));
			BulletPostfixCallbacks = new List<(double, ReceiveBulletDamage)>(BulletPostfixCallbacks.OrderBy<(double, ReceiveBulletDamage), double>(((double, ReceiveBulletDamage) x) => x.Item1));
		}

		public static void AddReceiveExplosionPrefix(double priority, ReceiveExplosionDamage method)
		{
			Setup();
			ExplosionPrefixCallbacks.Add((priority, method));
			ExplosionPrefixCallbacks = new List<(double, ReceiveExplosionDamage)>(ExplosionPrefixCallbacks.OrderBy<(double, ReceiveExplosionDamage), double>(((double, ReceiveExplosionDamage) x) => x.Item1));
		}

		public static void AddReceiveExplosionPostfix(double priority, ReceiveExplosionDamage method)
		{
			Setup();
			ExplosionPostfixCallbacks.Add((priority, method));
			ExplosionPostfixCallbacks = new List<(double, ReceiveExplosionDamage)>(ExplosionPostfixCallbacks.OrderBy<(double, ReceiveExplosionDamage), double>(((double, ReceiveExplosionDamage) x) => x.Item1));
		}

		internal static void InvokeReceiveMeleePrefix(Dam_EnemyDamageBase instance, ref pFullDamageData data)
		{
			foreach (var meleePrefixCallback in MeleePrefixCallbacks)
			{
				meleePrefixCallback.Item2(instance, ref data);
			}
		}

		internal static void InvokeReceiveMeleePostfix(Dam_EnemyDamageBase instance, ref pFullDamageData data)
		{
			foreach (var meleePostfixCallback in MeleePostfixCallbacks)
			{
				meleePostfixCallback.Item2(instance, ref data);
			}
		}

		internal static void InvokeReceiveBulletPrefix(Dam_EnemyDamageBase instance, ref pBulletDamageData data)
		{
			foreach (var bulletPrefixCallback in BulletPrefixCallbacks)
			{
				bulletPrefixCallback.Item2(instance, ref data);
			}
		}

		internal static void InvokeReceiveBulletPostfix(Dam_EnemyDamageBase instance, ref pBulletDamageData data)
		{
			foreach (var bulletPostfixCallback in BulletPostfixCallbacks)
			{
				bulletPostfixCallback.Item2(instance, ref data);
			}
		}

		internal static void InvokeReceiveExplosionPrefix(Dam_EnemyDamageBase instance, ref pExplosionDamageData data)
		{
			foreach (var explosionPrefixCallback in ExplosionPrefixCallbacks)
			{
				explosionPrefixCallback.Item2(instance, MineDeployerExplosivePatches.CachedAgent, ref data);
			}
		}

		internal static void InvokeReceiveExplosionPostfix(Dam_EnemyDamageBase instance, ref pExplosionDamageData data)
		{
			foreach (var explosionPostfixCallback in ExplosionPostfixCallbacks)
			{
				explosionPostfixCallback.Item2(instance, MineDeployerExplosivePatches.CachedAgent, ref data);
			}
		}
	}
	public static class EnemyKillApi
	{
		private const string EnemyKillKey = "EnemyKillCallbacks";

		private static bool _setup = false;

		private static Dictionary<IntPtr, bool> _enemyStates = new Dictionary<IntPtr, bool>();

		private static Dictionary<IntPtr, EnemyKillDistribution> _enemyDistributions = new Dictionary<IntPtr, EnemyKillDistribution>();

		public static void AddEnemyKilledCallback(Action<EnemyKillDistribution> callBack)
		{
			Setup();
			if (!CacheApi.TryGetInformation<List<Action<EnemyKillDistribution>>>("EnemyKillCallbacks", out var information, "EndskApi", logNotFound: false))
			{
				information = new List<Action<EnemyKillDistribution>>();
				CacheApi.SaveInformation("EnemyKillCallbacks", information, "EndskApi");
			}
			information.Add(callBack);
		}

		internal static void InvokeEnemyKilledCallbacks(EnemyKillDistribution enemyKill)
		{
			if (!CacheApi.TryGetInformation<List<Action<EnemyKillDistribution>>>("EnemyKillCallbacks", out var information, "EndskApi", logNotFound: false))
			{
				return;
			}
			foreach (Action<EnemyKillDistribution> item in information)
			{
				item(enemyKill);
			}
		}

		private static void Setup()
		{
			if (!_setup)
			{
				EnemyDamageBasePatchApi.AddReceiveMeleePrefix(1.0, ReceiveMeleePrefix);
				EnemyDamageBasePatchApi.AddReceiveMeleePostfix(1.0, ReceiveMeleePostfix);
				EnemyDamageBasePatchApi.AddReceiveBulletPrefix(1.0, ReceiveBulletPrefix);
				EnemyDamageBasePatchApi.AddReceiveBulletPostfix(1.0, ReceiveBulletPostfix);
				EnemyDamageBasePatchApi.AddReceiveExplosionPrefix(1.0, ReceiveExplosionPrefix);
				EnemyDamageBasePatchApi.AddReceiveExplosionPostfix(1.0, ReceiveExplosionPostfix);
				LevelApi.AddEndLevelCallback(delegate
				{
					_enemyStates.Clear();
					_enemyDistributions.Clear();
				});
				_setup = true;
			}
		}

		private static void ReceiveMeleePrefix(Dam_EnemyDamageBase instance, ref pFullDamageData data)
		{
			bool alive = ((Agent)instance.Owner).Alive;
			if (alive || _enemyStates.ContainsKey(((Il2CppObjectBase)instance).Pointer))
			{
				_enemyStates[((Il2CppObjectBase)instance).Pointer] = alive;
			}
		}

		private static void ReceiveMeleePostfix(Dam_EnemyDamageBase instance, ref pFullDamageData data)
		{
			if (!(_enemyStates.TryGetValue(((Il2CppObjectBase)instance).Pointer, out var value) && value))
			{
				return;
			}
			Agent val = default(Agent);
			((pAgent)(ref data.source)).TryGet(ref val);
			if (!((Object)(object)val == (Object)null))
			{
				PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
				DamageDistributionAddDamageDealt(instance.Owner, val2, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)instance).HealthMax));
				if (!((Agent)instance.Owner).Alive)
				{
					EnemyDied(instance.Owner, val2, LastHitType.Melee);
				}
			}
		}

		private static void ReceiveBulletPrefix(Dam_EnemyDamageBase instance, ref pBulletDamageData data)
		{
			bool alive = ((Agent)instance.Owner).Alive;
			if (alive || _enemyStates.ContainsKey(((Il2CppObjectBase)instance).Pointer))
			{
				_enemyStates[((Il2CppObjectBase)instance).Pointer] = alive;
			}
		}

		private static void ReceiveBulletPostfix(Dam_EnemyDamageBase instance, ref pBulletDamageData data)
		{
			if (!(_enemyStates.TryGetValue(((Il2CppObjectBase)instance).Pointer, out var value) && value))
			{
				return;
			}
			Agent val = default(Agent);
			((pAgent)(ref data.source)).TryGet(ref val);
			if (!((Object)(object)val == (Object)null))
			{
				PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
				DamageDistributionAddDamageDealt(instance.Owner, val2, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)instance).HealthMax));
				if (!((Agent)instance.Owner).Alive)
				{
					EnemyDied(instance.Owner, val2, LastHitType.ShootyWeapon);
				}
			}
		}

		private static void ReceiveExplosionPrefix(Dam_EnemyDamageBase instance, PlayerAgent? source, ref pExplosionDamageData data)
		{
			bool alive = ((Agent)instance.Owner).Alive;
			if (alive || _enemyStates.ContainsKey(((Il2CppObjectBase)instance).Pointer))
			{
				_enemyStates[((Il2CppObjectBase)instance).Pointer] = alive;
			}
		}

		private static void ReceiveExplosionPostfix(Dam_EnemyDamageBase instance, PlayerAgent? source, ref pExplosionDamageData data)
		{
			if (_enemyStates.TryGetValue(((Il2CppObjectBase)instance).Pointer, out var value) && value)
			{
				if ((Object)(object)source != (Object)null)
				{
					DamageDistributionAddDamageDealt(instance.Owner, source, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)instance).HealthMax));
				}
				if (!((Agent)instance.Owner).Alive)
				{
					EnemyDied(instance.Owner, source, LastHitType.Explosion);
				}
			}
		}

		private static void DamageDistributionAddDamageDealt(EnemyAgent hitEnemy, PlayerAgent damageDealer, float damageDealt)
		{
			if (!_enemyDistributions.TryGetValue(((Il2CppObjectBase)hitEnemy).Pointer, out EnemyKillDistribution value))
			{
				_enemyDistributions.Add(((Il2CppObjectBase)hitEnemy).Pointer, value = new EnemyKillDistribution(hitEnemy));
			}
			value.AddDamageDealtByPlayerAgent(damageDealer, damageDealt);
		}

		private static void EnemyDied(EnemyAgent hitEnemy, PlayerAgent? lastHit, LastHitType lastHitType)
		{
			if (_enemyDistributions.TryGetValue(((Il2CppObjectBase)hitEnemy).Pointer, out EnemyKillDistribution value))
			{
				value.LastHitDealtBy = lastHit;
				value.lastHitType = lastHitType;
				InvokeEnemyKilledCallbacks(value);
				_enemyDistributions.Remove(((Il2CppObjectBase)hitEnemy).Pointer);
			}
			_enemyStates.Remove(((Il2CppObjectBase)hitEnemy).Pointer);
		}

		public static void RegisterDamage(EnemyAgent enemy, PlayerAgent? source, float damage, bool willKill)
		{
			if ((Object)(object)source != (Object)null)
			{
				DamageDistributionAddDamageDealt(enemy, source, damage);
			}
			if (willKill)
			{
				EnemyDied(enemy, source, LastHitType.ShootyWeapon);
			}
		}

		public static void RegisterBiotag(EnemyAgent enemy, PlayerAgent source)
		{
			if (!_enemyDistributions.TryGetValue(((Il2CppObjectBase)enemy).Pointer, out EnemyKillDistribution value))
			{
				_enemyDistributions.Add(((Il2CppObjectBase)enemy).Pointer, value = new EnemyKillDistribution(enemy));
			}
			value.AddPlayerTagged(source);
		}
	}
	public static class GearSwitchApi
	{
		static GearSwitchApi()
		{
			LevelApi.AddEndLevelCallback(LevelEndedCallback);
			SetGearInfoCache(new Dictionary<IntPtr, GearInfo>());
		}

		public static GearInfo CreateNewWeaponInfo(InventorySlot slot, AmmoType ammoType, GearIDRange gearId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			PlayerDataBlock block = GameDataBlockBase<PlayerDataBlock>.GetBlock(1u);
			InventorySlotAmmo val = new InventorySlotAmmo();
			val.Slot = slot;
			val.AmmoInPack = (((int)ammoType == 1) ? block.AmmoSpecialInitial : block.AmmoStandardInitial);
			val.AmmoMaxCap = (((int)ammoType == 1) ? block.AmmoSpecialMaxCap : block.AmmoStandardMaxCap);
			GearInfo gearInfo = new GearInfo(gearId, 0, val);
			GearCategoryDataBlock block2 = GameDataBlockBase<GearCategoryDataBlock>.GetBlock(gearId.GetCompID((eGearComponent)2));
			ArchetypeDataBlock block3 = GameDataBlockBase<ArchetypeDataBlock>.GetBlock(GearBuilder.GetArchetypeID(block2, (eWeaponFireMode)gearId.GetCompID((eGearComponent)1)));
			gearInfo.InventorySlotAmmo.BulletClipSize = block3.DefaultClipSize;
			gearInfo.AmmunitionInMagazine = block3.DefaultClipSize;
			LogManager.Debug($"Putting {gearInfo.AmmunitionInMagazine} into {block2.PublicName}");
			return gearInfo;
		}

		public static void EquipGear(GearInfo newGear, out GearInfo oldGear)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			AddWeaponInfo(newGear);
			SyncAmmonitionWithRegisteredWeapon(newGear.Slot, out oldGear);
			EquipGear(newGear);
		}

		public static void SyncAmmonitionWithRegisteredWeapon(InventorySlot slot, out GearInfo changedWeapon)
		{
			//IL_0000: 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)
			if (TryGetItemEquippableInSlot(slot, out ItemEquippable item) && (Object)(object)item != (Object)null)
			{
				LogManager.Debug("SyncAmmunitionWithRegisteredWeapon actually found Weapon itemequippable");
				InventorySlotAmmo inventorySlotAmmo = PlayerBackpackManager.LocalBackpack.AmmoStorage.GetInventorySlotAmmo(slot);
				if (GetGearInfo().TryGetValue(((Il2CppObjectBase)inventorySlotAmmo).Pointer, out changedWeapon))
				{
					changedWeapon.AmmunitionInMagazine = item.GetCurrentClip();
					LogManager.Debug($"Updated Ammo to {changedWeapon.AmmunitionInMagazine}, Max is {changedWeapon.InventorySlotAmmo.BulletClipSize}");
				}
			}
			else
			{
				changedWeapon = null;
			}
		}

		public static void AddWeaponInfo(GearInfo info)
		{
			Dictionary<IntPtr, GearInfo> gearInfo = GetGearInfo();
			if (!gearInfo.ContainsKey(((Il2CppObjectBase)info.InventorySlotAmmo).Pointer))
			{
				gearInfo.Add(((Il2CppObjectBase)info.InventorySlotAmmo).Pointer, info);
			}
		}

		public static void UnregisterWeapon(GearInfo info)
		{
			GetGearInfo().Remove(((Il2CppObjectBase)info.InventorySlotAmmo).Pointer);
		}

		private static void EquipGear(GearInfo info)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack;
			localBackpack.SpawnAndEquipGearAsync(info.Slot, info.GearId, delBackpackItemCallback.op_Implicit((Action<BackpackItem>)BackPackItemCreatedCallBack));
			SetAmmoStorage(info, localBackpack.AmmoStorage);
			void BackPackItemCreatedCallBack(BackpackItem backpackItem)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				ItemEquippable val = ((Il2CppObjectBase)backpackItem.Instance).TryCast<ItemEquippable>();
				if ((Object)(object)val != (Object)null)
				{
					val.SetCurrentClip(info.AmmunitionInMagazine);
					PlayerManager.GetLocalPlayerAgent().Sync.WantsToWieldSlot(info.Slot, false);
				}
			}
		}

		private static bool TryGetItemEquippableInSlot(InventorySlot slot, out ItemEquippable item)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			BackpackItem val = default(BackpackItem);
			if (!PlayerBackpackManager.LocalBackpack.TryGetBackpackItem(slot, ref val))
			{
				item = null;
				return false;
			}
			item = ((Il2CppObjectBase)val.Instance).TryCast<ItemEquippable>();
			return (Object)(object)item != (Object)null;
		}

		private static void SetAmmoStorage(GearInfo info, PlayerAmmoStorage storage)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			//IL_0018: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			((Il2CppArrayBase<InventorySlotAmmo>)(object)storage.m_ammoStorage)[(int)info.AmmoType] = info.InventorySlotAmmo;
			AmmoType ammoType = info.AmmoType;
			if ((int)ammoType != 0)
			{
				if ((int)ammoType == 1)
				{
					storage.SpecialAmmo = info.InventorySlotAmmo;
				}
			}
			else
			{
				storage.StandardAmmo = info.InventorySlotAmmo;
			}
		}

		internal static void LevelEndedCallback()
		{
			SetGearInfoCache(new Dictionary<IntPtr, GearInfo>());
		}

		private static Dictionary<IntPtr, GearInfo> GetGearInfo()
		{
			return CacheApi.GetInstance<Dictionary<IntPtr, GearInfo>>("EndskApi");
		}

		private static void SetGearInfoCache(Dictionary<IntPtr, GearInfo> dic)
		{
			CacheApi.SaveInstance(dic, "EndskApi");
		}
	}
	public static class InitApi
	{
		private const string InitKey = "InitKey";

		static InitApi()
		{
			BepInExLoader.Harmony.PatchAll(typeof(PageRundownNewPatches));
			BepInExLoader.Harmony.PatchAll(typeof(GUIManagerPatches));
		}

		public static void AddInitCallback(Action callBack)
		{
			if (!CacheApi.TryGetInformation<List<Action>>("InitKey", out var information, "EndskApi", logNotFound: false))
			{
				information = new List<Action>();
				CacheApi.SaveInformation("InitKey", information, "EndskApi");
			}
			information.Add(callBack);
		}

		internal static void InvokeInitCallbacks()
		{
			if (!CacheApi.TryGetInformation<List<Action>>("InitKey", out var information, "EndskApi", logNotFound: false))
			{
				return;
			}
			foreach (Action item in information)
			{
				try
				{
					item();
				}
				catch (Exception ex)
				{
					LogManager.Error(ex.ToString());
				}
			}
			CacheApi.RemoveInformation("InitKey", "EndskApi");
		}
	}
	public static class LevelApi
	{
		private const string EndLevelKey = "EndLevelKey";

		private const string StartLevelKey = "StartLevelKey";

		static LevelApi()
		{
			BepInExLoader.Harmony.PatchAll(typeof(GsAfterLevelPatches));
			BepInExLoader.Harmony.PatchAll(typeof(GsInLevelPatches));
		}

		public static void AddBeginLevelCallback(Action callBack)
		{
			if (!CacheApi.TryGetInformation<List<Action>>("StartLevelKey", out var information, "EndskApi", logNotFound: false))
			{
				information = new List<Action>();
				CacheApi.SaveInformation("StartLevelKey", information, "EndskApi");
			}
			information.Add(callBack);
		}

		public static void AddEndLevelCallback(Action callBack)
		{
			if (!CacheApi.TryGetInformation<List<Action>>("EndLevelKey", out var information, "EndskApi", logNotFound: false))
			{
				information = new List<Action>();
				CacheApi.SaveInformation("EndLevelKey", information, "EndskApi");
			}
			information.Add(callBack);
		}

		internal static void InvokeEndLevelCallbacks()
		{
			if (!CacheApi.TryGetInformation<List<Action>>("EndLevelKey", out var information, "EndskApi", logNotFound: false))
			{
				return;
			}
			foreach (Action item in information)
			{
				try
				{
					item();
				}
				catch (Exception msg)
				{
					LogManager.Error(msg);
				}
			}
		}

		internal static void InvokeStartLevelCallbacks()
		{
			if (!CacheApi.TryGetInformation<List<Action>>("StartLevelKey", out var information, "EndskApi", logNotFound: false))
			{
				return;
			}
			foreach (Action item in information)
			{
				try
				{
					item();
				}
				catch (Exception msg)
				{
					LogManager.Error(msg);
				}
			}
		}
	}
	public static class MenuApi
	{
		private static bool _setup;

		static MenuApi()
		{
		}

		internal static void Setup()
		{
			//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_0026: Expected O, but got Unknown
			if (!_setup)
			{
				GameObject val = new GameObject("EndskApi_Menu");
				CacheApi.SaveInstance(val.AddComponent<MainMenu>(), "EndskApi");
				Object.DontDestroyOnLoad((Object)val);
				_setup = true;
			}
		}

		public static void ActivateUnknownMenu<TScript>(TScript menu) where TScript : BaseMenu
		{
			Setup();
			CacheApi.GetInstance<MainMenu>("EndskApi").ActivateUnknownMenu(menu);
		}

		public static TScript AddMenu<TScript>(string pageName) where TScript : BaseMenu
		{
			Setup();
			MainMenu instance = CacheApi.GetInstance<MainMenu>("EndskApi");
			TScript val = ((Component)instance).gameObject.AddComponent<TScript>();
			instance.AddPage(pageName, val);
			CacheApi.SaveInstance(val, "EndskApi");
			return val;
		}

		public static TScript GetMenu<TScript>() where TScript : BaseMenu
		{
			Setup();
			return CacheApi.GetInstance<TScript>("EndskApi");
		}

		public static void AddMiddleMouseClickTool(IExtendedTool tool)
		{
			Setup();
			CacheApi.GetInstance<MainMenu>("EndskApi").AddMiddleMouseClickTool(tool);
		}

		public static void RemoveMiddleMouseClickTool(IExtendedTool tool)
		{
			Setup();
			CacheApi.GetInstance<MainMenu>("EndskApi").RemoveMiddleMouseClickTool(tool);
		}

		public static void AddTimerTool(IExtendedTool tool)
		{
			Setup();
			CacheApi.GetInstance<MainMenu>("EndskApi").AddTimedTool(tool);
		}

		public static void RemoveTimerTool(IExtendedTool tool)
		{
			Setup();
			CacheApi.GetInstance<MainMenu>("EndskApi").RemoveTimedTool(tool);
		}

		public static void AddHiddenFunction(Tool tool)
		{
			Setup();
			CacheApi.GetInstance<MainMenu>("EndskApi").AddHiddenTool(tool);
		}

		public static void RemoveHiddenFunction(Tool tool)
		{
			Setup();
			CacheApi.GetInstance<MainMenu>("EndskApi").RemoveHiddenTool(tool);
		}
	}
	public static class ProfileIndependentDataApi
	{
		private static readonly string _localLowPath;

		static ProfileIndependentDataApi()
		{
			_localLowPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).Replace("Roaming", "LocalLow"), "10 Chambers Collective", "Mods");
			if (!Directory.Exists(_localLowPath))
			{
				Directory.CreateDirectory(_localLowPath);
			}
		}

		public static T Load<T>(string fileName, JsonSerializerOptions option = null) where T : new()
		{
			if (TryLoadFromCache<T>(fileName, out var cachedObj))
			{
				return cachedObj;
			}
			if (option == null)
			{
				option = new JsonSerializerOptions
				{
					IncludeFields = false,
					ReadCommentHandling = JsonCommentHandling.Skip,
					PropertyNameCaseInsensitive = true,
					WriteIndented = true
				};
			}
			if (File.Exists(CreatePath(fileName)))
			{
				return JsonSerializer.Deserialize<T>(File.ReadAllText(CreatePath(fileName)), option);
			}
			return new T();
		}

		public static void Save(object obj, string fileName, JsonSerializerOptions option = null)
		{
			SaveIntoCache(fileName, obj);
			if (option == null)
			{
				option = new JsonSerializerOptions
				{
					IncludeFields = false,
					ReadCommentHandling = JsonCommentHandling.Skip,
					PropertyNameCaseInsensitive = true,
					WriteIndented = true
				};
			}
			File.WriteAllText(CreatePath(fileName), JsonSerializer.Serialize(obj, option));
		}

		internal static bool TryLoadFromCache<T>(string fileName, out T cachedObj)
		{
			return CacheApi.TryGetInformation<T>(fileName, out cachedObj, "ProfileIndependentApi", logNotFound: false);
		}

		internal static void SaveIntoCache(string fileName, object obj)
		{
			CacheApi.SaveInformation(fileName, obj, "ProfileIndependentApi");
		}

		private static string CreatePath(string fileName)
		{
			if (fileName.EndsWith(".json"))
			{
				return Path.Combine(_localLowPath, fileName);
			}
			return Path.Combine(_localLowPath, fileName + ".json");
		}
	}
}

Expansions.dll

Decompiled 2 days ago
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Text.Json.Serialization;
using AIGraph;
using AK;
using Agents;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CullingSystem;
using EndskApi.Api;
using Enemies;
using Expansions.Information.PackConverter;
using Expansions.Information.ToolAbility;
using Expansions.Patches.DoubleJump;
using Expansions.Patches.PackConverter;
using Expansions.Patches.ToolAbility;
using GTFO.API;
using GTFuckingXP.Communication;
using GTFuckingXP.Extensions;
using GTFuckingXP.Information.Level;
using GTFuckingXP.Managers;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Localization;
using MTFO.Managers;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;
using XpExpansions.Extensions;
using XpExpansions.Information;
using XpExpansions.Information.BioTrackerLocal;
using XpExpansions.Information.DoubleJump;
using XpExpansions.Information.StartingXp;
using XpExpansions.Manager;
using XpExpansions.Scripts;
using XpExpansions.Util;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Expansions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+gitfbd117d-dirty-master.fbd117d34bdc37962630c75f377a07297f961609")]
[assembly: AssemblyProduct("Expansions")]
[assembly: AssemblyTitle("Expansions")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
}
namespace Expansions
{
	[GeneratedCode("VersionInfoGenerator", "2.1.3+git35c0c2a-master")]
	[CompilerGenerated]
	internal static class VersionInfo
	{
		public const string RootNamespace = "Expansions";

		public const string Version = "1.0.0";

		public const string VersionPrerelease = null;

		public const string VersionMetadata = "gitfbd117d-dirty-master";

		public const string SemVer = "1.0.0+gitfbd117d-dirty-master";

		public const string GitRevShort = "fbd117d-dirty";

		public const string GitRevLong = "fbd117d34bdc37962630c75f377a07297f961609-dirty";

		public const string GitBranch = "master";

		public const string GitTag = null;

		public const int GitCommitsSinceTag = 0;

		public const bool GitIsDirty = true;
	}
}
namespace Expansions.Patches.ToolAbility
{
	internal static class MinePatches
	{
		[HarmonyPatch(typeof(MineDeployerFirstPerson), "OnWield")]
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		private static void OnDeployerSpawn(MineDeployerFirstPerson __instance)
		{
			if (((Agent)((Item)__instance).Owner).IsLocallyOwned && !__instance.m_isConsumable && ToolAbilityHandler.Exists)
			{
				ToolAbilityHandler.Instance.OnDeployerWield(__instance);
			}
		}

		[HarmonyPatch(typeof(MineDeployerFirstPerson), "OnStickyMineSpawned")]
		[HarmonyPostfix]
		[HarmonyAfter(new string[] { "Dinorush.ExtraToolCustomization" })]
		[HarmonyWrapSafe]
		private static void OnMineSpawn(MineDeployerFirstPerson __instance, ISyncedItem item)
		{
			if (ToolAbilityHandler.Exists && !__instance.m_isConsumable)
			{
				ToolAbilityHandler.Instance.OnMineSpawn(((Il2CppObjectBase)item).Cast<MineDeployerInstance>());
			}
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "OnDestroy")]
		[HarmonyPrefix]
		[HarmonyWrapSafe]
		private static void OnMineDespawn(MineDeployerInstance __instance)
		{
			if (ToolAbilityHandler.Exists)
			{
				PlayerAgent owner = ((Item)__instance).Owner;
				if (owner != null && ((Agent)owner).IsLocallyOwned)
				{
					ToolAbilityHandler.Instance.OnMineDespawn(__instance);
				}
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPrefix]
		[HarmonyWrapSafe]
		private static bool PreMineCanWield(MineDeployerFirstPerson __instance, ref bool __result)
		{
			if (ToolAbilityHandler.InMineMode && !__instance.m_isConsumable)
			{
				__result = true;
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(MineDeployerFirstPerson), "Update")]
		[HarmonyPrefix]
		[HarmonyWrapSafe]
		private static void OnMineUpdate(MineDeployerFirstPerson __instance, ref (IInteractable interact, bool ladder) __state)
		{
			if (ToolAbilityHandler.MovingMine)
			{
				PlayerInteraction interaction = ((Item)__instance).Owner.Interaction;
				__state = (interact: interaction.m_bestSelectedInteract, ladder: interaction.m_enterLadderVisible);
				interaction.m_enterLadderVisible = false;
				interaction.m_bestSelectedInteract = null;
			}
		}

		[HarmonyPatch(typeof(MineDeployerFirstPerson), "Update")]
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		private static void OnMineUpdate(MineDeployerFirstPerson __instance, (IInteractable interact, bool ladder) __state)
		{
			if (ToolAbilityHandler.MovingMine)
			{
				__instance.m_placementIndicator.SetVisible(true);
				FirstPersonItemHolder fPItemHolder = ((ItemEquippable)__instance).FPItemHolder;
				bool itemHiddenTrigger = fPItemHolder.ItemHiddenTrigger;
				fPItemHolder.ItemHiddenTrigger = false;
				__instance.m_placementIndicator.SetPlacementEnabled(ToolAbilityHandler.CheckCanPlaceIgnoreHidden(__instance));
				fPItemHolder.ItemHiddenTrigger = itemHiddenTrigger;
				PlayerInteraction interaction = ((Item)__instance).Owner.Interaction;
				interaction.m_enterLadderVisible = __state.ladder;
				interaction.m_bestSelectedInteract = __state.interact;
			}
		}
	}
	internal static class PlayerPatches
	{
		[HarmonyPatch(typeof(LocalPlayerAgent), "Setup")]
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		private static void OnPlayerSpawn(LocalPlayerAgent __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<ToolAbilityHandler>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<ToolAbilityHandler>();
			}
		}
	}
	internal static class SentryPatches
	{
		[HarmonyPatch(typeof(SentryGunInstance), "OnGearSpawnComplete")]
		[HarmonyPostfix]
		[HarmonyAfter(new string[] { "Dinorush.ExtraToolCustomization" })]
		[HarmonyWrapSafe]
		private static void OnSentrySpawn(SentryGunInstance __instance)
		{
			if (ToolAbilityHandler.Exists)
			{
				PlayerAgent owner = ((Item)__instance).Owner;
				if (owner != null && ((Agent)owner).IsLocallyOwned)
				{
					ToolAbilityHandler.Instance.OnSentrySpawn(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(SentryGunInstance), "OnDestroy")]
		[HarmonyPrefix]
		[HarmonyWrapSafe]
		private static void OnSentryDespawn(SentryGunInstance __instance)
		{
			if (ToolAbilityHandler.Exists)
			{
				PlayerAgent owner = ((Item)__instance).Owner;
				if (owner != null && ((Agent)owner).IsLocallyOwned)
				{
					ToolAbilityHandler.Instance.OnSentryDespawn();
				}
			}
		}
	}
}
namespace Expansions.Patches.PackConverter
{
	internal static class ResourcePatches
	{
		[HarmonyPatch(typeof(PlayerAgent), "GiveAmmoRel")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Post_GiveAmmo(PlayerAgent __instance, float ammoStandardRel, float ammoSpecialRel, float ammoClassRel)
		{
			PackConverterManager.ApplyConversions(__instance, ammoStandardRel, ammoSpecialRel, ammoClassRel);
		}

		[HarmonyPatch(typeof(PlayerAgent), "GiveHealth")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Post_GiveHealth(PlayerAgent __instance, float amountRel)
		{
			PackConverterManager.ApplyConversions(__instance, ResourceType.Health, amountRel);
		}

		[HarmonyPatch(typeof(PlayerAgent), "GiveDisinfection")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void Post_GiveDisinfect(PlayerAgent __instance, float amountRel)
		{
			PackConverterManager.ApplyConversions(__instance, ResourceType.Disinfect, amountRel);
		}
	}
}
namespace Expansions.Patches.DoubleJump
{
	[HarmonyPatch]
	internal static class FallDamagePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Dam_SyncedDamageBase), "FallDamage")]
		private static bool FallDamage(Dam_SyncedDamageBase __instance)
		{
			//IL_0001: 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: Invalid comparison between Unknown and I4
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			if ((int)__instance.DamageBaseOwner != 0)
			{
				return true;
			}
			PlayerAgent val = ((Il2CppObjectBase)__instance.GetBaseAgent()).Cast<PlayerAgent>();
			if ((int)val.Locomotion.m_currentStateEnum == 3 || (int)val.Locomotion.m_currentStateEnum == 4)
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class PLOC_Patches
	{
		private static bool _canDoubleJump = true;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PLOC_Crouch), "Enter")]
		[HarmonyPatch(typeof(PLOC_Run), "Enter")]
		[HarmonyPatch(typeof(PLOC_Stand), "Enter")]
		public static void Enter()
		{
			_canDoubleJump = DoubleJumpManager.DoubleJumpUnlocked;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PLOC_Fall), "Update")]
		public static void Update(PLOC_Fall __instance)
		{
			TryDoubleJump((PLOC_Base)(object)__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PLOC_Jump), "Update")]
		public static void Update(PLOC_Jump __instance)
		{
			TryDoubleJump((PLOC_Base)(object)__instance);
		}

		private static void TryDoubleJump(PLOC_Base state)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			PlayerAgent owner = state.m_owner;
			if (_canDoubleJump && InputMapper.GetButtonDown.Invoke((InputAction)5, owner.InputFilter))
			{
				owner.Sound.Post(EVENTS.FLAMERFIREBURST, true);
				state.UpdateHorizontalVelocityOnGround(owner.PlayerData.runMoveSpeed);
				owner.Locomotion.ChangeState((PLOC_State)3, false);
				_canDoubleJump = false;
			}
		}
	}
	[HarmonyPatch]
	internal static class SuperJumpPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(PLOC_Jump), "Enter")]
		public static void Enter(PLOC_Jump __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			PlayerAgent owner = ((PLOC_Base)__instance).m_owner;
			if (DoubleJumpManager.DoubleJumpUnlocked && InputMapper.GetButtonKeyMouse((InputAction)10, owner.InputFilter))
			{
				owner.Sound.Post(EVENTS.IMPLANTSMALLJUMPBOOSTTRIGGER, true);
				PlayerLocomotion locomotion = owner.Locomotion;
				locomotion.VerticalVelocity += Vector3.up * DoubleJumpManager.ActiveConfig.SuperJumpVelocity;
			}
		}
	}
}
namespace Expansions.Information.ToolAbility
{
	public class ToolAbilityHandler : MonoBehaviour
	{
		private enum ToolMode
		{
			None,
			Sentry,
			Mine
		}

		private class ProgressGradient
		{
			private const float WidthBuffer = 50f;

			private static Sprite s_sprite;

			private readonly GameObject _overlayGO;

			private readonly GameObject _maskGO;

			private readonly (float x, float y) _size;

			private static Sprite Sprite
			{
				get
				{
					//IL_0015: Unknown result type (might be due to invalid IL or missing references)
					//IL_001a: Unknown result type (might be due to invalid IL or missing references)
					//IL_001d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					//IL_0041: Unknown result type (might be due to invalid IL or missing references)
					//IL_0050: Unknown result type (might be due to invalid IL or missing references)
					//IL_005f: Expected O, but got Unknown
					if ((Object)(object)s_sprite != (Object)null)
					{
						return s_sprite;
					}
					Texture2D val = new Texture2D(1, 1);
					val.SetPixel(0, 0, Color.white);
					val.Apply();
					s_sprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f), 1f);
					return s_sprite;
				}
			}

			public ProgressGradient(SpriteRenderer orig)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Expected O, but got Unknown
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: 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_0116: Expected O, but got Unknown
				_overlayGO = new GameObject("ProgressOverlay");
				_overlayGO.transform.SetParent(((Component)orig).transform, false);
				_overlayGO.layer = LayerManager.LAYER_UI;
				SpriteRenderer obj = _overlayGO.AddComponent<SpriteRenderer>();
				Color color = orig.color;
				color.g = 1f;
				color.a = 0.2f;
				obj.sprite = orig.sprite;
				obj.color = color;
				((Renderer)obj).sortingLayerID = ((Renderer)orig).sortingLayerID;
				((Renderer)obj).sortingOrder = ((Renderer)orig).sortingOrder + 1;
				obj.drawMode = orig.drawMode;
				obj.tileMode = orig.tileMode;
				obj.spriteSortPoint = orig.spriteSortPoint;
				_size = (x: orig.size.x + 50f, y: orig.size.y);
				obj.size = new Vector2(_size.x, _size.y);
				obj.maskInteraction = (SpriteMaskInteraction)1;
				_maskGO = new GameObject("ProgressMask");
				_maskGO.transform.SetParent(((Component)orig).transform, false);
				_maskGO.layer = LayerManager.LAYER_UI;
				SpriteMask obj2 = _maskGO.AddComponent<SpriteMask>();
				obj2.sprite = Sprite;
				obj2.alphaCutoff = 0f;
				obj2.frontSortingLayerID = ((Renderer)orig).sortingLayerID;
				obj2.backSortingLayerID = ((Renderer)orig).sortingLayerID;
				obj2.frontSortingOrder = ((Renderer)orig).sortingOrder + 1;
				obj2.backSortingOrder = ((Renderer)orig).sortingOrder + 1;
			}

			public void Update(float progress)
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				_maskGO.transform.localPosition = new Vector3(_size.x * (progress * 0.5f - 1f), 0f, 0f);
				_maskGO.transform.localScale = new Vector3(_size.x * progress, _size.y, 1f);
			}

			public void Destroy()
			{
				Object.Destroy((Object)(object)_maskGO);
				Object.Destroy((Object)(object)_overlayGO);
			}
		}

		private static PUI_InteractionPrompt s_interactPrompt;

		private PlayerAgent _player;

		private readonly CellSoundPlayer _sound = new CellSoundPlayer();

		private ProgressGradient _slimGradient;

		private ProgressGradient _selectedGradient;

		private float _recallDuration = 1f;

		private float _recallDeltaMod;

		private bool _recallingTool;

		private float _toolRecallProgress;

		private Interact_Timed? _activeInteract;

		private ToolMode _mode;

		private SentryGunInstance? _sentry;

		private MineDeployerInstance? _movingMine;

		private MineDeployerFirstPerson? _mineDeployer;

		private Color _origMineColor = Color.black;

		private readonly Dictionary<IntPtr, MineDeployerInstance> _activeMines = new Dictionary<IntPtr, MineDeployerInstance>();

		public static ToolAbilityHandler Instance { get; private set; }

		public static bool Exists { get; private set; }

		public static bool MovingMine
		{
			get
			{
				if (Exists)
				{
					return (Object)(object)Instance._movingMine != (Object)null;
				}
				return false;
			}
		}

		public static bool InMineMode
		{
			get
			{
				if (Exists)
				{
					return Instance.DoMineUpdate;
				}
				return false;
			}
		}

		public static bool InSentryMode
		{
			get
			{
				if (Exists)
				{
					return Instance.DoSentryUpdate;
				}
				return false;
			}
		}

		public float ToolRecallProgress
		{
			get
			{
				return _toolRecallProgress;
			}
			set
			{
				_toolRecallProgress = value;
				_slimGradient.Update(value);
				_selectedGradient.Update(value);
				if (_toolRecallProgress == 0f)
				{
					((RectTransformComp)s_interactPrompt).SetVisible(false);
				}
			}
		}

		private bool DoSentryUpdate
		{
			get
			{
				if (_mode == ToolMode.Sentry)
				{
					return ToolAbilityManager.ActiveAbility.SentryRecall;
				}
				return false;
			}
		}

		private bool DoMineUpdate
		{
			get
			{
				ToolAbilityData.LevelData activeAbility = ToolAbilityManager.ActiveAbility;
				if (_mode == ToolMode.Mine && _activeMines.Count > 0)
				{
					if (!activeAbility.MineRecall)
					{
						return activeAbility.MoveMines;
					}
					return true;
				}
				return false;
			}
		}

		public static bool CheckCanPlaceIgnoreHidden(MineDeployerFirstPerson deployer)
		{
			FirstPersonItemHolder fPItemHolder = ((ItemEquippable)deployer).FPItemHolder;
			bool itemHiddenTrigger = fPItemHolder.ItemHiddenTrigger;
			fPItemHolder.ItemHiddenTrigger = false;
			bool result = deployer.CheckCanPlace();
			fPItemHolder.ItemHiddenTrigger = itemHiddenTrigger;
			return result;
		}

		public ToolAbilityHandler(IntPtr ptr)
			: base(ptr)
		{
		}//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_0017: 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)


		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s_interactPrompt == (Object)null)
			{
				s_interactPrompt = ((Il2CppObjectBase)((GuiLayer)GuiManager.InteractionLayer).AddRectComp("Gui/Player/PUI_InteractionPrompt_CellUI", (GuiAnchor)3, new Vector2(0f, 0f), (Transform)null)).Cast<PUI_InteractionPrompt>();
				((Component)s_interactPrompt).transform.localPosition = new Vector3(0f, -360f, 0f);
				((Component)((Component)s_interactPrompt).transform.GetChild(2)).gameObject.SetActive(false);
				((Component)((Component)s_interactPrompt).transform.GetChild(3)).gameObject.SetActive(false);
				((RectTransformComp)s_interactPrompt).SetVisible(false);
			}
			_player = ((Component)this).GetComponent<PlayerAgent>();
			Instance = this;
			Exists = true;
			PUI_InventoryItem obj = GuiManager.PlayerLayer.Inventory.m_inventorySlots[(InventorySlot)3];
			SpriteRenderer component = ((Component)obj.m_slim_root.transform.GetChild(0).GetChild(5)).GetComponent<SpriteRenderer>();
			SpriteRenderer component2 = ((Component)obj.m_selected_root.transform.GetChild(0).GetChild(1)).GetComponent<SpriteRenderer>();
			_slimGradient = new ProgressGradient(component);
			_selectedGradient = new ProgressGradient(component2);
		}

		private void Update()
		{
			if (DoSentryUpdate)
			{
				UpdateSentry();
			}
			else if (DoMineUpdate)
			{
				UpdateMines();
			}
			if (_recallingTool)
			{
				ToolRecallProgress = Math.Min(1f, ToolRecallProgress + Clock.Delta * _recallDeltaMod);
			}
		}

		private void UpdateSentry()
		{
			CheckToggleRecall(Text.Get(1419u), (InputAction)25);
			if (ToolRecallProgress == 1f)
			{
				StopRecall(finished: true);
				ToolAbilityManager.DoSentryPickup(_sentry);
			}
		}

		private void UpdateMines()
		{
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_mineDeployer == (Object)null)
			{
				OnDeployerDespawn();
				return;
			}
			bool isActiveAndEnabled = ((Behaviour)_mineDeployer).isActiveAndEnabled;
			if (ToolAbilityManager.ActiveAbility.MineRecall)
			{
				if (isActiveAndEnabled)
				{
					if (_recallingTool)
					{
						((RectTransformComp)s_interactPrompt).SetVisible(true);
					}
					CheckToggleRecall(Text.Get(1420u), (InputAction)11);
				}
				else
				{
					((RectTransformComp)s_interactPrompt).SetVisible(false);
				}
			}
			if (_recallingTool && ToolRecallProgress == 1f)
			{
				StopRecall(finished: true);
				foreach (MineDeployerInstance value in _activeMines.Values)
				{
					value.WantItemAction(((Item)value).Owner, (SyncedItemAction_New)0);
				}
			}
			if (!ToolAbilityManager.ActiveAbility.MoveMines)
			{
				return;
			}
			if ((Object)(object)_movingMine != (Object)null)
			{
				if (!isActiveAndEnabled || !InputMapper.GetButtonKeyMouse((InputAction)8, _player.InputFilter))
				{
					PlayerInteraction interaction = _player.Interaction;
					bool enterLadderVisible = interaction.m_enterLadderVisible;
					IInteractable bestSelectedInteract = interaction.m_bestSelectedInteract;
					interaction.m_enterLadderVisible = false;
					interaction.m_bestSelectedInteract = null;
					if (CheckCanPlaceIgnoreHidden(_mineDeployer))
					{
						MineDeployerInstance? movingMine = _movingMine;
						RaycastHit lastRayHit = _mineDeployer.m_lastRayHit;
						Vector3 point = ((RaycastHit)(ref lastRayHit)).point;
						lastRayHit = _mineDeployer.m_lastRayHit;
						ToolAbilityManager.DoMineMove(movingMine, point, Quaternion.LookRotation(((RaycastHit)(ref lastRayHit)).normal * -1f, ((Component)((Item)_mineDeployer).Owner).transform.forward));
					}
					interaction.m_enterLadderVisible = enterLadderVisible;
					interaction.m_bestSelectedInteract = bestSelectedInteract;
					_mineDeployer.m_placementIndicator.m_colorEnabled = _origMineColor;
					_mineDeployer.m_placementIndicator.m_cookieLight.color = _origMineColor;
					_movingMine = null;
				}
			}
			else if (isActiveAndEnabled && InputMapper.GetButtonDownKeyMouse((InputAction)8, _player.InputFilter))
			{
				Interact_Timed? activeInteract = _activeInteract;
				MonoBehaviour val = ((activeInteract != null) ? ((Il2CppObjectBase)activeInteract).TryCast<MonoBehaviour>() : null);
				if ((Object)(object)val != (Object)null)
				{
					_movingMine = ((Component)((Component)val).transform.parent).GetComponent<MineDeployerInstance>();
					_mineDeployer.m_placementIndicator.m_colorEnabled = Color.cyan;
				}
			}
		}

		private void CheckToggleRecall(string toolName, InputAction toggleAction)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (!InputMapper.GetButtonDownKeyMouse(toggleAction, _player.InputFilter))
			{
				return;
			}
			if (!_recallingTool)
			{
				_recallingTool = true;
				_sound.Post(EVENTS.INTERACT_TOOL_START, true);
				((RectTransformComp)s_interactPrompt).SetVisible(true);
				s_interactPrompt.SetPrompt("Cancel " + toolName + " Recall", Text.Format(825u, (Object[])(object)new Object[1] { Object.op_Implicit(InputMapper.GetBindingName(toggleAction)) }));
				if (_mode == ToolMode.Sentry)
				{
					_recallDeltaMod = ToolAbilityManager.ActiveAbility.SentryRecallSpeed / _recallDuration;
				}
				else
				{
					_recallDeltaMod = ToolAbilityManager.ActiveAbility.MineRecallSpeed / _recallDuration;
				}
			}
			else
			{
				StopRecall();
			}
		}

		private void StopRecall(bool finished = false)
		{
			if (_recallingTool)
			{
				_recallingTool = false;
				_sound.Post(finished ? EVENTS.INTERACT_TOOL_FINISHED : EVENTS.INTERACT_TOOL_CANCEL, true);
				ToolRecallProgress = 0f;
				((RectTransformComp)s_interactPrompt).SetVisible(false);
			}
		}

		internal void OnSentrySpawn(SentryGunInstance sentry)
		{
			_mode = ToolMode.Sentry;
			_sentry = sentry;
			_activeInteract = ((Il2CppObjectBase)((Item)sentry).PickupInteraction).Cast<Interact_Timed>();
			_recallDuration = _activeInteract.InteractDuration;
		}

		internal void OnSentryDespawn()
		{
			_mode = ToolMode.None;
			_sentry = null;
			_activeInteract = null;
			StopRecall();
		}

		internal void OnDeployerWield(MineDeployerFirstPerson deployer)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_mineDeployer != (Object)null) || !(((Il2CppObjectBase)_mineDeployer).Pointer == ((Il2CppObjectBase)deployer).Pointer))
			{
				_mode = ToolMode.Mine;
				_mineDeployer = deployer;
				_origMineColor = deployer.m_placementIndicator.m_colorEnabled;
			}
		}

		internal void OnDeployerDespawn()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_mineDeployer != (Object)null)
			{
				_mineDeployer.m_placementIndicator.m_colorEnabled = _origMineColor;
			}
			_mineDeployer = null;
			_activeInteract = null;
			StopRecall();
			_activeMines.Clear();
		}

		internal void OnMineSpawn(MineDeployerInstance instance)
		{
			Interact_Timed interact = ((Il2CppObjectBase)((Item)instance).PickupInteraction).Cast<Interact_Timed>();
			Interact_Timed obj = interact;
			obj.OnInteractionSelected += Action<PlayerAgent, bool>.op_Implicit((Action<PlayerAgent, bool>)delegate(PlayerAgent player, bool selected)
			{
				if (selected)
				{
					_activeInteract = interact;
				}
				else
				{
					_activeInteract = null;
				}
			});
			_recallDuration = interact.InteractDuration;
			_activeMines.TryAdd(((Il2CppObjectBase)instance).Pointer, instance);
		}

		internal void OnMineDespawn(MineDeployerInstance mine)
		{
			if (_activeMines.Remove(((Il2CppObjectBase)mine).Pointer) && _activeMines.Count == 0)
			{
				_activeInteract = null;
				StopRecall();
			}
		}

		private void OnDestroy()
		{
			OnSentryDespawn();
			OnDeployerDespawn();
			_slimGradient.Destroy();
			_selectedGradient.Destroy();
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Exists = false;
				Instance = null;
			}
		}
	}
}
namespace Expansions.Information.PackConverter
{
	public class PackConverterData
	{
		public class LevelData
		{
			public class ConversionData
			{
				public ResourceType ReceiveType { get; set; }

				public ResourceType ConvertType { get; set; }

				public float Value { get; set; }
			}

			public int Level { get; set; }

			public List<ConversionData> Conversions { get; set; } = new List<ConversionData>();
		}

		public static readonly PackConverterData[] Template = new PackConverterData[1]
		{
			new PackConverterData
			{
				DebugName = "Template",
				DataChanges = new List<LevelData>
				{
					new LevelData
					{
						Level = 0,
						Conversions = new List<LevelData.ConversionData>
						{
							new LevelData.ConversionData
							{
								ReceiveType = ResourceType.Ammo,
								ConvertType = ResourceType.Tool,
								Value = 0.5f
							}
						}
					},
					new LevelData
					{
						Level = 10,
						Conversions = new List<LevelData.ConversionData>
						{
							new LevelData.ConversionData
							{
								ReceiveType = ResourceType.Standard,
								ConvertType = ResourceType.Tool,
								Value = 0.25f
							},
							new LevelData.ConversionData
							{
								ReceiveType = ResourceType.Special,
								ConvertType = ResourceType.Tool,
								Value = 0.25f
							},
							new LevelData.ConversionData
							{
								ReceiveType = ResourceType.Health,
								ConvertType = ResourceType.Disinfect,
								Value = 1f
							}
						}
					}
				}
			}
		};

		public int LevelLayoutID { get; set; }

		public string DebugName { get; set; } = string.Empty;

		public List<LevelData> DataChanges { get; set; } = new List<LevelData>();
	}
	public enum ResourceType
	{
		None,
		Standard,
		Special,
		Ammo,
		Tool,
		Health,
		Disinfect
	}
	public class ToolAbilityData
	{
		public class LevelData
		{
			public int Level { get; set; }

			public bool SentryRecall { get; set; }

			public float SentryRecallSpeed { get; set; } = 1f;

			public bool MoveMines { get; set; }

			public bool MineRecall { get; set; }

			public float MineRecallSpeed { get; set; } = 1f;
		}

		public static readonly ToolAbilityData[] Template = new ToolAbilityData[1]
		{
			new ToolAbilityData
			{
				DebugName = "Template",
				DataChanges = new List<LevelData>
				{
					new LevelData()
				}
			}
		};

		public int LevelLayoutID { get; set; }

		public string DebugName { get; set; } = string.Empty;

		public List<LevelData> DataChanges { get; set; } = new List<LevelData>();
	}
}
namespace XpExpansions
{
	[BepInPlugin("Endskill.XpExpansions", "XpExpansions", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class BepinExLoader : BasePlugin
	{
		public const string MODNAME = "XpExpansions";

		public const string AUTHOR = "Endskill";

		public const string GUID = "Endskill.XpExpansions";

		public const string VERSION = "1.1.0";

		public override void Load()
		{
			LogManager.SetLogger(((BasePlugin)this).Log);
			LogManager._debugMessagesActive = ((BasePlugin)this).Config.Bind<bool>("Dev Settings", "DebugMessages", false, "This settings activates/deactivates debug messages in the console for this specific plugin.").Value;
			ClassInjector.RegisterTypeInIl2Cpp<ClientSidedBioTrackerAbility>();
			CacheApi.SaveInstance<ExpansionManager>(new ExpansionManager(), CacheApiWrapper.ExtensionCacheName);
		}
	}
}
namespace XpExpansions.Util
{
	public static class DoorUtil
	{
		private const float PortalCheckBuffer = 0.25f;

		private const float MinDotInNode = 0.1f;

		private static readonly List<AIG_CoursePortal> _portalCache = new List<AIG_CoursePortal>();

		public static bool TryGetNearbyPortal(Vector3 pos, AIG_CourseNode node, [MaybeNullWhen(false)] out AIG_CoursePortal portal)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			portal = null;
			Enumerator<AIG_CoursePortal> enumerator = node.m_portals.GetEnumerator();
			float num2 = default(float);
			float num3 = default(float);
			while (enumerator.MoveNext())
			{
				AIG_CoursePortal current = enumerator.Current;
				Vector3 val = pos - current.Position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				current.m_cullPortal.GetShapeWidthHeight(ref num2, ref num3);
				num2 /= 2f;
				num3 /= 2f;
				num2 += 0.25f;
				num3 += 0.25f;
				if (sqrMagnitude < num && sqrMagnitude < num2 * num2 + num3 * num3)
				{
					portal = current;
					num = sqrMagnitude;
				}
			}
			return portal != null;
		}

		public static bool TryGetCrossPortal(Vector3 pos, AIG_CourseNode nodeA, AIG_CourseNode nodeB, [MaybeNullWhen(false)] out AIG_CoursePortal portal)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			int nodeID = nodeB.NodeID;
			Enumerator<AIG_CoursePortal> enumerator = nodeA.m_portals.GetEnumerator();
			while (enumerator.MoveNext())
			{
				AIG_CoursePortal current = enumerator.Current;
				if (current.GetOppositeNode(nodeA).NodeID == nodeID)
				{
					_portalCache.Add(current);
				}
			}
			if (_portalCache.Count == 0)
			{
				portal = null;
				return false;
			}
			if (_portalCache.Count == 1)
			{
				portal = _portalCache[0];
				_portalCache.Clear();
				return true;
			}
			float num = float.MaxValue;
			portal = null;
			foreach (AIG_CoursePortal item in _portalCache)
			{
				Vector3 val = pos - item.Position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					portal = item;
					num = sqrMagnitude;
				}
			}
			_portalCache.Clear();
			return true;
		}

		public static bool IsOnSameSide(Vector3 pos, AIG_CourseNode checkNode, AIG_CoursePortal portal)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0020: Unknown result type (might be due to invalid IL or missing references)
			C_Portal cullPortal = portal.m_cullPortal;
			Vector3 val = pos - cullPortal.m_center;
			return Vector3.Dot(cullPortal.GetDirIntoNode(checkNode.m_cullNode), val) > 0.1f;
		}

		public static AIG_CourseNode GetCorrectNode(Vector3 pos, AIG_CourseNode node)
		{
			//IL_0000: 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)
			if (TryGetNearbyPortal(pos, node, out AIG_CoursePortal portal))
			{
				AIG_CourseNode oppositeNode = portal.GetOppositeNode(node);
				if (IsOnSameSide(pos, oppositeNode, portal))
				{
					return oppositeNode;
				}
			}
			return node;
		}

		public static bool CanTouchNode(Vector3 pos, AIG_CourseNode node, AIG_CourseNode checkNode)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (node.NodeID == checkNode.NodeID)
			{
				return true;
			}
			if (!TryGetCrossPortal(pos, node, checkNode, out AIG_CoursePortal portal))
			{
				return false;
			}
			if (portal.IsTraversable)
			{
				return true;
			}
			return IsOnSameSide(pos, checkNode, portal);
		}

		public static bool CanTouchNode(Vector3 pos, AIG_CourseNode checkNode)
		{
			//IL_0000: 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)
			if (!TryGetNearbyPortal(pos, checkNode, out AIG_CoursePortal portal) || portal.IsTraversable)
			{
				return true;
			}
			return IsOnSameSide(pos, checkNode, portal);
		}
	}
}
namespace XpExpansions.Scripts
{
	public class ClientSidedBioTrackerAbility : MonoBehaviour
	{
		private float _nextUpdate;

		public ClientSidedBioTrackerAbility(IntPtr intPtr)
			: base(intPtr)
		{
		}

		public void Update()
		{
			if (!(Time.time > _nextUpdate))
			{
				return;
			}
			if (GameStateManager.IsInExpedition)
			{
				PlayerManager.GetLocalPlayerAgent();
				Enumerator<EnemyAgent> enumerator = AIG_CourseGraph.GetReachableEnemiesInNodes(((Agent)PlayerManager.GetLocalPlayerAgent()).CourseNode, 1).GetEnumerator();
				while (enumerator.MoveNext())
				{
					ToolSyncManager.WantToTagEnemy(enumerator.Current);
				}
			}
			_nextUpdate = Time.time + 10f;
		}
	}
}
namespace XpExpansions.Patches
{
	[HarmonyBefore(new string[] { "Endskill.XpExpansions", "Endskill.GTFuckingXP" })]
	[HarmonyPatch(typeof(Dam_EnemyDamageBase))]
	public class EnemyDamageBasePatches
	{
		[HarmonyPatch("MeleeDamage")]
		[HarmonyPrefix]
		public static bool MeleePrefix(Dam_EnemyDamageBase __instance, ref float dam, Agent sourceAgent)
		{
			return true;
		}
	}
}
namespace XpExpansions.Manager
{
	public abstract class BaseManager
	{
		private static string? _folderPath;

		protected string FolderPath
		{
			get
			{
				if (string.IsNullOrEmpty(_folderPath))
				{
					_folderPath = CacheApiWrapper.GetFolderPath();
				}
				return _folderPath;
			}
		}

		public virtual bool LocalOnly => true;

		public virtual void LevelReached(PlayerAgent player, Level level)
		{
		}

		public virtual void LevelInitialized(Level level)
		{
		}

		public virtual void Initialize()
		{
		}

		public virtual void LevelCleanup()
		{
		}
	}
	public class ClientSidedBioTrackerManager : BaseManager
	{
		private const string _expansionFileName = "BioTracker.json";

		public ClientSidedBioTrackerManager()
		{
			LevelApi.AddEndLevelCallback((Action)DestroyBioTrackerAbility);
		}

		public override void Initialize()
		{
			WriteDefaultJsonBlocks();
			UpdateEverything();
		}

		public override void LevelReached(PlayerAgent player, Level level)
		{
			LevelLayout levelLayout = CacheApiWrapper.GetCurrentLevelLayout();
			LocalBioTrackerData localBioTrackerData = CacheApi.GetInstance<List<LocalBioTrackerData>>(CacheApiWrapper.ExtensionCacheName).FirstOrDefault((LocalBioTrackerData it) => it.LevelLayoutPersistentId == levelLayout.PersistentId);
			if (localBioTrackerData != null)
			{
				if (localBioTrackerData.UnlockAtLevel <= level.LevelNumber)
				{
					CacheApiWrapper.DestroyOldCreateRegisterAndReturnComponent<ClientSidedBioTrackerAbility>();
				}
				else
				{
					DestroyBioTrackerAbility();
				}
			}
		}

		public void DestroyBioTrackerAbility()
		{
			CacheApiWrapper.KillScript<ClientSidedBioTrackerAbility>();
		}

		private void WriteDefaultJsonBlocks()
		{
			if (!Directory.Exists(base.FolderPath))
			{
				Directory.CreateDirectory(base.FolderPath);
			}
			string path = Path.Combine(base.FolderPath, "BioTracker.json");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, ExpJson.Serialize(GetDefaultData()));
			}
		}

		private void UpdateEverything()
		{
			CacheApi.SaveInstance<List<LocalBioTrackerData>>(ExpJson.Deserialize<List<LocalBioTrackerData>>(File.ReadAllText(Path.Combine(base.FolderPath, "BioTracker.json"))), CacheApiWrapper.ExtensionCacheName);
		}

		private List<LocalBioTrackerData> GetDefaultData()
		{
			List<LocalBioTrackerData> list = new List<LocalBioTrackerData>();
			for (int i = 0; i < 20; i++)
			{
				list.Add(new LocalBioTrackerData(i, 3));
			}
			return list;
		}
	}
	public class DeactivateManager : BaseManager
	{
		private const string _expansionFileName = "DeactivateOnMissions.json";

		private const string _expansionClassFileName = "DeactivateClassLayout.json";

		public override void Initialize()
		{
		}

		private void WriteDefaultJsonBlocks()
		{
			if (base.FolderPath.Contains("BepInEx"))
			{
				if (!Directory.Exists(base.FolderPath))
				{
					Directory.CreateDirectory(base.FolderPath);
				}
				string path = Path.Combine(base.FolderPath, "DeactivateOnMissions.json");
				if (!File.Exists(path))
				{
					File.WriteAllText(path, ExpJson.Serialize(new List<int> { 69420, 42069 }));
				}
			}
		}
	}
	public class DoubleJumpManager : BaseManager
	{
		public const string OldGUID = "com.mccad00.DoubleJump";

		public const string DoubleJumpXpExpansionId = "Endskill.DoubleJumpExpansion";

		private const string _expansionFileName = "DoubleJumpExpansion.json";

		private const string _configFileName = "DoubleJumpDefaultConfig.json";

		private static DoubleJumpConfig _baseConfig = new DoubleJumpConfig();

		public static DoubleJumpConfig ActiveConfig { get; private set; } = new DoubleJumpConfig();

		public static bool DoubleJumpUnlocked { get; private set; }

		public DoubleJumpManager()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Harmony.UnpatchID("com.mccad00.DoubleJump");
			DoubleJumpUnlocked = false;
			Harmony val = new Harmony("Endskill.DoubleJumpExpansion");
			val.PatchAll(typeof(PLOC_Patches));
			val.PatchAll(typeof(FallDamagePatches));
			val.PatchAll(typeof(SuperJumpPatches));
		}

		public override void Initialize()
		{
			WriteDefaultJsonBlocks();
			UpdateEverything();
		}

		public override void LevelCleanup()
		{
			DoubleJumpUnlocked = false;
		}

		public override void LevelReached(PlayerAgent player, Level level)
		{
			LogManager.Message("LevelReached, DoubleJump " + ((object)level).ToString());
			LevelLayout levelLayout = CacheApiWrapper.GetCurrentLevelLayout();
			DoubleJumpData doubleJumpData = CacheApi.GetInstance<List<DoubleJumpData>>(CacheApiWrapper.ExtensionCacheName).FirstOrDefault((DoubleJumpData it) => it.LevelLayoutPersistentId == levelLayout.PersistentId);
			if (doubleJumpData != null)
			{
				if (doubleJumpData.UnlockAtLevel <= level.LevelNumber)
				{
					DoubleJumpUnlocked = true;
					ActiveConfig = doubleJumpData.DoubleJumpConfig ?? _baseConfig;
				}
				else
				{
					DoubleJumpUnlocked = false;
				}
			}
			else
			{
				DoubleJumpUnlocked = false;
			}
		}

		private void WriteDefaultJsonBlocks()
		{
			if (!Directory.Exists(base.FolderPath))
			{
				Directory.CreateDirectory(base.FolderPath);
			}
			string path = Path.Combine(base.FolderPath, "DoubleJumpExpansion.json");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, "[\r\n  {\r\n    \"LevelLayoutPersistentId\": 13,\r\n    \"UnlockAtLevel\": 10,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 14,\r\n    \"UnlockAtLevel\": 6,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 7,\r\n    \"UnlockAtLevel\": 5,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 8,\r\n    \"UnlockAtLevel\": 5,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 15,\r\n    \"UnlockAtLevel\": 5,\r\n    \"DoubleJumpConfig\": null\r\n  }\r\n]");
			}
			string path2 = Path.Combine(base.FolderPath, "DoubleJumpDefaultConfig.json");
			if (File.Exists(path2))
			{
				_baseConfig = ExpJson.Deserialize<DoubleJumpConfig>(File.ReadAllText(path2));
				return;
			}
			string path3 = Path.Combine(ConfigManager.CustomPath, "mccad00", "DoubleJump.json");
			if (File.Exists(path3))
			{
				_baseConfig = ExpJson.Deserialize<DoubleJumpConfig>(File.ReadAllText(path3));
			}
			else
			{
				_baseConfig = new DoubleJumpConfig();
			}
			File.WriteAllText(path2, ExpJson.Serialize(_baseConfig));
		}

		private void UpdateEverything()
		{
			CacheApi.SaveInstance<List<DoubleJumpData>>(ExpJson.Deserialize<List<DoubleJumpData>>(File.ReadAllText(Path.Combine(base.FolderPath, "DoubleJumpExpansion.json"))), CacheApiWrapper.ExtensionCacheName);
		}
	}
	public class ExpansionManager : BaseManager
	{
		public const string ExpansionActivePath = "ExpansionsActive.json";

		public override bool LocalOnly => false;

		public ExpansionManager()
		{
			LogManager.Message("ExpansionManager constructor.");
			InitApi.AddInitCallback((Action)Initialize);
			LevelApi.AddEndLevelCallback((Action)LevelCleanup);
			XpApi.AddOnLevelUpCallback((Action<PlayerAgent, Level>)LevelReached);
			XpApi.AddScriptsLoaded((Action<Level>)LevelInitialized);
		}

		public override void Initialize()
		{
			CacheApiWrapper.SetFolderPath(Path.Combine(ScriptManager.Instance.GetFolderPath(), "Expansions"));
			WriteDefaultData();
			List<BaseManager> list = CreateManagers();
			CacheApi.SaveInstance<List<BaseManager>>(list, CacheApiWrapper.ExtensionCacheName);
			foreach (BaseManager item in list)
			{
				item.Initialize();
			}
		}

		public override void LevelCleanup()
		{
			foreach (BaseManager item in CacheApi.GetInstance<List<BaseManager>>(CacheApiWrapper.ExtensionCacheName))
			{
				item.LevelCleanup();
			}
		}

		public override void LevelReached(PlayerAgent player, Level level)
		{
			LogManager.Message("LevelReached in the Expansion Manager.");
			foreach (BaseManager item in CacheApi.GetInstance<List<BaseManager>>(CacheApiWrapper.ExtensionCacheName))
			{
				if (!item.LocalOnly || ((Agent)player).IsLocallyOwned)
				{
					item.LevelReached(player, level);
				}
			}
		}

		public override void LevelInitialized(Level level)
		{
			LogManager.Message("LevelInitialized in the Expansion Manager.");
			foreach (BaseManager item in CacheApi.GetInstance<List<BaseManager>>(CacheApiWrapper.ExtensionCacheName))
			{
				item.LevelInitialized(level);
			}
		}

		private List<BaseManager> CreateManagers()
		{
			List<BaseManager> list = new List<BaseManager>();
			ActiveExpansions activeExpansions = ExpJson.Deserialize<ActiveExpansions>(File.ReadAllText(Path.Combine(base.FolderPath, "ExpansionsActive.json")));
			LogManager.Debug("CreateManagers method.");
			if (activeExpansions != null)
			{
				if (activeExpansions.DoubleJumpAbility)
				{
					list.Add(new DoubleJumpManager());
				}
				if (activeExpansions.StartingXp)
				{
					list.Add(new StartingLevelXpManager());
				}
				if (activeExpansions.LivingBioAbility)
				{
					list.Add(new ClientSidedBioTrackerManager());
				}
				if (activeExpansions.PackConverter)
				{
					list.Add(new PackConverterManager());
				}
				if (activeExpansions.ToolAbility)
				{
					list.Add(new ToolAbilityManager());
				}
			}
			return list;
		}

		private void WriteDefaultData()
		{
			if (!Directory.Exists(base.FolderPath))
			{
				Directory.CreateDirectory(base.FolderPath);
			}
			string path = Path.Combine(base.FolderPath, "ExpansionsActive.json");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, ExpJson.Serialize(new ActiveExpansions()));
			}
		}
	}
	public class ExplosionAbilityManager : BaseManager
	{
		public const string ExplosionHarmonyInstanceId = "Endskill.ExplosionAbility";

		public Harmony ExplosionHarmony { get; private set; }

		public ExplosionAbilityManager()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			ExplosionHarmony = new Harmony("Endskill.ExplosionAbility");
		}

		public override void Initialize()
		{
		}

		public override void LevelCleanup()
		{
		}
	}
	public static class LogManager
	{
		private static ManualLogSource logger;

		internal static bool _debugMessagesActive;

		internal static void SetLogger(ManualLogSource log)
		{
			logger = log;
		}

		public static void Verbose(object msg)
		{
			if (_debugMessagesActive)
			{
				logger.LogInfo(msg);
			}
		}

		public static void Debug(object msg)
		{
			if (_debugMessagesActive)
			{
				logger.LogDebug(msg);
			}
		}

		public static void Message(object msg)
		{
			if (_debugMessagesActive)
			{
				logger.LogMessage(msg);
			}
		}

		public static void Error(object msg)
		{
			logger.LogError(msg);
		}

		public static void Warn(object msg)
		{
			logger.LogWarning(msg);
		}
	}
	public class PackConverterManager : BaseManager
	{
		private class ConversionWrapper
		{
			private readonly Dictionary<ResourceType, List<PackConverterData.LevelData.ConversionData>> _typeToConversions = new Dictionary<ResourceType, List<PackConverterData.LevelData.ConversionData>>();

			public ConversionWrapper(PackConverterData.LevelData dataChanges)
			{
				foreach (PackConverterData.LevelData.ConversionData conversion in dataChanges.Conversions)
				{
					if (!_typeToConversions.TryGetValue(conversion.ReceiveType, out List<PackConverterData.LevelData.ConversionData> value))
					{
						value = (_typeToConversions[conversion.ReceiveType] = new List<PackConverterData.LevelData.ConversionData>());
					}
					value.Add(conversion);
				}
			}

			public void ApplyConversions(PlayerAgent player, ResourceType type, float amount)
			{
				if (_typeToConversions.TryGetValue(type, out List<PackConverterData.LevelData.ConversionData> value))
				{
					float standard = 0f;
					float special = 0f;
					float tool = 0f;
					float disinfect = 0f;
					float health = 0f;
					AddConversions(value, amount, ref standard, ref special, ref tool, ref health, ref disinfect);
					ApplyConversions(player, standard, special, tool, health, disinfect);
				}
			}

			public void ApplyConversions(PlayerAgent player, float standardAmount, float specialAmount, float toolAmount)
			{
				float standard = 0f;
				float special = 0f;
				float tool = 0f;
				float disinfect = 0f;
				float health = 0f;
				if (_typeToConversions.TryGetValue(ResourceType.Standard, out List<PackConverterData.LevelData.ConversionData> value))
				{
					AddConversions(value, standardAmount, ref standard, ref special, ref tool, ref health, ref disinfect);
				}
				if (_typeToConversions.TryGetValue(ResourceType.Special, out value))
				{
					AddConversions(value, specialAmount, ref standard, ref special, ref tool, ref health, ref disinfect);
				}
				if (_typeToConversions.TryGetValue(ResourceType.Ammo, out value))
				{
					AddConversions(value, (standardAmount + specialAmount) / 2f, ref standard, ref special, ref tool, ref health, ref disinfect);
				}
				if (_typeToConversions.TryGetValue(ResourceType.Tool, out value))
				{
					AddConversions(value, toolAmount, ref standard, ref special, ref tool, ref health, ref disinfect);
				}
				ApplyConversions(player, standard, special, tool, health, disinfect);
			}

			private static void AddConversions(List<PackConverterData.LevelData.ConversionData> list, float amount, ref float standard, ref float special, ref float tool, ref float health, ref float disinfect)
			{
				foreach (PackConverterData.LevelData.ConversionData item in list)
				{
					float num = item.Value * amount;
					switch (item.ConvertType)
					{
					case ResourceType.Standard:
						standard += num;
						break;
					case ResourceType.Special:
						special += num;
						break;
					case ResourceType.Ammo:
						standard += num / 2f;
						special += num / 2f;
						break;
					case ResourceType.Tool:
						tool += num;
						break;
					case ResourceType.Health:
						health += num;
						break;
					case ResourceType.Disinfect:
						disinfect += num;
						break;
					}
				}
			}

			private static void ApplyConversions(PlayerAgent player, float standard, float special, float tool, float health, float disinfect)
			{
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_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)
				if (standard != 0f || special != 0f || tool != 0f)
				{
					PlayerBackpackManager.GiveAmmoToPlayer(player.Owner, standard, special, tool);
				}
				if (health != 0f)
				{
					PlayerBackpackManager.PickupHealthRel(health, player);
				}
				if (disinfect != 0f)
				{
					player.Damage.ModifyInfection(new pInfection
					{
						amount = 0f - disinfect,
						effect = (pInfectionEffect)1,
						mode = (pInfectionMode)1
					}, true, true);
				}
			}
		}

		public const string ExpansionID = "Endskill.PackConverter";

		private const string _expansionFileName = "PackConverterExpansion.json";

		private static readonly Dictionary<IntPtr, ConversionWrapper> _activeConversions = new Dictionary<IntPtr, ConversionWrapper>();

		private static List<PackConverterData> JsonData = new List<PackConverterData>();

		public override bool LocalOnly => false;

		public static void ApplyConversions(PlayerAgent player, ResourceType type, float amount)
		{
			if (_activeConversions.TryGetValue(((Il2CppObjectBase)player).Pointer, out ConversionWrapper value))
			{
				value.ApplyConversions(player, type, amount);
			}
		}

		public static void ApplyConversions(PlayerAgent player, float standardAmount, float specialAmount, float toolAmount)
		{
			if (_activeConversions.TryGetValue(((Il2CppObjectBase)player).Pointer, out ConversionWrapper value))
			{
				value.ApplyConversions(player, standardAmount, specialAmount, toolAmount);
			}
		}

		public PackConverterManager()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			new Harmony("Endskill.PackConverter").PatchAll(typeof(ResourcePatches));
		}

		public override void Initialize()
		{
			WriteDefaultJsonBlocks();
			UpdateEverything();
		}

		public override void LevelCleanup()
		{
			_activeConversions.Clear();
		}

		public override void LevelReached(PlayerAgent player, Level level)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			ActiveLevel val = default(ActiveLevel);
			if (!CacheApiWrapper.TryGetFullActiveLevel(player, ref val))
			{
				return;
			}
			int levelLayoutID = val.Layout.PersistentId;
			PackConverterData packConverterData = JsonData.Find((PackConverterData it) => it.LevelLayoutID == levelLayoutID);
			if (packConverterData == null)
			{
				return;
			}
			for (int num = packConverterData.DataChanges.Count - 1; num >= 0; num--)
			{
				PackConverterData.LevelData levelData = packConverterData.DataChanges[num];
				if (levelData.Level <= level.LevelNumber)
				{
					_activeConversions[((Il2CppObjectBase)player).Pointer] = new ConversionWrapper(levelData);
					break;
				}
			}
		}

		private void WriteDefaultJsonBlocks()
		{
			if (!Directory.Exists(base.FolderPath))
			{
				Directory.CreateDirectory(base.FolderPath);
			}
			string path = Path.Combine(base.FolderPath, "PackConverterExpansion.json");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, ExpJson.Serialize(PackConverterData.Template));
			}
		}

		private void UpdateEverything()
		{
			JsonData = ExpJson.Deserialize<List<PackConverterData>>(File.ReadAllText(Path.Combine(base.FolderPath, "PackConverterExpansion.json")));
			foreach (PackConverterData jsonDatum in JsonData)
			{
				jsonDatum.DataChanges.Sort((PackConverterData.LevelData x, PackConverterData.LevelData y) => x.Level.CompareTo(y.Level));
			}
		}
	}
	internal class StartingLevelXpManager : BaseManager
	{
		private const string _expansionFileName = "StartingXP.json";

		public override void Initialize()
		{
			WriteDefaultJsonBlocks();
			UpdateEverything();
		}

		public override void LevelInitialized(Level level)
		{
			ExpeditionInTierData expedition = RundownManager.ActiveExpedition;
			StartingXpData startingXpData = CacheApi.GetInstance<List<StartingXpData>>(CacheApiWrapper.ExtensionCacheName).FirstOrDefault((StartingXpData it) => it.LevelLayoutData == expedition.LevelLayoutData);
			if (startingXpData != null)
			{
				XpApi.AddXp(startingXpData.StartingXp);
			}
		}

		private void UpdateEverything()
		{
			CacheApi.SaveInstance<List<StartingXpData>>(ExpJson.Deserialize<List<StartingXpData>>(File.ReadAllText(Path.Combine(base.FolderPath, "StartingXP.json"))), CacheApiWrapper.ExtensionCacheName);
		}

		private void WriteDefaultJsonBlocks()
		{
			if (!Directory.Exists(base.FolderPath))
			{
				Directory.CreateDirectory(base.FolderPath);
			}
			string path = Path.Combine(base.FolderPath, "StartingXP.json");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, ExpJson.Serialize(GetDefaultData()));
			}
		}

		private List<StartingXpData> GetDefaultData()
		{
			List<StartingXpData> list = new List<StartingXpData>();
			foreach (RundownDataBlock allBlock in GameDataBlockBase<RundownDataBlock>.GetAllBlocks())
			{
				Enumerator<ExpeditionInTierData> enumerator2 = allBlock.TierD.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					ExpeditionInTierData current = enumerator2.Current;
					list.Add(new StartingXpData(current.LevelLayoutData, 100));
				}
			}
			return list;
		}
	}
	public class ToolAbilityManager : BaseManager
	{
		private struct MoveMineData
		{
			public pReplicator mine;

			public pCourseNode courseNode;

			public Vector3 position;

			public Quaternion rotation;
		}

		public const string ExpansionID = "Endskill.ToolAbility";

		private const string _expansionFileName = "ToolAbilityExpansion.json";

		private const string PickupNetworkID = "ToolAbilityPickup";

		private const string MoveMineNetworkID = "ToolAbilityMoveMine";

		private static List<ToolAbilityData> JsonData = new List<ToolAbilityData>();

		public static ToolAbilityData.LevelData ActiveAbility { get; private set; } = new ToolAbilityData.LevelData();

		public ToolAbilityManager()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			Harmony val = new Harmony("Endskill.ToolAbility");
			val.PatchAll(typeof(PlayerPatches));
			val.PatchAll(typeof(SentryPatches));
			val.PatchAll(typeof(MinePatches));
			ClassInjector.RegisterTypeInIl2Cpp<ToolAbilityHandler>();
			NetworkAPI.RegisterEvent<pReplicator>("ToolAbilityPickup", (Action<ulong, pReplicator>)PickupSentry);
			NetworkAPI.RegisterEvent<MoveMineData>("ToolAbilityMoveMine", (Action<ulong, MoveMineData>)MoveMine);
		}

		public override void Initialize()
		{
			WriteDefaultJsonBlocks();
			UpdateEverything();
		}

		public override void LevelCleanup()
		{
			ActiveAbility = new ToolAbilityData.LevelData();
		}

		public override void LevelReached(PlayerAgent player, Level level)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			ActiveLevel val = default(ActiveLevel);
			if (!CacheApiWrapper.TryGetFullActiveLevel(player, ref val))
			{
				return;
			}
			int levelLayoutID = val.Layout.PersistentId;
			ToolAbilityData toolAbilityData = JsonData.Find((ToolAbilityData it) => it.LevelLayoutID == levelLayoutID);
			if (toolAbilityData == null)
			{
				return;
			}
			for (int num = toolAbilityData.DataChanges.Count - 1; num >= 0; num--)
			{
				ToolAbilityData.LevelData levelData = toolAbilityData.DataChanges[num];
				if (levelData.Level <= level.LevelNumber)
				{
					ActiveAbility = levelData;
					break;
				}
			}
		}

		private void WriteDefaultJsonBlocks()
		{
			if (!Directory.Exists(base.FolderPath))
			{
				Directory.CreateDirectory(base.FolderPath);
			}
			string path = Path.Combine(base.FolderPath, "ToolAbilityExpansion.json");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, ExpJson.Serialize(ToolAbilityData.Template));
			}
		}

		private void UpdateEverything()
		{
			JsonData = ExpJson.Deserialize<List<ToolAbilityData>>(File.ReadAllText(Path.Combine(base.FolderPath, "ToolAbilityExpansion.json")));
			foreach (ToolAbilityData jsonDatum in JsonData)
			{
				jsonDatum.DataChanges.Sort((ToolAbilityData.LevelData x, ToolAbilityData.LevelData y) => x.Level.CompareTo(y.Level));
			}
		}

		public static void DoSentryPickup(SentryGunInstance sentry)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			pReplicator val = default(pReplicator);
			((pReplicator)(ref val)).SetID(sentry.Replicator);
			NetworkAPI.InvokeEvent<pReplicator>("ToolAbilityPickup", val, SNet.Master, (SNet_ChannelType)2);
		}

		public static void DoMineMove(MineDeployerInstance mine, Vector3 newPos, Quaternion rotation)
		{
			//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_0024: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			MoveMineData moveMineData = default(MoveMineData);
			((pReplicator)(ref moveMineData.mine)).SetID(mine.Replicator);
			moveMineData.position = newPos;
			moveMineData.rotation = rotation;
			((pCourseNode)(ref moveMineData.courseNode)).Set(DoorUtil.GetCorrectNode(newPos, ((Agent)((Item)mine).Owner).CourseNode));
			NetworkAPI.InvokeEvent<MoveMineData>("ToolAbilityMoveMine", moveMineData, (SNet_ChannelType)2);
			MoveMine(0uL, moveMineData);
		}

		private static void PickupSentry(ulong _, pReplicator packet)
		{
			//IL_0077: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			IReplicator val = default(IReplicator);
			if (!((pReplicator)(ref packet)).TryGetID(ref val) || val == null)
			{
				return;
			}
			SentryGunInstance val2 = ((Il2CppObjectBase)val.ReplicatorSupplier).Cast<SentryGunInstance>();
			if (!val2.Alive || (Object)(object)((Item)val2).Owner == (Object)null)
			{
				return;
			}
			PlayerAgent owner = ((Item)val2).Owner;
			SNet_Player owner2 = owner.Owner;
			PlayerBackpack val3 = default(PlayerBackpack);
			BackpackItem val4 = default(BackpackItem);
			if (!PlayerBackpackManager.TryGetBackpack(owner2, ref val3) || !val3.TryGetBackpackItem((InventorySlot)3, ref val4))
			{
				return;
			}
			if (SNet.IsMaster)
			{
				if (!val2.Alive)
				{
					return;
				}
				NetworkAPI.InvokeEvent<pReplicator>("ToolAbilityPickup", packet, (SNet_ChannelType)2);
			}
			if ((int)val4.Status != 0)
			{
				val4.Status = (eInventoryItemStatus)0;
				if (owner2.IsLocal || (SNet.IsMaster && owner2.IsBot))
				{
					pInventoryItemStatus val5 = default(pInventoryItemStatus);
					((pPlayer)(ref val5.sourcePlayer)).SetPlayer(owner2);
					val5.slot = (InventorySlot)3;
					val5.status = (eInventoryItemStatus)0;
					PlayerBackpackManager.InventoryItemStatusChange(val5, (SNet_Player)null);
				}
				else
				{
					val3.ShowHideInstance(val4, true);
				}
				GuiManager.PlayerLayer.Inventory.UpdateItemUI(val4, owner.Inventory.WieldedSlot, true);
			}
			((Item)val2).SyncedPickup(owner);
		}

		private static void MoveMine(ulong _, MoveMineData data)
		{
			//IL_0028: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			IReplicator val = default(IReplicator);
			if (((pReplicator)(ref data.mine)).TryGetID(ref val) && val != null)
			{
				MineDeployerInstance val2 = ((Il2CppObjectBase)val.ReplicatorSupplier).Cast<MineDeployerInstance>();
				Transform transform = ((Component)val2).transform;
				transform.position = data.position;
				transform.rotation = data.rotation;
				AIG_CourseNode courseNode = default(AIG_CourseNode);
				if (((pCourseNode)(ref data.courseNode)).TryGet(ref courseNode))
				{
					val2.m_courseNode = courseNode;
				}
				((ItemEquippable)val2).Sound.Post(EVENTS.STICKYMINEATTACH, data.position);
			}
		}
	}
}
namespace XpExpansions.Information
{
	public class ActiveExpansions
	{
		public bool DoubleJumpAbility { get; set; } = true;

		public bool StartingXp { get; set; }

		public bool LivingBioAbility { get; set; }

		public bool PackConverter { get; set; } = true;

		public bool ToolAbility { get; set; } = true;
	}
	internal static class ExpJson
	{
		private static readonly JsonSerializerOptions _setting;

		static ExpJson()
		{
			_setting = new JsonSerializerOptions
			{
				ReadCommentHandling = JsonCommentHandling.Skip,
				IncludeFields = true,
				PropertyNameCaseInsensitive = true,
				WriteIndented = true,
				IgnoreReadOnlyProperties = true
			};
			_setting.Converters.Add(new JsonStringEnumConverter());
		}

		public static T? Deserialize<T>(string json)
		{
			return JsonSerializer.Deserialize<T>(json, _setting);
		}

		public static string Serialize<T>(T value)
		{
			return JsonSerializer.Serialize(value, _setting);
		}
	}
}
namespace XpExpansions.Information.StartingXp
{
	public class StartingXpData
	{
		public uint LevelLayoutData { get; set; }

		public int StartingXp { get; set; }

		public StartingXpData(uint levelLayoutData, int startingXp)
		{
			LevelLayoutData = levelLayoutData;
			StartingXp = startingXp;
		}
	}
}
namespace XpExpansions.Information.Explosion
{
	public class ExplosionAbilityData
	{
		public int LevelLayoutPersistentId { get; set; }

		public int UnlockAtLevel { get; set; }

		public ExplosionAbilityData(int levelLayoutPersistentId, int unlockAtLevel)
		{
			LevelLayoutPersistentId = levelLayoutPersistentId;
			UnlockAtLevel = unlockAtLevel;
		}
	}
}
namespace XpExpansions.Information.DoubleJump
{
	public sealed class DoubleJumpConfig
	{
		public bool DoubleJumpEnabled { get; set; } = true;

		public bool SuperJumpEnabled { get; set; } = true;

		public float SuperJumpVelocity { get; set; } = 3f;
	}
	internal class DoubleJumpData
	{
		public int LevelLayoutPersistentId { get; set; }

		public int UnlockAtLevel { get; set; }

		public DoubleJumpConfig? DoubleJumpConfig { get; set; }

		public DoubleJumpData(int levelLayoutPersistentId, int unlockAtLevel, DoubleJumpConfig? doubleJumpConfig)
		{
			LevelLayoutPersistentId = levelLayoutPersistentId;
			UnlockAtLevel = unlockAtLevel;
			DoubleJumpConfig = doubleJumpConfig;
		}
	}
}
namespace XpExpansions.Information.BioTrackerLocal
{
	internal class LocalBioTrackerData
	{
		public int LevelLayoutPersistentId { get; set; }

		public int UnlockAtLevel { get; set; }

		public LocalBioTrackerData(int levelLayoutPersistentId, int unlockAtLevel)
		{
			LevelLayoutPersistentId = levelLayoutPersistentId;
			UnlockAtLevel = unlockAtLevel;
		}
	}
}
namespace XpExpansions.Extensions
{
	public static class CacheApiWrapper
	{
		internal static string ExtensionCacheName = "XpExtensions";

		private const string _folderPath = "FolderPath";

		public static void SetFolderPath(string path)
		{
			CacheApi.SaveInformation((object)"FolderPath", (object)path, ExtensionCacheName);
		}

		public static string GetFolderPath()
		{
			return CacheApi.GetInformation<string>((object)"FolderPath", ExtensionCacheName);
		}
	}
}

GTFuckingXP.dll

Decompiled 2 days ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using CellMenu;
using EndskApi.Api;
using EndskApi.Enums.Menus;
using EndskApi.Information.EnemyKill;
using EndskApi.Information.Menus;
using EndskApi.Manager;
using EndskApi.Scripts;
using Enemies;
using FloatingTextAPI;
using GTFO.API;
using GTFuckingXP.Communication;
using GTFuckingXP.Dependencies;
using GTFuckingXP.Enums;
using GTFuckingXP.Extensions;
using GTFuckingXP.Extensions.Information;
using GTFuckingXP.Extensions.Information.Level.Json;
using GTFuckingXP.Information;
using GTFuckingXP.Information.ClassSelector;
using GTFuckingXP.Information.Enemies;
using GTFuckingXP.Information.Level;
using GTFuckingXP.Information.NetworkingInfo;
using GTFuckingXP.Managers;
using GTFuckingXP.Patches;
using GTFuckingXP.Patches.SelectLevelPatches;
using GTFuckingXP.Scripts;
using GTFuckingXp.Managers;
using GTFuckingXp.Patches;
using GameData;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Localization;
using MTFO.API;
using MTFO.Ext.PartialData;
using Microsoft.CodeAnalysis;
using ModifierAPI;
using Player;
using SNetwork;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GTFuckingXP")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+git33620c7-dirty-master.33620c7e9766136dea115db87926bb0ec5e6969c")]
[assembly: AssemblyProduct("GTFuckingXP")]
[assembly: AssemblyTitle("GTFuckingXP")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
}
namespace GTFuckingXp.Patches
{
	[HarmonyPatch(typeof(Dam_EnemyDamageLimb))]
	public static class EnemyDamageLimbPatches
	{
		[HarmonyPatch("MeleeDamage")]
		[HarmonyPrefix]
		public static void MeleePrefix(Dam_EnemyDamageLimb __instance, ref float dam, Agent sourceAgent)
		{
			if (((Agent)__instance.m_base.Owner).Alive && (Object)(object)sourceAgent != (Object)null && sourceAgent.IsLocallyOwned)
			{
				float num = dam;
				LogManager.Debug($"Melee damage from local player registered. {num} was scaled up to:");
				num *= CacheApiWrapper.GetActiveLevel().MeleeDamageMultiplier;
				LogManager.Debug($"{num}");
				dam = num;
			}
		}

		[HarmonyPatch("BulletDamage")]
		[HarmonyPrefix]
		public static void BulletPostfix(Dam_EnemyDamageLimb __instance, ref float dam, Agent sourceAgent)
		{
			if (((Agent)__instance.m_base.Owner).Alive && (Object)(object)sourceAgent != (Object)null && sourceAgent.IsLocallyOwned && !SentryGunCheckPatches.SentryShot)
			{
				float num = dam;
				LogManager.Debug($"Bullet damage from local player registered. {num} was scaled to:");
				num *= CacheApiWrapper.GetActiveLevel().WeaponDamageMultiplier;
				LogManager.Debug($"{num}");
				dam = num;
			}
		}
	}
	[HarmonyPatch]
	internal static class PlayerDamagePatches
	{
		[HarmonyPatch(typeof(Dam_PlayerDamageLimb), "BulletDamage")]
		[HarmonyPrefix]
		private static void Prefix_BulletDamage(Dam_PlayerDamageLimb __instance, ref float dam, Agent sourceAgent)
		{
			PlayerAgent owner = __instance.m_base.Owner;
			if (((Agent)owner).Alive)
			{
				if (CacheApiWrapper.TryGetActiveLevel(owner, out Level level) && level.CustomScaling.TryGetValue(CustomScaling.BulletResistance, out var value))
				{
					dam *= 2f - value;
				}
				if (!SentryGunCheckPatches.SentryShot && (Object)(object)sourceAgent != (Object)null && sourceAgent.IsLocallyOwned)
				{
					float num = dam;
					LogManager.Debug($"Bullet damage from local player registered. {num} was scaled up to:");
					num *= CacheApiWrapper.GetActiveLevel().WeaponDamageMultiplier;
					LogManager.Debug($"{num}");
					dam = num;
				}
			}
		}

		[HarmonyPatch(typeof(Dam_SyncedDamageBase), "FireDamage")]
		[HarmonyPrefix]
		private static void Prefix_FireDamage(Dam_SyncedDamageBase __instance, ref float dam)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__instance.DamageBaseOwner == 0)
			{
				PlayerAgent val = ((Il2CppObjectBase)__instance.GetBaseAgent()).Cast<PlayerAgent>();
				if (((Agent)val).Alive && ((Agent)val).IsLocallyOwned && CacheApiWrapper.GetActiveLevel().CustomScaling.TryGetValue(CustomScaling.BleedResistance, out var value))
				{
					dam *= 2f - value;
				}
			}
		}

		[HarmonyPatch(typeof(Dam_SyncedDamageBase), "ExplosionDamage")]
		[HarmonyPrefix]
		private static void Prefix_ExplosionDamage(Dam_SyncedDamageBase __instance, ref float dam)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__instance.DamageBaseOwner == 0 && CacheApiWrapper.TryGetActiveLevel(((Il2CppObjectBase)__instance.GetBaseAgent()).Cast<PlayerAgent>(), out Level level) && level.CustomScaling.TryGetValue(CustomScaling.ExplosionResistance, out var value))
			{
				dam *= 2f - value;
			}
		}
	}
	[HarmonyPatch(typeof(Dam_PlayerDamageBase))]
	internal static class PlayerRegenPatches
	{
		[HarmonyPatch("OnIncomingDamage")]
		[HarmonyPostfix]
		private static void Postfix_OnDamage(Dam_PlayerDamageBase __instance)
		{
			PlayerAgent owner = __instance.Owner;
			if (CacheApiWrapper.TryGetActiveLevel(owner, out Level level) && level.CustomScaling.TryGetValue(CustomScaling.RegenStartDelayMultiplier, out var value))
			{
				__instance.m_nextRegen = Clock.Time + owner.PlayerData.healthRegenStartDelayAfterDamage * value;
			}
		}
	}
	[HarmonyPatch(typeof(BulletWeapon))]
	internal static class SentryGunCheckPatches
	{
		internal static bool SentryShot { get; private set; }

		[HarmonyPatch("BulletHit")]
		[HarmonyBefore(new string[] { "Dinorush.ExtraWeaponCustomization" })]
		[HarmonyPrefix]
		private static void Prefix_BulletHit(ref WeaponHitData weaponRayData, bool allowDirectionalBonus)
		{
			if (!allowDirectionalBonus || weaponRayData.vfxBulletHit != null)
			{
				SentryShot = true;
			}
		}

		[HarmonyPatch("BulletHit")]
		[HarmonyPostfix]
		private static void Postfix_BulletHit()
		{
			SentryShot = false;
		}
	}
}
namespace GTFuckingXp.Managers
{
	public static class EnemyKillManager
	{
		public static void Setup()
		{
			EnemyKillApi.AddEnemyKilledCallback((Action<EnemyKillDistribution>)EnemyKilled);
		}

		public static void EnemyKilled(EnemyKillDistribution info)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)info.LastHitDealtBy == (Object)null)
			{
				GiveXpToEveryone(info.KilledEnemyAgent);
				return;
			}
			EnemyXp enemyXp = GetEnemyXp(info.KilledEnemyAgent);
			Vector3 position = info.KilledEnemyAgent.Position;
			position.y += 1f;
			Enumerator<SNet_Player> enumerator = SNet.SessionHub.PlayersInSession.GetEnumerator();
			XpHandler xpHandler = default(XpHandler);
			while (enumerator.MoveNext())
			{
				SNet_Player current = enumerator.Current;
				if (!((Object)(object)current != (Object)null) || current.IsBot)
				{
					continue;
				}
				if (info.LastHitDealtBy.Owner.PlayerSlot.index == current.PlayerSlot.index)
				{
					if (current.IsLocal)
					{
						if (CacheApi.TryGetInstance<XpHandler>(ref xpHandler, "GTF_XP", true))
						{
							PlayerReviveManager.AddXP(current.Lookup, ((IXpData)enemyXp).GetXp(isDebuff: false));
							xpHandler.AddXp(enemyXp, position);
						}
					}
					else
					{
						NetworkApiXpManager.SendReceiveXp(current, enemyXp, position, forceDebuffXp: false);
					}
					continue;
				}
				float damageDealtBySnet = info.GetDamageDealtBySnet(current);
				float healthMax = ((Dam_SyncedDamageBase)info.KilledEnemyAgent.Damage).HealthMax;
				float num = damageDealtBySnet / healthMax;
				bool flag = info.DidSnetBiotag(current);
				if (flag)
				{
					float biotagXpFrac = enemyXp.BiotagXpFrac;
					if (biotagXpFrac < 0f)
					{
						biotagXpFrac = CacheApiWrapper.GetGlobalValues().BiotagXpFrac;
					}
					num = Math.Max(num, biotagXpFrac);
					flag = biotagXpFrac > 0f;
				}
				if (damageDealtBySnet > 0.5f || flag)
				{
					LogManager.Debug($"percentageDealt = {num}, damageDealt = {damageDealtBySnet}");
					NetworkApiXpManager.SendStaticXpInfo(current, (int)((float)enemyXp.XpGain * num), (int)((float)enemyXp.DebuffXp * num), (int)((float)enemyXp.LevelScalingXpDecrese * num), position);
				}
			}
		}

		private static void GiveXpToEveryone(EnemyAgent killedEnemy)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			EnemyXp enemyXp = GetEnemyXp(killedEnemy);
			Vector3 position = killedEnemy.Position;
			position.y += 1f;
			XpHandler xpHandler = default(XpHandler);
			if (CacheApi.TryGetInstance<XpHandler>(ref xpHandler, "GTF_XP", true))
			{
				xpHandler.AddXp(enemyXp, position, forceDebuffXp: true, "<#F30>");
			}
			NetworkApiXpManager.SendHalfAssedXp(enemyXp, position, forceDebuffXp: true);
		}

		private static EnemyXp GetEnemyXp(EnemyAgent killedEnemy)
		{
			List<EnemyXp> instance = CacheApi.GetInstance<List<EnemyXp>>("GTF_XP");
			EnemyXp enemyXp = instance.FirstOrDefault((EnemyXp it) => it.EnemyId == killedEnemy.EnemyDataID);
			if (enemyXp == null)
			{
				LogManager.Warn($"There was no enemy XP data found for {killedEnemy.EnemyDataID}!");
				enemyXp = new EnemyXp(killedEnemy.EnemyDataID, ((Object)killedEnemy).name, 0, 0, 0);
				instance.Add(enemyXp);
				CacheApi.SaveInstance<List<EnemyXp>>(instance, "GTF_XP");
			}
			LogManager.Debug($"Enemy kill was registered. Enemy XpData was {enemyXp.XpGain}.");
			return enemyXp;
		}
	}
}
namespace GTFuckingXp.Information
{
	public class DefaultConstants
	{
		public const string DoubleJumpExpansion = "[\r\n  {\r\n    \"LevelLayoutPersistentId\": 13,\r\n    \"UnlockAtLevel\": 10,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 14,\r\n    \"UnlockAtLevel\": 6,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 7,\r\n    \"UnlockAtLevel\": 5,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 8,\r\n    \"UnlockAtLevel\": 5,\r\n    \"DoubleJumpConfig\": null\r\n  },\r\n  {\r\n    \"LevelLayoutPersistentId\": 15,\r\n    \"UnlockAtLevel\": 5,\r\n    \"DoubleJumpConfig\": null\r\n  }\r\n]";

		public const string ExpansionsActive = "\r\n{\r\n    \"ExplosionAbility\": false,\r\n    \"DoubleJumpAbility\": true\r\n}\r\n";

		public const string BoosterEffects = "\r\n[\r\n  {\r\n    \"ClassLayoutPersistentId\": 2,\r\n    \"ActiveLevels\": [\r\n      10\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 1.35\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.03,\r\n      \"ProjectileResistance\": 1.03,\r\n      \"InfectionResistance\": 1.03\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.06,\r\n      \"ProjectileResistance\": 1.06,\r\n      \"InfectionResistance\": 1.06\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.09,\r\n      \"ProjectileResistance\": 1.09,\r\n      \"InfectionResistance\": 1.09\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.12,\r\n      \"ProjectileResistance\": 1.12,\r\n      \"InfectionResistance\": 1.12\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.15,\r\n      \"ProjectileResistance\": 1.15,\r\n      \"InfectionResistance\": 1.15\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      6\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.18,\r\n      \"ProjectileResistance\": 1.18,\r\n      \"InfectionResistance\": 1.18\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      7\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.21,\r\n      \"ProjectileResistance\": 1.21,\r\n      \"InfectionResistance\": 1.21\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      8\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.24,\r\n      \"ProjectileResistance\": 1.24,\r\n      \"InfectionResistance\": 1.24\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      9\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.27,\r\n      \"ProjectileResistance\": 1.27,\r\n      \"InfectionResistance\": 1.27\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      10\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.3,\r\n      \"ProjectileResistance\": 1.3,\r\n      \"InfectionResistance\": 1.3\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      11\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.33,\r\n      \"ProjectileResistance\": 1.33,\r\n      \"InfectionResistance\": 1.33\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      12\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.36,\r\n      \"ProjectileResistance\": 1.36,\r\n      \"InfectionResistance\": 1.36\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      13\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.39,\r\n      \"ProjectileResistance\": 1.39,\r\n      \"InfectionResistance\": 1.39\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      14\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.42,\r\n      \"ProjectileResistance\": 1.42,\r\n      \"InfectionResistance\": 1.42\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 3,\r\n    \"ActiveLevels\": [\r\n      15\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.45,\r\n      \"ProjectileResistance\": 1.45,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 4,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 1.35,\r\n      \"ReviveSpeedSupport\": 1.25\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 4,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 1.7,\r\n      \"ReviveSpeedSupport\": 1.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 4,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.05,\r\n      \"ReviveSpeedSupport\": 1.75\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 4,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.40,\r\n      \"ReviveSpeedSupport\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 4,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.75,\r\n      \"ReviveSpeedSupport\": 2.25,\r\n      \"MeleeResistance\": 1.15,\r\n      \"ProjectileResistance\": 1.15\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 15,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 12,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 1.35,\r\n      \"ReviveSpeedSupport\": 1.1,\r\n      \"MeleeResistance\": 1.04,\r\n      \"ProjectileResistance\": 1.04,\r\n      \"InfectionResistance\": 1.05\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 12,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 1.7,\r\n      \"ReviveSpeedSupport\": 1.2,\r\n      \"MeleeResistance\": 1.08,\r\n      \"ProjectileResistance\": 1.08,\r\n      \"InfectionResistance\": 1.1\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 12,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.05,\r\n      \"ReviveSpeedSupport\": 1.3,\r\n      \"MeleeResistance\": 1.12,\r\n      \"ProjectileResistance\": 1.12,\r\n      \"InfectionResistance\": 1.15\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 12,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.40,\r\n      \"ReviveSpeedSupport\": 1.4,\r\n      \"MeleeResistance\": 1.16,\r\n      \"ProjectileResistance\": 1.16,\r\n      \"InfectionResistance\": 1.2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 12,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.75,\r\n      \"ReviveSpeedSupport\": 1.5,\r\n      \"MeleeResistance\": 1.2,\r\n      \"ProjectileResistance\": 1.2,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 5,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.55,\r\n      \"ScannerRechargeSpeed\": 1.15,\r\n      \"SentryGunDamage\": 1.15,\r\n      \"GlueEfficiency\": 1.15,\r\n      \"TripMineDamage\": 1.15,\r\n      \"ComputerProcessingSpeed\": 1.2,\r\n      \"FogRepellerEffect\": 1.2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 5,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 2.1,\r\n      \"ScannerRechargeSpeed\": 1.3,\r\n      \"SentryGunDamage\": 1.3,\r\n      \"GlueEfficiency\": 1.3,\r\n      \"TripMineDamage\": 1.3,\r\n      \"ComputerProcessingSpeed\": 1.4,\r\n      \"FogRepellerEffect\": 1.4\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 5,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 2.65,\r\n      \"ScannerRechargeSpeed\": 1.45,\r\n      \"SentryGunDamage\": 1.45,\r\n      \"GlueEfficiency\": 1.45,\r\n      \"TripMineDamage\": 1.45,\r\n      \"ComputerProcessingSpeed\": 1.6,\r\n      \"FogRepellerEffect\": 1.6\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 5,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 3.2,\r\n      \"ScannerRechargeSpeed\": 1.6,\r\n      \"SentryGunDamage\": 1.6,\r\n      \"GlueEfficiency\": 1.6,\r\n      \"TripMineDamage\": 1.6,\r\n      \"ComputerProcessingSpeed\": 1.8,\r\n      \"FogRepellerEffect\": 1.8\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 5,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 999.0,\r\n      \"ScannerRechargeSpeed\": 1.8,\r\n      \"SentryGunDamage\": 1.75,\r\n      \"GlueEfficiency\": 1.75,\r\n      \"TripMineDamage\": 1.75,\r\n      \"ComputerProcessingSpeed\": 999.0,\r\n      \"FogRepellerEffect\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 6,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.5,\r\n      \"ProjectileResistance\": 0.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 6,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 1.5,\r\n      \"MeleeResistance\": 0.46,\r\n      \"ProjectileResistance\": 0.46\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 6,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.0,\r\n      \"MeleeResistance\": 0.42,\r\n      \"ProjectileResistance\": 0.42\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 6,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 2.5,\r\n      \"MeleeResistance\": 0.38,\r\n      \"ProjectileResistance\": 0.38\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 6,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 3.0,\r\n      \"MeleeResistance\": 0.34,\r\n      \"ProjectileResistance\": 0.34\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 6,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"RegenerationSpeed\": 3.5,\r\n      \"MeleeResistance\": 0.3,\r\n      \"ProjectileResistance\": 0.3\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 7,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.04,\r\n      \"ProjectileResistance\": 1.04\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 7,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.08,\r\n      \"ProjectileResistance\": 1.08\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 7,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.12,\r\n      \"ProjectileResistance\": 1.12\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 7,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.16,\r\n      \"ProjectileResistance\": 1.16\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 7,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.2,\r\n      \"ProjectileResistance\": 1.2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 8,\r\n    \"ActiveLevels\": [\r\n      0\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.55,\r\n      \"ProjectileResistance\": 0.55\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 8,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.6,\r\n      \"ProjectileResistance\": 0.6\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 8,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.65,\r\n      \"ProjectileResistance\": 0.65\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 8,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.7,\r\n      \"ProjectileResistance\": 0.7\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 8,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.75,\r\n      \"ProjectileResistance\": 0.75\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 8,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.8,\r\n      \"ProjectileResistance\": 0.8\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      0\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.6,\r\n      \"ProjectileResistance\": 0.6\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.63,\r\n      \"ProjectileResistance\": 0.63\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.66,\r\n      \"ProjectileResistance\": 0.66\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.69,\r\n      \"ProjectileResistance\": 0.69\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.72,\r\n      \"ProjectileResistance\": 0.72\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.75,\r\n      \"ProjectileResistance\": 0.75\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      6\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.78,\r\n      \"ProjectileResistance\": 0.78\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      7\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.81,\r\n      \"ProjectileResistance\": 0.81\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      8\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.84,\r\n      \"ProjectileResistance\": 0.84\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      9\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.87,\r\n      \"ProjectileResistance\": 0.87\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 9,\r\n    \"ActiveLevels\": [\r\n      10\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 0.9,\r\n      \"ProjectileResistance\": 0.9\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.02,\r\n      \"ProjectileResistance\": 1.05,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.04,\r\n      \"ProjectileResistance\": 1.1,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.06,\r\n      \"ProjectileResistance\": 1.15,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.08,\r\n      \"ProjectileResistance\": 1.2,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.10,\r\n      \"ProjectileResistance\": 1.25,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      6\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.12,\r\n      \"ProjectileResistance\": 1.3,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      7\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.14,\r\n      \"ProjectileResistance\": 1.35,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      8\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.16,\r\n      \"ProjectileResistance\": 1.4,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      9\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.18,\r\n      \"ProjectileResistance\": 1.45,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      10\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.2,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      11\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.22,\r\n      \"ProjectileResistance\": 1.55,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      12\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.24,\r\n      \"ProjectileResistance\": 1.6,\r\n      \"InfectionResistance\": 2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      13\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.26,\r\n      \"ProjectileResistance\": 1.65,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      14\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.28,\r\n      \"ProjectileResistance\": 1.7,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 11,\r\n    \"ActiveLevels\": [\r\n      15\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.3,\r\n      \"ProjectileResistance\": 1.75,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 16,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"ScannerRechargeSpeed\": 1.15,\r\n      \"SentryGunDamage\": 1.15,\r\n      \"GlueEfficiency\": 1.15,\r\n      \"TripMineDamage\": 1.15,\r\n      \"FogRepellerEffect\": 1.6,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 16,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"ScannerRechargeSpeed\": 1.3,\r\n      \"SentryGunDamage\": 1.3,\r\n      \"GlueEfficiency\": 1.3,\r\n      \"TripMineDamage\": 1.3,\r\n      \"FogRepellerEffect\": 2.2,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 16,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"ScannerRechargeSpeed\": 1.45,\r\n      \"SentryGunDamage\": 1.45,\r\n      \"GlueEfficiency\": 1.45,\r\n      \"TripMineDamage\": 1.45,\r\n      \"FogRepellerEffect\": 2.8,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 16,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"ScannerRechargeSpeed\": 1.6,\r\n      \"SentryGunDamage\": 1.6,\r\n      \"GlueEfficiency\": 1.6,\r\n      \"TripMineDamage\": 1.6,\r\n      \"FogRepellerEffect\": 3.4,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 16,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"ScannerRechargeSpeed\": 1.15,\r\n      \"SentryGunDamage\": 1.75,\r\n      \"GlueEfficiency\": 1.75,\r\n      \"TripMineDamage\": 1.75,\r\n      \"FogRepellerEffect\": 15.0,\r\n      \"InfectionResistance\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      1\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.1,\r\n      \"ScannerRechargeSpeed\": 1.05,\r\n      \"SentryGunDamage\": 1.05,\r\n      \"GlueEfficiency\": 1.05,\r\n      \"TripMineDamage\": 1.05,\r\n      \"ComputerProcessingSpeed\": 1.05,\r\n      \"FogRepellerEffect\": 1.05,\r\n      \"MeleeResistance\": 1.02,\r\n      \"ProjectileResistance\": 1.02,\r\n      \"InfectionResistance\": 1.02\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      2\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.2,\r\n      \"ScannerRechargeSpeed\": 1.1,\r\n      \"SentryGunDamage\": 1.1,\r\n      \"GlueEfficiency\": 1.1,\r\n      \"TripMineDamage\": 1.1,\r\n      \"ComputerProcessingSpeed\": 1.1,\r\n      \"FogRepellerEffect\": 1.1,\r\n      \"MeleeResistance\": 1.04,\r\n      \"ProjectileResistance\": 1.04,\r\n      \"InfectionResistance\": 1.04\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.3,\r\n      \"ScannerRechargeSpeed\": 1.15,\r\n      \"SentryGunDamage\": 1.15,\r\n      \"GlueEfficiency\": 1.15,\r\n      \"TripMineDamage\": 1.15,\r\n      \"ComputerProcessingSpeed\": 1.15,\r\n      \"FogRepellerEffect\": 1.15,\r\n      \"MeleeResistance\": 1.06,\r\n      \"ProjectileResistance\": 1.06,\r\n      \"InfectionResistance\": 1.06\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.4,\r\n      \"ScannerRechargeSpeed\": 1.2,\r\n      \"SentryGunDamage\": 1.2,\r\n      \"GlueEfficiency\": 1.2,\r\n      \"TripMineDamage\": 1.2,\r\n      \"ComputerProcessingSpeed\": 1.2,\r\n      \"FogRepellerEffect\": 1.2,\r\n      \"MeleeResistance\": 1.08,\r\n      \"ProjectileResistance\": 1.08,\r\n      \"InfectionResistance\": 1.08\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.5,\r\n      \"ScannerRechargeSpeed\": 1.25,\r\n      \"SentryGunDamage\": 1.25,\r\n      \"GlueEfficiency\": 1.25,\r\n      \"TripMineDamage\": 1.25,\r\n      \"ComputerProcessingSpeed\": 1.25,\r\n      \"FogRepellerEffect\": 1.25,\r\n      \"MeleeResistance\": 1.1,\r\n      \"ProjectileResistance\": 1.1,\r\n      \"InfectionResistance\": 1.1\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      6\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.6,\r\n      \"ScannerRechargeSpeed\": 1.3,\r\n      \"SentryGunDamage\": 1.3,\r\n      \"GlueEfficiency\": 1.3,\r\n      \"TripMineDamage\": 1.3,\r\n      \"ComputerProcessingSpeed\": 1.3,\r\n      \"FogRepellerEffect\": 1.3,\r\n      \"MeleeResistance\": 1.12,\r\n      \"ProjectileResistance\": 1.12,\r\n      \"InfectionResistance\": 1.12\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      7\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.7,\r\n      \"ScannerRechargeSpeed\": 1.35,\r\n      \"SentryGunDamage\": 1.35,\r\n      \"GlueEfficiency\": 1.35,\r\n      \"TripMineDamage\": 1.35,\r\n      \"ComputerProcessingSpeed\": 1.35,\r\n      \"FogRepellerEffect\": 1.35,\r\n      \"MeleeResistance\": 1.14,\r\n      \"ProjectileResistance\": 1.14,\r\n      \"InfectionResistance\": 1.14\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      8\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.8,\r\n      \"ScannerRechargeSpeed\": 1.4,\r\n      \"SentryGunDamage\": 1.4,\r\n      \"GlueEfficiency\": 1.4,\r\n      \"TripMineDamage\": 1.4,\r\n      \"ComputerProcessingSpeed\": 1.4,\r\n      \"FogRepellerEffect\": 1.4,\r\n      \"MeleeResistance\": 1.16,\r\n      \"ProjectileResistance\": 1.16,\r\n      \"InfectionResistance\": 1.16\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      9\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 1.9,\r\n      \"ScannerRechargeSpeed\": 1.45,\r\n      \"SentryGunDamage\": 1.45,\r\n      \"GlueEfficiency\": 1.45,\r\n      \"TripMineDamage\": 1.45,\r\n      \"ComputerProcessingSpeed\": 1.45,\r\n      \"FogRepellerEffect\": 1.45,\r\n      \"MeleeResistance\": 1.18,\r\n      \"ProjectileResistance\": 1.18,\r\n      \"InfectionResistance\": 1.18\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 13,\r\n    \"ActiveLevels\": [\r\n      10\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"HackingProficiency\": 2.0,\r\n      \"ScannerRechargeSpeed\": 1.5,\r\n      \"SentryGunDamage\": 1.5,\r\n      \"GlueEfficiency\": 1.5,\r\n      \"TripMineDamage\": 1.5,\r\n      \"ComputerProcessingSpeed\": 1.5,\r\n      \"FogRepellerEffect\": 1.5,\r\n      \"MeleeResistance\": 1.2,\r\n      \"ProjectileResistance\": 1.2,\r\n      \"InfectionResistance\": 1.2\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      3\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 1.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      4\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 1.5,\r\n      \"RegenerationSpeed\": 2.0,\r\n      \"RegenerationCap\": 2.0\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      5\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 1.5,\r\n      \"RegenerationSpeed\": 2.0,\r\n      \"RegenerationCap\": 2.0,\r\n      \"ComputerProcessingSpeed\": 999,\r\n      \"HackingProficiency\": 999.0,\r\n      \"ScannerRechargeSpeed\": 1.5,\r\n      \"SentryGunDamage\": 1.5,\r\n      \"GlueEfficiency\": 1.5,\r\n      \"TripMineDamage\": 1.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      6\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 1.5,\r\n      \"RegenerationSpeed\": 2.0,\r\n      \"RegenerationCap\": 2.0,\r\n      \"ComputerProcessingSpeed\": 999,\r\n      \"HackingProficiency\": 999.0,\r\n      \"ScannerRechargeSpeed\": 1.5,\r\n      \"SentryGunDamage\": 1.5,\r\n      \"GlueEfficiency\": 1.5,\r\n      \"TripMineDamage\": 1.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      7\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 1.5,\r\n      \"RegenerationSpeed\": 2.0,\r\n      \"RegenerationCap\": 2.0,\r\n      \"ComputerProcessingSpeed\": 999,\r\n      \"HackingProficiency\": 999.0,\r\n      \"ScannerRechargeSpeed\": 1.5,\r\n      \"SentryGunDamage\": 1.5,\r\n      \"GlueEfficiency\": 1.5,\r\n      \"TripMineDamage\": 1.5,\r\n      \"BioscanSpeed\": 1.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      8\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 1.5,\r\n      \"RegenerationSpeed\": 2.0,\r\n      \"RegenerationCap\": 2.0,\r\n      \"ComputerProcessingSpeed\": 999,\r\n      \"HackingProficiency\": 999.0,\r\n      \"ScannerRechargeSpeed\": 1.5,\r\n      \"SentryGunDamage\": 1.5,\r\n      \"GlueEfficiency\": 1.5,\r\n      \"TripMineDamage\": 1.5,\r\n      \"BioscanSpeed\": 1.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      9\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 2.0,\r\n      \"RegenerationSpeed\": 2.0,\r\n      \"RegenerationCap\": 2.0,\r\n      \"ComputerProcessingSpeed\": 999,\r\n      \"HackingProficiency\": 999.0,\r\n      \"ScannerRechargeSpeed\": 1.5,\r\n      \"SentryGunDamage\": 1.5,\r\n      \"GlueEfficiency\": 1.5,\r\n      \"TripMineDamage\": 1.5,\r\n      \"BioscanSpeed\": 1.5\r\n    }\r\n  },\r\n  {\r\n    \"ClassLayoutPersistentId\": 14,\r\n    \"ActiveLevels\": [\r\n      10\r\n    ],\r\n    \"ValueToBoosterEffects\": {\r\n      \"MeleeResistance\": 1.5,\r\n      \"ProjectileResistance\": 1.5,\r\n      \"InfectionResistance\": 2.0,\r\n      \"RegenerationSpeed\": 3.5,\r\n      \"RegenerationCap\": 2.0,\r\n      \"ComputerProcessingSpeed\": 999,\r\n      \"HackingProficiency\": 999.0,\r\n      \"ScannerRechargeSpeed\": 1.5,\r\n      \"SentryGunDamage\": 1.5,\r\n      \"GlueEfficiency\": 1.5,\r\n      \"TripMineDamage\": 1.5,\r\n      \"BioscanSpeed\": 1.5\r\n    }\r\n  }\r\n]\r\n";

		public const string Groups = "\r\n[\r\n  {\r\n    \"PersistentId\": 0,\r\n    \"VisibleForPlayerCount\": [\r\n      1,\r\n      2,\r\n      3,\r\n      4\r\n    ],\r\n    \"Name\": \"Combat\"\r\n  },\r\n  {\r\n    \"PersistentId\": 1,\r\n    \"VisibleForPlayerCount\": [\r\n      1,\r\n      2,\r\n      3,\r\n      4\r\n    ],\r\n    \"Name\": \"Survival\"\r\n  },\r\n  {\r\n    \"PersistentId\": 2,\r\n    \"VisibleForPlayerCount\": [\r\n      1,\r\n      2,\r\n      3,\r\n      4\r\n    ],\r\n    \"Name\": \"Utility\"\r\n  },\r\n  {\r\n    \"PersistentId\": 3,\r\n    \"VisibleForPlayerCount\": [\r\n      1\r\n    ],\r\n    \"Name\": \"Solo\"\r\n  }\r\n]\r\n";

		public const string ClassLayouts = "\r\n[\r\n  {\r\n    \"Header\": \"Generalist\",\r\n    \"GroupPersistentId\": 2,\r\n    \"PersistentId\": 13,\r\n    \"InfoText\": \"Good at everything, best at nothing.\\nMax LV 10 Bonus: Double Jump\\n\\nBonuses Each LV up:\\n+2% Damage\\n+2% Armor\\n+2% Infection Resist\\n+10% Hack Skill\\n-5% Terminal Delay\\n+5% Tool Power\\n+5% Repeller Power\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\\n1% Speed\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 100% -> 102%\\nArmor 100% -> 102%\\nInfect Res. 0% -> 2%\\nHacking 100% - > 110%\\nTerminal Delay 100% -> 95%\\nTool Power 100% -> 105%\\nRepeller 100% -> 105%\\nSpeed 100% -> 101%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.0,\r\n        \"WeaponDamageMultiplier\": 1.0,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 300,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 102% -> 104%\\nArmor 102% -> 104%\\nInfect Res. 2% -> 4%\\nHacking 110% - > 120%\\nTerminal Delay 95% -> 90%\\nTool Power 105% -> 110%\\nRepeller 105% -> 110%\\nSpeed 101% -> 102%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.02,\r\n        \"WeaponDamageMultiplier\": 1.02,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.01\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 800,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 104% -> 106%\\nArmor 104% -> 106%\\nInfect Res. 4% -> 6%\\nHacking 120% - > 130%\\nTerminal Delay 90% -> 85%\\nTool Power 110% -> 115%\\nRepeller 110% -> 115%\\nSpeed 102% -> 103%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.04,\r\n        \"WeaponDamageMultiplier\": 1.04,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.02\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 1450,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 106% -> 108%\\nArmor 106% -> 108%\\nInfect Res. 6% -> 8%\\nHacking 130% - > 140%\\nTerminal Delay 85% -> 80%\\nTool Power 115% -> 120%\\nRepeller 115% -> 120%\\nSpeed 103% -> 104%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.06,\r\n        \"WeaponDamageMultiplier\": 1.06,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.03\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 2200,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 108% -> 110%\\nArmor 108% -> 110%\\nInfect Res. 8% -> 10%\\nHacking 140% - > 150%\\nTerminal Delay 80% -> 75%\\nTool Power 120% > 125%\\nRepeller 120% -> 125%\\nSpeed 104% -> 105%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.08,\r\n        \"WeaponDamageMultiplier\": 1.08,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.04\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 3025,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 110% -> 112%\\nArmor 110% -> 112%\\nInfect Res. 10% -> 12%\\nHacking 150% -> 160%\\nTerminal Delay 75% -> 70%\\nTool Power 125% -> 130%\\nRepeller 125% -> 130%\\nSpeed 105% -> 106%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.1,\r\n        \"WeaponDamageMultiplier\": 1.1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.05\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 6,\r\n        \"TotalXpRequired\": 3975,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 112% -> 114%\\nArmor 112% -> 114%\\nInfect Res. 12% -> 14%\\nHacking 160% -> 170%\\nTerminal Delay 70% -> 65%\\nTool Power 130% -> 135%\\nRepeller 130% -> 135%\\nSpeed 106% -> 107%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.12,\r\n        \"WeaponDamageMultiplier\": 1.12,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.06\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 7,\r\n        \"TotalXpRequired\": 5100,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 114% -> 116%\\nArmor 114% -> 116%\\nInfect Res. 14% -> 16%\\nHacking 170% -> 180%\\nTerminal Delay 65% -> 60%\\nTool Power 135% -> 140%\\nRepeller 135% -> 140%\\nSpeed 107% -> 108%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.14,\r\n        \"WeaponDamageMultiplier\": 1.14,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.07\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 8,\r\n        \"TotalXpRequired\": 6300,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 116% -> 118%\\nArmor 116% -> 118%\\nInfect Res. 16% -> 18%\\nHacking 180% -> 190%\\nTerminal Delay 60% -> 55%\\nTool Power 140% -> 145%\\nRepeller 140% -> 145%\\nSpeed 108% -> 109%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.16,\r\n        \"WeaponDamageMultiplier\": 1.16,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.08\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 9,\r\n        \"TotalXpRequired\": 7575,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 118% -> 120%\\nArmor 118% -> 120%\\nInfect Res. 18% -> 20%\\nHacking 190% -> 200%\\nTerminal Delay 55% -> 50%\\nTool Power 145% -> 150%\\nRepeller 145% -> 150%\\nSpeed 109% -> 110%\\nJump -> Double Jump\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.18,\r\n        \"WeaponDamageMultiplier\": 1.18,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.09\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 10,\r\n        \"TotalXpRequired\": 8925,\r\n        \"CustomLevelUpPopupText\": \"MAX LV!\\n+Double Jump\\n2% Ammo Refill\\n2% Tool Refill\\n4% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Generalist\\n{0}\\nDamage 120%\\nArmor 120%\\nInfect Res. 20%\\nHacking 200%\\nTerminal Delay 50%\\nTool Power 150%\\nRepeller 150%\\nSpeed 110%\\nDouble Jump\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.2,\r\n        \"WeaponDamageMultiplier\": 1.2,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.1\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionTool\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.02\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.02\r\n          }\r\n        ]\r\n      }\r\n    ]\r\n  },\r\n  {\r\n    \"Header\": \"Soldier\",\r\n    \"GroupPersistentId\": 0,\r\n    \"PersistentId\": 2,\r\n    \"InfoText\": \"Specialized in ranged combat. Stronger guns with ammo refunds on each level up.\\nMax LV 10 bonus: +35% HP Regen Speed\\n\\nBonuses Each LV up:\\n+4% Gun Damage\\n+4% Ammo Refill\\n\\nBonus Each 5 LVs:\\n+6% Ammo Refill\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 100% -> 104%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 100,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 104% -> 108%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.04,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 108% -> 112%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.08,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 1200,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 112% -> 116%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.12,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 1900,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 116% -> 120%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.16,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 2700,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n10% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 120% -> 124%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.2,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.1\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 6,\r\n        \"TotalXpRequired\": 3600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 124% -> 128%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.24,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 7,\r\n        \"TotalXpRequired\": 4600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 128% -> 132%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.28,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 8,\r\n        \"TotalXpRequired\": 5700,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 132% -> 136%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.32,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 9,\r\n        \"TotalXpRequired\": 6900,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +4%\\n4% Ammo Refill\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 136% -> 140%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.36,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.04\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.04\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 10,\r\n        \"TotalXpRequired\": 8200,\r\n        \"CustomLevelUpPopupText\": \"MAX LV!\\nGun Damage +4%\\n10% Ammo Refill\\nRegen Speed +35%\",\r\n        \"CustomLevelStatsText\": \"Class: Soldier\\n{0}\\nGun Damage 140%\\nRegen Speed 135%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.4,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"AmmunitionMain\",\r\n            \"Value\": 0.1\r\n          },\r\n          {\r\n            \"SingleBuff\": \"AmmunitionSpecial\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      }\r\n    ]\r\n  },\r\n  {\r\n    \"Header\": \"Marine\",\r\n    \"GroupPersistentId\": 0,\r\n    \"PersistentId\": 9,\r\n    \"InfoText\": \"Specialized in ranged combat. Powerful weapons but with poor Armor.\\n<color=red>Starting Debuff: -40% Armor</color>\\nMax LV 10\\n\\nBonuses Each LV up:\\n+8% Gun Damage\\n+3% Armor\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 100% -> 108%\\nArmor 60% -> 63%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 85,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 108% -> 116%\\nArmor 63% -> 66%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.08,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 510,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 116% -> 124%\\nArmor 66% -> 69%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.16,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 1020,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 124% -> 132%\\nArmor 69% -> 72%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.24,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 1615,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 132% -> 140%\\nArmor 72% -> 75%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.32,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 2295,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 140% -> 148%\\nArmor 75% -> 78%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.4,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 6,\r\n        \"TotalXpRequired\": 3060,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 148% -> 156%\\nArmor 78% -> 81%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.48,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 7,\r\n        \"TotalXpRequired\": 3910,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 156% -> 164%\\nArmor 81% -> 84%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.56,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 8,\r\n        \"TotalXpRequired\": 4845,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 164% -> 172%\\nArmor 84% -> 87%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.64,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 9,\r\n        \"TotalXpRequired\": 5865,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 172% -> 180%\\nArmor 87% -> 90%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.72,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 10,\r\n        \"TotalXpRequired\": 6970,\r\n        \"CustomLevelUpPopupText\": \"MAX LV!\\nGun Damage +8%\\nArmor +3%\",\r\n        \"CustomLevelStatsText\": \"Class: Marine\\n{0}\\nGun Damage 180%\\nArmor 90%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1.8,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      }\r\n    ]\r\n  },\r\n  {\r\n    \"Header\": \"Hunter\",\r\n    \"GroupPersistentId\": 0,\r\n    \"PersistentId\": 7,\r\n    \"InfoText\": \"Specialized in melee combat. Deal high melee damage while gaining light Armor for survivability.\\nMax LV 5 bonus: Double Jump\\nLV 1 bonus: 125% Melee Damage\\n\\nBonuses Each LV up:\\n+4% Armor\\n+4% Speed\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Hunter\\n{0}\\nMelee 100% -> 225%\\nArmor 100% -> 104%\\nSpeed 100% -> 104%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.0,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 450,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee +125%\\nArmor +4%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Hunter\\n{0}\\nMelee 225%\\nArmor 104% -> 108%\\nSpeed 104% -> 108%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 2.25,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.04\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 1150,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +4%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Hunter\\n{0}\\nMelee 225%\\nArmor 108% -> 112%\\nSpeed 108% -> 112%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 2.25,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.08\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 2200,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +4%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Hunter\\n{0}\\nMelee 225%\\nArmor 112% -> 116%\\nSpeed 112% -> 116%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 2.25,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.2\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 3700,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +4%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Hunter\\n{0}\\nMelee 225%\\nArmor 116% -> 120%\\nSpeed 116% -> 120%\\nJump -> Double Jump\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 2.25,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.16\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 5650,\r\n        \"CustomLevelUpPopupText\": \"MAX LV!\\nArmor +4%\\nSpeed +4%\\n+Double Jump\",\r\n        \"CustomLevelStatsText\": \"Class: Hunter\\n{0}\\nMelee 225%\\nArmor 120%\\nSpeed 120%\\nDouble Jump\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 2.25,\r\n        \"WeaponDamageMultiplier\": 1.0,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.2\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      }\r\n    ]\r\n  },\r\n  {\r\n    \"Header\": \"Assassin\",\r\n    \"GroupPersistentId\": 0,\r\n    \"PersistentId\": 8,\r\n    \"InfoText\": \"Specialized in melee combat. Devastating in stealth and combat but with very poor survivability.\\n<color=red>Starting Debuff: -45% Armor</color>\\nMax LV 5 bonus: Double Jump\\nLV 1 bonus: 215% Melee Damage\\n\\nBonuses Each LV up:\\n+5% Armor\\n+4% Speed\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Assassin\\n{0}\\nMelee 100% -> 315%\\nArmor 55% -> 60%\\nSpeed 100% -> 104%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.0,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.0\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 450,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee +215%\\nArmor +5%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Assassin\\n{0}\\nMelee 315%\\nArmor 60% -> 65%\\nSpeed 104% -> 108%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 3.15,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.04\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 1150,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +5%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Assassin\\n{0}\\nMelee 315%\\nArmor 65% -> 70%\\nSpeed 108% -> 112%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 3.15,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.08\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 2200,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +5%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Assassin\\n{0}\\nMelee 315%\\nArmor 70% -> 75%\\nSpeed 112% -> 116%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 3.15,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.12\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 3700,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +5%\\nSpeed +4%\",\r\n        \"CustomLevelStatsText\": \"Class: Assassin\\n{0}\\nMelee 315%\\nArmor 75% -> 80%\\nSpeed 116% -> 120%\\nJump -> Double Jump\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 3.15,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.16\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 5650,\r\n        \"CustomLevelUpPopupText\": \"MAX LV!\\nArmor +5%\\nSpeed +4%\\n+Double Jump\",\r\n        \"CustomLevelStatsText\": \"Class: Assassin\\n{0}\\nMelee 315%\\nArmor 80%\\nSpeed 120%\\nDouble Jump\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 3.15,\r\n        \"WeaponDamageMultiplier\": 1.0,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.2\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      }\r\n    ]\r\n  },\r\n  {\r\n    \"Header\": \"Fighter\",\r\n    \"GroupPersistentId\": 0,\r\n    \"PersistentId\": 10,\r\n    \"InfoText\": \"Specialized in general combat. Improved damage with all guns and melee.\\nMax LV 10\\n\\nBonuses Each LV up:\\n+3% Gun Damage\\n+6% Melee Damage\\n+1% Speed\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 100% -> 103%\\nMelee Damage 100% -> 106%\\nSpeed 100% -> 101%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 100,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +6%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 103% -> 106%\\nMelee Damage 106% -> 112%\\nSpeed 101% -> 102%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.06,\r\n        \"WeaponDamageMultiplier\": 1.03,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.01\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 106% -> 109%\\nMelee Damage 112% -> 118%\\nSpeed 102% -> 103%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.12,\r\n        \"WeaponDamageMultiplier\": 1.06,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.02\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 1200,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 109% -> 112%\\nMelee Damage 118% -> 124%\\nSpeed 103% -> 104%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.18,\r\n        \"WeaponDamageMultiplier\": 1.09,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.03\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 1900,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 112% -> 115%\\nMelee Damage 124% -> 130%\\nSpeed 104% -> 105%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.24,\r\n        \"WeaponDamageMultiplier\": 1.12,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.04\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 2700,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 115% -> 118%\\nMelee Damage 130% -> 136%\\nSpeed 105% -> 106%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.3,\r\n        \"WeaponDamageMultiplier\": 1.15,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.05\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 6,\r\n        \"TotalXpRequired\": 3600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 118% -> 121%\\nMelee Damage 136% -> 142%\\nSpeed 106% -> 107%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.36,\r\n        \"WeaponDamageMultiplier\": 1.18,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.06\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 7,\r\n        \"TotalXpRequired\": 4600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 121% -> 124%\\nMelee Damage 142% -> 148%\\nSpeed 107% -> 108%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.42,\r\n        \"WeaponDamageMultiplier\": 1.21,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.07\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 8,\r\n        \"TotalXpRequired\": 5700,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 124% -> 127%\\nMelee Damage 148% -> 154%\\nSpeed 108% -> 109%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.48,\r\n        \"WeaponDamageMultiplier\": 1.24,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.08\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 9,\r\n        \"TotalXpRequired\": 6900,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 127% -> 130%\\nMelee Damage 154% -> 160%\\nSpeed 109% -> 110%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.54,\r\n        \"WeaponDamageMultiplier\": 1.27,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.09\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 10,\r\n        \"TotalXpRequired\": 8200,\r\n        \"CustomLevelUpPopupText\": \"MAX LV!\\nGun Damage +3%\\nMelee Damage +7%\\nSpeed +1%\",\r\n        \"CustomLevelStatsText\": \"Class: Fighter\\n{0}\\nGun Damage 130%\\nMelee Damage 160%\\nSpeed 110%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1.6,\r\n        \"WeaponDamageMultiplier\": 1.3,\r\n        \"CustomScaling\": [\r\n          {\r\n            \"CustomBuff\": \"MovementSpeedMultiplier\",\r\n            \"Value\": 1.1\r\n          }\r\n        ],\r\n        \"LevelUpBonus\": []\r\n      }\r\n    ]\r\n  },\r\n  {\r\n    \"Header\": \"Survivalist\",\r\n    \"GroupPersistentId\": 1,\r\n    \"PersistentId\": 3,\r\n    \"InfoText\": \"Increased odds of survival in extreme conditions. Endure any scenario.\\nMax LV 15 bonus: Infect Immune\\n\\nBonuses Each LV up:\\n+3% Armor\\n+3% Infect Resist\\n10% Heal\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 100% -> 103%\\nInfect Res. 0% -> 3%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 100,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 103% -> 106%\\nInfect Res. 0% -> 3%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 106% -> 109%\\nInfect Res. 3% -> 6%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 1200,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 109% -> 112%\\nInfect Res. 6% -> 9%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 1850,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 112% -> 115%\\nInfect Res. 9% -> 12%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 2550,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n20% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 115% -> 118%\\nInfect Res. 12% -> 15%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.2\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 6,\r\n        \"TotalXpRequired\": 3300,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 118% -> 121%\\nInfect Res. 15% -> 18%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 7,\r\n        \"TotalXpRequired\": 4100,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 121% -> 124%\\nInfect Res. 18% -> 21%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 8,\r\n        \"TotalXpRequired\": 4950,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 124% -> 127%\\nInfect Res. 21% -> 24%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 9,\r\n        \"TotalXpRequired\": 5850,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 127% -> 130%\\nInfect Res. 24% -> 27%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 10,\r\n        \"TotalXpRequired\": 6850,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n20% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 130% -> 133%\\nInfect Res. 27% -> 30%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.2\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 11,\r\n        \"TotalXpRequired\": 7950,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 133% -> 136%\\nInfect Res. 30% -> 33%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 12,\r\n        \"TotalXpRequired\": 9150,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 136% -> 139%\\nInfect Res. 33% -> 36%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 13,\r\n        \"TotalXpRequired\": 10450,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 139% -> 142%\\nInfect Res. 36% -> 39%\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 14,\r\n        \"TotalXpRequired\": 11850,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nArmor +3%\\nInfection Res. +3%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 142% -> 145%\\nInfect Res. 39% -> Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 15,\r\n        \"TotalXpRequired\": 13350,\r\n        \"CustomLevelUpPopupText\": \"MAX LV!\\nArmor +3%\\nInfection Res. +61%\\n20% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Survivalist\\n{0}\\nArmor 145%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.2\r\n          }\r\n        ]\r\n      }\r\n    ]\r\n  },\r\n  {\r\n    \"Header\": \"Outlander\",\r\n    \"GroupPersistentId\": 1,\r\n    \"PersistentId\": 11,\r\n    \"InfoText\": \"Specialized for surviving on the run. Greatly improved Projectile Armor and Infect Resist.\\nMax LV 15\\nLV 1 bonus: Infect Immune\\n\\nBonuses Each LV up:\\n+2% Melee Armor\\n+5% Projectile Armor\\n10% Heal\",\r\n    \"StartingBuffs\": [],\r\n    \"Levels\": [\r\n      {\r\n        \"LevelNumber\": 0,\r\n        \"TotalXpRequired\": 0,\r\n        \"CustomLevelUpPopupText\": null,\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 100% -> 102%\\nProjectile Armor 100% -> 105%\\nInfect Res. 0% -> Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": []\r\n      },\r\n      {\r\n        \"LevelNumber\": 1,\r\n        \"TotalXpRequired\": 100,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 102% -> 104%\\nProjectile Armor 105% -> 110%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 2,\r\n        \"TotalXpRequired\": 600,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 104% -> 106%\\nProjectile Armor 110% -> 115%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 3,\r\n        \"TotalXpRequired\": 1200,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 106% -> 108%\\nProjectile Armor 115% -> 120%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 4,\r\n        \"TotalXpRequired\": 1850,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 108% -> 110%\\nProjectile Armor 120% -> 125%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 5,\r\n        \"TotalXpRequired\": 2550,\r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n20% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 110% -> 112%\\nProjectile Armor 125% -> 130%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.2\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 6,\r\n        \"TotalXpRequired\": 3300,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 112% -> 114%\\nProjectile Armor 130% -> 135%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 7,\r\n        \"TotalXpRequired\": 4100,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 114% -> 116%\\nProjectile Armor 135% -> 140%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 8,\r\n        \"TotalXpRequired\": 4950,        \r\n        \"CustomLevelUpPopupText\": \"Lv Up!\\nMelee Armor +2%\\nProjectile Armor +5%\\n10% Heal\",\r\n        \"CustomLevelStatsText\": \"Class: Outlander\\n{0}\\nMelee Armor 116% -> 118%\\nProjectile Armor 140% -> 145%\\nInfect Immune\",\r\n        \"HealthMultiplier\": 1,\r\n        \"MeleeDamageMultiplier\": 1,\r\n        \"WeaponDamageMultiplier\": 1,\r\n        \"CustomScaling\": [],\r\n        \"LevelUpBonus\": [\r\n          {\r\n            \"SingleBuff\": \"Heal\",\r\n            \"Value\": 0.1\r\n          }\r\n        ]\r\n      },\r\n      {\r\n        \"LevelNumber\": 9,\r\n        \"TotalXpRequired\": 5850,        \r\n        \"C