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+gite1fe3bb-dirty-master.e1fe3bbd64a069c93b70c9e973d34900b464a762")] [assembly: AssemblyProduct("EndskApi")] [assembly: AssemblyTitle("EndskApi")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace EndskApi { [BepInPlugin("Endskill.EndskApi", "EndskApi", "1.3.0")] 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.0"; 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("Dev Settings", "DebugMessages", false, "This settings activates/deactivates debug messages in the console for this specific plugin.").Value; ConfigLoader = ((BasePlugin)this).Config; ClassInjector.RegisterTypeInIl2Cpp(); ClassInjector.RegisterTypeInIl2Cpp(); 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 = "gite1fe3bb-dirty-master"; public const string SemVer = "1.0.0+gite1fe3bb-dirty-master"; public const string GitRevShort = "e1fe3bb-dirty"; public const string GitRevLong = "e1fe3bbd64a069c93b70c9e973d34900b464a762-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)(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 _tools; public string PageTitle { get; set; } protected static string PageTitlePostfix { get; set; } = ""; public BaseMenu(IntPtr intPtr) : base(intPtr) { _tools = new List(); } 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 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 _toolToMenuMap; private List _unknownMenus; private List _middleMouseClickTools = new List(); private List _timedTools = new List(); private List _hiddenTools = new List(); 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(); _unknownMenus = new List(); _currentState = MenuStates.HiddenAndActive; Instance = this; } public void Awake() { Il2CppArrayBase allBlocks = GameDataBlockBase.GetAllBlocks(); _enemyNamesIdMap = new(uint, string)[allBlocks.Count]; for (int i = 0; i < allBlocks.Count; i++) { _enemyNamesIdMap[i] = (((GameDataBlockBase)(object)allBlocks[i]).persistentID, ((GameDataBlockBase)(object)allBlocks[i]).name); } CurrentEnemyIndex = 0; } [HideFromIl2Cpp] public void ActivateUnknownMenu(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 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 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 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(BepInExLoader.ConfigLoader.Bind("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> _cache; public static InformationCache Instance { get; } = new InformationCache(); public InformationCache() { _cache = new Dictionary>(); } public void SaveInformation(object key, object info, string mod) { GetCacheOfMod(mod)[key] = info; } public T GetInformation(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 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(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 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 cache)) { cache.Remove(key); } } public bool ContainsKey(object key, string mod) { if (TryGetCacheOfMod(mod, out Dictionary cache)) { return cache.ContainsKey(key); } return false; } private Dictionary GetCacheOfMod(string mod) { if (!_cache.TryGetValue(mod, out Dictionary value)) { value = new Dictionary(); _cache[mod] = value; } return value; } private bool TryGetCacheOfMod(string mod, out Dictionary 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("CheckpointCleanup", (Action)ReceiveCheckpointCleanup); NetworkAPI.RegisterEvent("CheckpointHasBeenReached", (Action)ReceiveCheckpointReached); NetworkAPI.RegisterEvent("BiotagApplied", (Action)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()); } } public static void SendCheckpointReached() { NetworkAPI.InvokeEvent("CheckpointHasBeenReached", default(DummyStruct), (SNet_ChannelType)2); } public static void SendCheckpointCleanups() { NetworkAPI.InvokeEvent("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("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 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 UseTool { get; set; } public Action 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 onToggleUpdate, bool startState) { Text = text; CheckInput = input; IsToggle = true; UseTool = ToggleTool; OnToggleUpdate = onToggleUpdate; CurrentToggleState = startState; } public Tool(string text, InputTool input, bool isToggle, Action useCheat, Action 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 ExtraToolAction { get; set; } public InformationId InformationId { get; set; } public ToolExtended(string text, InputTool input, bool isToggle, Action useCheat, Action extraCheatAction, Action 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 DamageDistributions { get; set; } public HashSet TaggedBy { get; set; } public PlayerAgent? LastHitDealtBy { get; set; } public LastHitType lastHitType { get; set; } public EnemyKillDistribution(EnemyAgent agentToKill) { KilledEnemyAgent = agentToKill; DamageDistributions = new Dictionary(); TaggedBy = new HashSet(); } 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 BoosterEffects { get; set; } List 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 info, string mod = "GlobalCache") { SaveInformation(typeof(T), info, mod); } public static T GetInformation(object key, string mod = "GlobalCache") { return _informationCache.GetInformation(key, mod); } public static T GetInstance(string mod = "GlobalCache") { return GetInformation(typeof(T), mod); } public static bool TryGetInformation(object key, out T information, string mod = "GlobalCache", bool logNotFound = true) { return _informationCache.TryGetInformation(key, out information, mod, logNotFound); } public static bool TryGetInstance(out T information, string mod = "GlobalCache", bool logNotFound = true) { return _informationCache.TryGetInformation(typeof(T), out information, mod, logNotFound); } public static void RemoveInformation(object key, string mod = "GlobalCache") { _informationCache.RemoveInformation(key, mod); } public static void RemoveInstance(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>("CheckpointReachedKey", out var information, "EndskApi", logNotFound: false)) { information = new List(); CacheApi.SaveInformation("CheckpointReachedKey", information, "EndskApi"); } information.Add(callBack); } public static void AddCheckpointReloadedCallback(Action callBack) { if (!CacheApi.TryGetInformation>("CheckpointReloadedKey", out var information, "EndskApi", logNotFound: false)) { information = new List(); CacheApi.SaveInformation("CheckpointReloadedKey", information, "EndskApi"); } information.Add(callBack); } public static void AddCheckpointCleanupCallback(Action callBack) { if (!CacheApi.TryGetInformation>("CheckpointCleanupKey", out var information, "EndskApi", logNotFound: false)) { information = new List(); CacheApi.SaveInformation("CheckpointCleanupKey", information, "EndskApi"); } information.Add(callBack); } public static void RemoveCheckpointReachedCallback(Action callBack) { if (CacheApi.TryGetInformation>("CheckpointReachedKey", out var information, "EndskApi", logNotFound: false)) { information.Remove(callBack); } } public static void RemoveCheckpointReloadedCallback(Action callBack) { if (CacheApi.TryGetInformation>("CheckpointReloadedKey", out var information, "EndskApi", logNotFound: false)) { information.Remove(callBack); } } public static void RemoveCheckpointCleanupCallback(Action callBack) { if (CacheApi.TryGetInformation>("CheckpointCleanupKey", out var information, "EndskApi", logNotFound: false)) { information.Remove(callBack); } } internal static void InvokeCheckpointReachedCallbacks() { if (!CacheApi.TryGetInformation>("CheckpointReachedKey", out var information, "EndskApi", logNotFound: false)) { return; } foreach (Action item in information) { item(); } } internal static void InvokeCheckpointReloadedCallbacks() { if (!CacheApi.TryGetInformation>("CheckpointReloadedKey", out var information, "EndskApi", logNotFound: false)) { return; } foreach (Action item in information) { item(); } } internal static void InvokeCheckpointCleanupCallbacks() { if (!CacheApi.TryGetInformation>("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>("EndskApi"); } set { CacheApi.SaveInstance(value, "EndskApi"); } } internal static List<(double, ReceiveMeleeDamage)> MeleePostfixCallbacks { get { return CacheApi.GetInstance>(); } set { CacheApi.SaveInstance(value); } } internal static List<(double, ReceiveBulletDamage)> BulletPrefixCallbacks { get { return CacheApi.GetInstance>("EndskApi"); } set { CacheApi.SaveInstance(value, "EndskApi"); } } internal static List<(double, ReceiveBulletDamage)> BulletPostfixCallbacks { get { return CacheApi.GetInstance>(); } set { CacheApi.SaveInstance(value); } } internal static List<(double, ReceiveExplosionDamage)> ExplosionPrefixCallbacks { get { return CacheApi.GetInstance>("EndskApi"); } set { CacheApi.SaveInstance(value, "EndskApi"); } } internal static List<(double, ReceiveExplosionDamage)> ExplosionPostfixCallbacks { get { return CacheApi.GetInstance>(); } 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 _enemyStates = new Dictionary(); private static Dictionary _enemyDistributions = new Dictionary(); public static void AddEnemyKilledCallback(Action callBack) { Setup(); if (!CacheApi.TryGetInformation>>("EnemyKillCallbacks", out var information, "EndskApi", logNotFound: false)) { information = new List>(); CacheApi.SaveInformation("EnemyKillCallbacks", information, "EndskApi"); } information.Add(callBack); } internal static void InvokeEnemyKilledCallbacks(EnemyKillDistribution enemyKill) { if (!CacheApi.TryGetInformation>>("EnemyKillCallbacks", out var information, "EndskApi", logNotFound: false)) { return; } foreach (Action 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(); 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(); 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()); } 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.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.GetBlock(gearId.GetCompID((eGearComponent)2)); ArchetypeDataBlock block3 = GameDataBlockBase.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 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) GearInfo info2 = info; PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack; localBackpack.SpawnAndEquipGearAsync(info2.Slot, info2.GearId, delBackpackItemCallback.op_Implicit((Action)BackPackItemCreatedCallBack)); SetAmmoStorage(info2, 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(); if ((Object)(object)val != (Object)null) { val.SetCurrentClip(info2.AmmunitionInMagazine); PlayerManager.GetLocalPlayerAgent().Sync.WantsToWieldSlot(info2.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(); 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)(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()); } private static Dictionary GetGearInfo() { return CacheApi.GetInstance>("EndskApi"); } private static void SetGearInfoCache(Dictionary 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>("InitKey", out var information, "EndskApi", logNotFound: false)) { information = new List(); CacheApi.SaveInformation("InitKey", information, "EndskApi"); } information.Add(callBack); } internal static void InvokeInitCallbacks() { if (!CacheApi.TryGetInformation>("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>("StartLevelKey", out var information, "EndskApi", logNotFound: false)) { information = new List(); CacheApi.SaveInformation("StartLevelKey", information, "EndskApi"); } information.Add(callBack); } public static void AddEndLevelCallback(Action callBack) { if (!CacheApi.TryGetInformation>("EndLevelKey", out var information, "EndskApi", logNotFound: false)) { information = new List(); CacheApi.SaveInformation("EndLevelKey", information, "EndskApi"); } information.Add(callBack); } internal static void InvokeEndLevelCallbacks() { if (!CacheApi.TryGetInformation>("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>("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(), "EndskApi"); Object.DontDestroyOnLoad((Object)val); _setup = true; } } public static void ActivateUnknownMenu(TScript menu) where TScript : BaseMenu { Setup(); CacheApi.GetInstance("EndskApi").ActivateUnknownMenu(menu); } public static TScript AddMenu(string pageName) where TScript : BaseMenu { Setup(); MainMenu instance = CacheApi.GetInstance("EndskApi"); TScript val = ((Component)instance).gameObject.AddComponent(); instance.AddPage(pageName, val); CacheApi.SaveInstance(val, "EndskApi"); return val; } public static TScript GetMenu() where TScript : BaseMenu { Setup(); return CacheApi.GetInstance("EndskApi"); } public static void AddMiddleMouseClickTool(IExtendedTool tool) { Setup(); CacheApi.GetInstance("EndskApi").AddMiddleMouseClickTool(tool); } public static void RemoveMiddleMouseClickTool(IExtendedTool tool) { Setup(); CacheApi.GetInstance("EndskApi").RemoveMiddleMouseClickTool(tool); } public static void AddTimerTool(IExtendedTool tool) { Setup(); CacheApi.GetInstance("EndskApi").AddTimedTool(tool); } public static void RemoveTimerTool(IExtendedTool tool) { Setup(); CacheApi.GetInstance("EndskApi").RemoveTimedTool(tool); } public static void AddHiddenFunction(Tool tool) { Setup(); CacheApi.GetInstance("EndskApi").AddHiddenTool(tool); } public static void RemoveHiddenFunction(Tool tool) { Setup(); CacheApi.GetInstance("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(string fileName, JsonSerializerOptions option = null) where T : new() { if (TryLoadFromCache(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(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(string fileName, out T cachedObj) { return CacheApi.TryGetInformation(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"); } } }