using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BoneLib; using BoneLib.BoneMenu; using BoneLib.Notifications; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.Pool; using Il2CppSLZ.Marrow.Warehouse; using MelonLoader; using MelonLoader.Preferences; using Newtonsoft.Json; using SpawnLoadout; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Main), "SpawnLoadout", "1.0.0", "zekeg", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyVersion("0.0.0.0")] namespace SpawnLoadout; public class Main : MelonMod { internal static Main Instance; internal static MelonPreferences_Category PrefCategory; internal static MelonPreferences_Entry PrefAutoLoad; internal static MelonPreferences_Entry PrefActivePreset; private Page _mainPage; private Page _presetsPage; private bool _isDead; private bool _respawnWatcherRunning; public override void OnInitializeMelon() { Instance = this; PrefCategory = MelonPreferences.CreateCategory("SpawnLoadout"); PrefAutoLoad = PrefCategory.CreateEntry("AutoLoad", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); PrefActivePreset = PrefCategory.CreateEntry("ActivePreset", "", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); PresetManager.Initialize(); SetupBoneMenu(); Hooking.OnLevelLoaded += delegate { if (PrefAutoLoad.Value && !string.IsNullOrEmpty(PrefActivePreset.Value)) { MelonCoroutines.Start(DelayedLoad(3f)); } }; Hooking.OnPlayerDeath += delegate { _isDead = true; if (!_respawnWatcherRunning) { _respawnWatcherRunning = true; MelonCoroutines.Start(RespawnWatcher()); } }; } private IEnumerator RespawnWatcher() { while (_isDead) { yield return (object)new WaitForSeconds(0.5f); if (!PrefAutoLoad.Value || string.IsNullOrEmpty(PrefActivePreset.Value)) { _isDead = false; break; } bool ready = false; try { ready = (Object)(object)Player.RigManager != (Object)null && (Object)(object)Player.RigManager.inventory != (Object)null && (Object)(object)Player.Head != (Object)null; } catch { } if (ready) { _isDead = false; yield return (object)new WaitForSeconds(1.5f); TryLoadActivePreset(); break; } } _respawnWatcherRunning = false; } private void SetupBoneMenu() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) _mainPage = Page.Root.CreatePage("SpawnLoadout", new Color(0.2f, 0.6f, 1f), 0, true); _mainPage.CreateBool("Auto Load", Color.green, PrefAutoLoad.Value, (Action)delegate(bool val) { PrefAutoLoad.Value = val; }); StringElement nameElement = _mainPage.CreateString("Preset Name", Color.white, "", (Action)null); _mainPage.CreateFunction("Save Current as Preset", Color.cyan, (Action)delegate { string text = nameElement.Value.Trim(); if (string.IsNullOrEmpty(text)) { SendNotification("Error", "Enter a name first", (NotificationType)2); } else if (PresetManager.PresetExists(text)) { SendNotification("Error", "Preset name already exists", (NotificationType)2); } else { PresetManager.SavePreset(text); RefreshPresetsPage(); SendNotification("Saved", "Preset \"" + text + "\" saved", (NotificationType)3); } }); _mainPage.CreateFunction("Load Active Preset Now", Color.yellow, (Action)delegate { TryLoadActivePreset(); }); _presetsPage = _mainPage.CreatePage("Presets", Color.cyan, 0, true); RefreshPresetsPage(); } private void RefreshPresetsPage() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) _presetsPage.RemoveAll(); List allPresets = PresetManager.GetAllPresets(); if (allPresets.Count == 0) { _presetsPage.CreateFunction("(no presets saved)", Color.gray, (Action)delegate { }); return; } foreach (Preset preset in allPresets) { bool flag = preset.Name == PrefActivePreset.Value; Page val = _presetsPage.CreatePage(preset.Name, flag ? Color.green : Color.white, 0, true); val.CreateFunction("Load Now", Color.green, (Action)delegate { PresetManager.LoadPreset(preset); SendNotification("Loaded", "Preset \"" + preset.Name + "\" loaded", (NotificationType)3); }); if (!flag) { val.CreateFunction("Set as Auto Load", Color.yellow, (Action)delegate { PrefActivePreset.Value = preset.Name; RefreshPresetsPage(); SendNotification("Active", "\"" + preset.Name + "\" set as auto-load", (NotificationType)0); }); } else { val.CreateFunction("(active)", Color.green, (Action)delegate { }); } val.CreateFunction("Delete", Color.red, (Action)delegate { Menu.DisplayDialog("Delete Preset", "Delete \"" + preset.Name + "\"?", Dialog.WarningIcon, (Action)delegate { bool flag2 = preset.Name == PrefActivePreset.Value; PresetManager.DeletePreset(preset.Name); if (flag2) { PrefActivePreset.Value = ""; } RefreshPresetsPage(); SendNotification("Deleted", "\"" + preset.Name + "\" deleted", (NotificationType)1); }, (Action)null); }); } } private IEnumerator DelayedLoad(float delay) { yield return (object)new WaitForSeconds(delay); TryLoadActivePreset(); } private void TryLoadActivePreset() { if (!string.IsNullOrEmpty(PrefActivePreset.Value)) { Preset preset = PresetManager.GetPreset(PrefActivePreset.Value); if (preset == null) { SendNotification("Error", "Preset \"" + PrefActivePreset.Value + "\" not found", (NotificationType)2); } else { PresetManager.LoadPreset(preset); } } } internal static void SendNotification(string title, string message, NotificationType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown Notifier.Send(new Notification { Title = NotificationText.op_Implicit(title), Message = NotificationText.op_Implicit(message), Type = type, PopupLength = 3f, ShowTitleOnPopup = true }); } } public class Preset { public string Name; public Dictionary Slots = new Dictionary(); } public static class PresetManager { private static string _presetsDir; public static void Initialize() { _presetsDir = Path.Combine(Directory.GetCurrentDirectory(), "UserData", "SpawnLoadout", "Presets"); Directory.CreateDirectory(_presetsDir); } private static string GetFilePath(string presetName) { string text = string.Join("_", presetName.Split(Path.GetInvalidFileNameChars())); return Path.Combine(_presetsDir, text + ".json"); } public static bool PresetExists(string name) { return File.Exists(GetFilePath(name)); } public static List GetAllPresets() { if (!Directory.Exists(_presetsDir)) { return new List(); } List list = new List(); string[] files = Directory.GetFiles(_presetsDir, "*.json"); foreach (string path in files) { try { Preset preset = JsonConvert.DeserializeObject(File.ReadAllText(path)); if (preset != null && !string.IsNullOrEmpty(preset.Name)) { list.Add(preset); } } catch { } } return list; } public static Preset GetPreset(string name) { string filePath = GetFilePath(name); if (!File.Exists(filePath)) { return null; } try { return JsonConvert.DeserializeObject(File.ReadAllText(filePath)); } catch { return null; } } public static void SavePreset(string name) { Dictionary currentInventoryBarcodes = GetCurrentInventoryBarcodes(); string contents = JsonConvert.SerializeObject((object)new Preset { Name = name, Slots = currentInventoryBarcodes }, (Formatting)1); File.WriteAllText(GetFilePath(name), contents); } public static void DeletePreset(string name) { string filePath = GetFilePath(name); if (File.Exists(filePath)) { File.Delete(filePath); } } public static Dictionary GetCurrentInventoryBarcodes() { Dictionary dictionary = new Dictionary(); try { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null || (Object)(object)rigManager.inventory == (Object)null) { return dictionary; } foreach (SlotContainer item in (Il2CppArrayBase)(object)rigManager.inventory.bodySlots) { if ((Object)(object)((item != null) ? item.inventorySlotReceiver : null) == (Object)null) { continue; } WeaponSlot slottedWeapon = item.inventorySlotReceiver._slottedWeapon; if ((Object)(object)((slottedWeapon != null) ? slottedWeapon.interactableHost : null) == (Object)null) { continue; } Poolee val = (((Object)(object)slottedWeapon.interactableHost.manager != (Object)null) ? ((Component)slottedWeapon.interactableHost.manager).GetComponent() : ((Component)slottedWeapon.interactableHost).GetComponent()); if (!((Object)(object)((val != null) ? val.SpawnableCrate : null) == (Object)null)) { string iD = ((Scannable)val.SpawnableCrate).Barcode.ID; if (!string.IsNullOrEmpty(iD) && !dictionary.ContainsKey(((Object)item).name)) { dictionary[((Object)item).name] = iD; } } } } catch (Exception ex) { Main instance = Main.Instance; if (instance != null) { ((MelonBase)instance).LoggerInstance.Error("GetInventory: " + ex.Message); } } return dictionary; } public static void LoadPreset(Preset preset) { //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) if (preset?.Slots == null || preset.Slots.Count == 0) { return; } try { RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager == (Object)null) { Main instance = Main.Instance; if (instance != null) { ((MelonBase)instance).LoggerInstance.Error("RigManager null"); } return; } int num = 0; foreach (KeyValuePair slot in preset.Slots) { string value = slot.Value; string key = slot.Key; if (string.IsNullOrEmpty(value)) { continue; } InventorySlotReceiver val = null; foreach (SlotContainer item in (Il2CppArrayBase)(object)rigManager.inventory.bodySlots) { if ((Object)(object)item != (Object)null && ((Object)item).name == key) { val = item.inventorySlotReceiver; break; } } if ((Object)(object)val == (Object)null) { Vector3 val2 = Vector3.zero; try { val2 = Player.Head.position + Player.Head.forward * 1.5f; } catch { ((Vector3)(ref val2))..ctor(0f, 1.5f, 0f); } HelperMethods.SpawnCrate(value, val2 + Vector3.right * ((float)num * 0.3f), Quaternion.identity, Vector3.one, true, (Action)null, (Action)null); num++; } else { if ((Object)(object)val._slottedWeapon != (Object)null) { val.DespawnContents(); } val.SpawnInSlotAsync(new Barcode(value)); num++; } } if (num > 0) { Main.SendNotification("SpawnLoadout", $"Loaded {num} items", (NotificationType)3); } } catch (Exception ex) { Main instance2 = Main.Instance; if (instance2 != null) { ((MelonBase)instance2).LoggerInstance.Error("LoadPreset: " + ex.Message); } } } }