using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using HarmonyLib;
using Il2CppCysharp.Threading.Tasks;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab.SaveData;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.SaveData;
using Il2CppSLZ.Marrow.Utilities;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using KeepInventory;
using KeepInventory.Fusion;
using KeepInventory.Helper;
using KeepInventory.Saves;
using KeepInventory.Utilities;
using LabFusion.Marrow;
using LabFusion.Player;
using LabFusion.SDK.Gamemodes;
using MelonLoader;
using MelonLoader.Pastel;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Semver;
using Tomlet.Attributes;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "KeepInventory", "1.2.0", "HAHOOS", "https://thunderstore.io/c/bonelab/p/HAHOOS/KeepInventory/")]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAuthorColor(0, 255, 165, 0)]
[assembly: MelonColor(0, 255, 255, 0)]
[assembly: MelonOptionalDependencies(new string[] { "LabFusion", "KeepInventory.Fusion" })]
[assembly: AssemblyTitle("Keep your inventory when switching between mod levels, as well as when quitting the game!")]
[assembly: AssemblyDescription("Keep your inventory when switching between mod levels, as well as when quitting the game!")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("HAHOOS")]
[assembly: AssemblyProduct("KeepInventory")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: ComVisible(true)]
[assembly: Guid("b45d7a48-e5c2-49b2-a7a2-331de9c55d26")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace KeepInventory
{
public class Core : MelonMod
{
public const string Version = "1.2.0";
internal static Assembly MLAssembly;
public static readonly List<string> defaultBlacklistedLevels = new List<string>(19)
{
"SLZ.BONELAB.Content.Level.LevelOutro", "c2534c5a-db71-49cf-b694-24584c657665", "c2534c5a-4197-4879-8cd3-4a695363656e", "c2534c5a-54df-470b-baaf-741f4c657665", "c2534c5a-56a6-40ab-a8ce-23074c657665", "c2534c5a-7601-4443-bdfe-7f235363656e", "SLZ.BONELAB.Content.Level.LevelBigAnomalyB", "SLZ.BONELAB.Content.Level.LevelStreetPunch", "SLZ.BONELAB.Content.Level.SprintBridge04", "SLZ.BONELAB.Content.Level.SceneMagmaGate",
"SLZ.BONELAB.Content.Level.MoonBase", "SLZ.BONELAB.Content.Level.LevelKartRace", "c2534c5a-c056-4883-ac79-e051426f6964", "c2534c5a-162f-4661-a04d-975d5363656e", "fa534c5a868247138f50c62e424c4144.Level.LevelArenaMin", "c2534c5a-c180-40e0-b2b7-325c5363656e", "c2534c5a-de61-4df9-8f6c-416954726547", "c2534c5a-4f3b-480e-ad2f-69175363656e", "c2534c5a-80e1-4a29-93ca-f3254d656e75"
};
private static readonly Dictionary<string, string> SaveNames = new Dictionary<string, string>
{
{ "Descent", "c2534c5a-4197-4879-8cd3-4a695363656e" },
{ "Ascent", "c2534c5a-db71-49cf-b694-24584c657665" },
{ "LongRun", "c2534c5a-56a6-40ab-a8ce-23074c657665" },
{ "Hub", "c2534c5a-6b79-40ec-8e98-e58c5363656e" },
{ "KartBowling", "fa534c5a83ee4ec6bd641fec424c4142.Level.LevelKartBowling" },
{ "Tuscany", "c2534c5a-2c4c-4b44-b076-203b5363656e" },
{ "HalfwayPark", "fa534c5a83ee4ec6bd641fec424c4142.Level.LevelHalfwayPark" },
{ "MineDive", "c2534c5a-54df-470b-baaf-741f4c657665" },
{ "BigAnomaly_A", "c2534c5a-7601-4443-bdfe-7f235363656e" },
{ "StreetPuncher", "SLZ.BONELAB.Content.Level.LevelStreetPunch" },
{ "SprintBridge", "SLZ.BONELAB.Content.Level.SprintBridge04" },
{ "MagmaGate", "SLZ.BONELAB.Content.Level.SceneMagmaGate" },
{ "MoonBase", "SLZ.BONELAB.Content.Level.MoonBase" },
{ "MonogonMotorway", "SLZ.BONELAB.Content.Level.LevelKartRace" },
{ "Pillar", "c2534c5a-c056-4883-ac79-e051426f6964" },
{ "BigAnomaly_B", "SLZ.BONELAB.Content.Level.LevelBigAnomalyB" },
{ "Holodeck", "fa534c5a83ee4ec6bd641fec424c4142.Level.LevelHoloChamber" },
{ "DungeonWarrior", "c2534c5a-5c2f-4eef-a851-66214c657665" },
{ "DistrictParkour", "fa534c5a83ee4ec6bd641fec424c4142.Level.SceneparkourDistrictLogic" },
{ "FantasyArena", "fa534c5a868247138f50c62e424c4144.Level.LevelArenaMin" },
{ "Baseline", "c2534c5a-61b3-4f97-9059-79155363656e" },
{ "GunRangeSandbox", "fa534c5a83ee4ec6bd641fec424c4142.Level.LevelGunRange" },
{ "MuseumSandbox", "fa534c5a83ee4ec6bd641fec424c4142.Level.LevelMuseumBasement" },
{ "Mirror", "SLZ.BONELAB.Content.Level.LevelMirror" },
{ "G114", "fa534c5a868247138f50c62e424c4144.Level.VoidG114" }
};
public static readonly string KI_PreferencesDirectory = Path.Combine(MelonEnvironment.UserDataDirectory, "KeepInventory");
internal static MelonPreferences_Category PrefsCategory;
internal static MelonPreferences_ReflectiveCategory SaveCategory;
internal static MelonPreferences_Entry<bool> mp_itemsaving;
internal static MelonPreferences_Entry<bool> mp_ammosaving;
internal static MelonPreferences_Entry<bool> mp_saveGunData;
internal static MelonPreferences_Entry<bool> mp_persistentsave;
internal static MelonPreferences_Entry<bool> mp_saveOnLevelUnload;
internal static MelonPreferences_Entry<bool> mp_loadOnLevelLoad;
internal static MelonPreferences_Entry<bool> mp_automaticallySaveToFile;
internal static MelonPreferences_Entry<List<string>> mp_blacklistedLevels;
internal static MelonPreferences_Entry<bool> mp_blacklistBONELABlevels;
internal static MelonPreferences_Entry<bool> mp_showNotifications;
internal static MelonPreferences_Entry<bool> mp_fusionSupport;
internal static MelonPreferences_Entry<int> mp_configVersion;
internal static MelonPreferences_Entry<bool> mp_initialInventoryRemove;
internal static FunctionElement statusElement;
internal static LevelInfo levelInfo;
private bool InitialLoad = true;
internal static bool LoadAmmoOnAwake = false;
public static Save CurrentSave { get; internal set; }
public static Core Instance { get; internal set; }
internal static Instance Logger { get; private set; }
public static bool HasFusion { get; private set; }
public static bool IsConnected
{
get
{
if (HasFusion && IsFusionLibraryInitialized)
{
return FusionLibraryIsConnected();
}
if (HasFusion && !IsFusionLibraryInitialized)
{
return FusionIsConnected();
}
return false;
}
}
public static bool IsFusionLibraryInitialized { get; private set; } = false;
public static bool FailedFLLoad { get; private set; } = false;
internal static Thunderstore ThunderstoreInstance { get; private set; }
internal static bool IsLatestVersion { get; private set; } = true;
internal static Package ThunderstorePackage { get; private set; }
public override void OnInitializeMelon()
{
MLAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly x) => x.GetName().Name == "MelonLoader");
Logger = ((MelonBase)this).LoggerInstance;
((MelonBase)this).LoggerInstance.Msg("Setting up KeepInventory");
ThunderstoreInstance = new Thunderstore("KeepInventory / 1.2.0 A BONELAB MelonLoader Mod");
try
{
ThunderstorePackage = ThunderstoreInstance.GetPackage("HAHOOS", "KeepInventory");
if (ThunderstorePackage != null)
{
if (ThunderstorePackage.Latest != null && !string.IsNullOrWhiteSpace(ThunderstorePackage.Latest.Version))
{
IsLatestVersion = ThunderstorePackage.IsLatestVersion("1.2.0");
if (!IsLatestVersion)
{
((MelonBase)this).LoggerInstance.Warning("A new version of KeepInventory is available: v" + ThunderstorePackage.Latest.Version + ". It is recommended that you update");
}
else
{
((MelonBase)this).LoggerInstance.Msg("Latest version of KeepInventory is installed!");
}
}
else
{
((MelonBase)this).LoggerInstance.Warning("Latest version could not be found or the version is empty");
}
}
else
{
((MelonBase)this).LoggerInstance.Warning("Could not find thunderstore package for KeepInventory");
}
}
catch (Exception value)
{
((MelonBase)this).LoggerInstance.Error($"An unexpected error has occurred while trying to check if KeepInventory is the latest version, exception:\n{value}");
}
SetupPreferences();
SetupMenu();
HasFusion = HelperMethods.CheckIfAssemblyLoaded("labfusion");
if (!HasFusion)
{
((MelonBase)this).LoggerInstance.Warning("Could not find LabFusion, the mod will not use any of Fusion's functionality");
}
else
{
((MelonBase)this).LoggerInstance.Msg("Found LabFusion");
}
if (HasFusion)
{
((MelonBase)this).LoggerInstance.Msg("Attempting to load the Fusion Support Library");
try
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
if (executingAssembly != null)
{
AssemblyName name = executingAssembly.GetName();
if (name != null)
{
string text = name.Name + ".Embedded.Dependencies.KeepInventory.Fusion.dll";
string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
if (manifestResourceNames == null || manifestResourceNames.Length == 0 || !manifestResourceNames.Contains(text))
{
FailedFLLoad = true;
((MelonBase)this).LoggerInstance.Error("There were no embedded resources or dependency was not found in the list of embedded resources, cannot not load Fusion Support Library");
}
else
{
Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(text);
if (manifestResourceStream != null && manifestResourceStream.Length > 0)
{
Assembly.Load(StreamToByteArray(manifestResourceStream));
((MelonBase)this).LoggerInstance.Msg("Loaded Fusion Support Library");
IsFusionLibraryInitialized = true;
}
else
{
FailedFLLoad = true;
((MelonBase)this).LoggerInstance.Error("Could not get stream of Fusion Support Library, cannot not load Fusion Support Library");
}
}
}
else
{
FailedFLLoad = true;
((MelonBase)this).LoggerInstance.Error("Assembly Info was not found, cannot not load Fusion Support Library");
}
}
else
{
FailedFLLoad = true;
((MelonBase)this).LoggerInstance.Error("Executing assembly was somehow not found, cannot not load Fusion Support Library");
}
}
catch (Exception value2)
{
FailedFLLoad = true;
((MelonBase)this).LoggerInstance.Error($"An unexpected error occurred while loading the library:\n{value2}");
}
}
Hooking.OnLevelLoaded += LevelLoadedEvent;
Hooking.OnLevelUnloaded += LevelUnloadedEvent;
if (IsFusionLibraryInitialized)
{
SetupFusionLibrary();
}
}
private static void SetupFusionLibrary()
{
Logger.Msg("Setting up the library");
try
{
FusionMethods.Setup(Logger);
FusionMethods.LoadModule();
}
catch (Exception value)
{
FailedFLLoad = true;
Logger.Error($"An unexpected error has occurred while setting up and/or loading the fusion module, exception:\n{value}");
}
}
private static bool FusionLibraryIsConnected()
{
return FusionMethods.LocalNetworkPlayer != null;
}
private static bool FusionIsConnected()
{
return LocalPlayer.GetNetworkPlayer() != null;
}
private static void FusionSpawnInSlot(Barcode barcode, InventorySlotReceiver inventorySlotReceiver, string slotName, Color slotColor, Action<GameObject> inBetween = null)
{
FusionMethods.NetworkSpawnInSlotAsync(inventorySlotReceiver, barcode, slotColor, slotName, inBetween);
}
private static RigManager FusionFindRigManager_FSL()
{
return FusionMethods.RigManager ?? Player.RigManager;
}
private static RigManager FusionFindRigManager()
{
if (!IsConnected)
{
return Player.RigManager;
}
RigManager obj;
if (!IsFusionLibraryInitialized)
{
obj = LocalPlayer.GetNetworkPlayer().RigRefs.RigManager;
if (obj == null)
{
return Player.RigManager;
}
}
else
{
obj = FusionFindRigManager_FSL();
}
return obj;
}
private void RemoveRigCreateEvent_FSL()
{
FusionMethods.OnRigCreated -= SpawnSavedItems;
}
private void RemoveRigCreateEvent()
{
if (HasFusion && IsConnected && IsFusionLibraryInitialized)
{
RemoveRigCreateEvent_FSL();
}
}
private static AmmoInventory FusionGetAmmoInventory_FSL()
{
return FusionMethods.FindAmmoInventory();
}
private static AmmoInventory FusionGetAmmoInventory()
{
if (HasFusion)
{
object obj;
if (!IsFusionLibraryInitialized)
{
obj = NetworkGunManager.NetworkAmmoInventory;
if (obj == null)
{
return AmmoInventory.Instance;
}
}
else
{
obj = FusionGetAmmoInventory_FSL() ?? AmmoInventory.Instance;
}
return (AmmoInventory)obj;
}
return AmmoInventory.Instance;
}
private void FusionSpawnSavedItems_FSL()
{
if ((Object)(object)FusionMethods.RigManager == (Object)null)
{
Logger.Msg("Rig not found, awaiting");
FusionMethods.OnRigCreated += SpawnSavedItems;
}
else
{
Logger.Msg("Rig found, spawning");
SpawnSavedItems(FusionMethods.RigManager);
}
}
private void FusionSpawnSavedItems()
{
if (IsConnected)
{
((MelonBase)this).LoggerInstance.Msg("Client is connected to a server");
if (mp_itemsaving.Value)
{
if (IsFusionLibraryInitialized)
{
FusionSpawnSavedItems_FSL();
}
else
{
SpawnSavedItems();
}
}
}
else
{
((MelonBase)this).LoggerInstance.Msg("Client is not connected to a server, spawning locally");
if (mp_itemsaving.Value)
{
SpawnSavedItems();
}
}
}
internal static bool FusionGamemodeCheck()
{
if (!IsConnected)
{
return false;
}
if (!GamemodeManager.IsGamemodeStarted && !GamemodeManager.StartTimerActive)
{
return GamemodeManager.IsGamemodeReady;
}
return true;
}
public static byte[] StreamToByteArray(Stream stream)
{
byte[] array = new byte[16384];
using MemoryStream memoryStream = new MemoryStream();
int count;
while ((count = stream.Read(array, 0, array.Length)) > 0)
{
memoryStream.Write(array, 0, count);
}
return memoryStream.ToArray();
}
internal static void MsgPrefix(string message, string prefix, Color color)
{
Logger._MsgPastel("[" + ConsoleExtensions.Pastel(prefix, color) + "] " + message);
}
public void SavePreferences()
{
if (!mp_persistentsave.Value || !mp_automaticallySaveToFile.Value)
{
return;
}
((MelonBase)this).LoggerInstance.Msg("Saving Preferences");
try
{
MelonPreferences_ReflectiveCategory saveCategory = SaveCategory;
if (saveCategory != null)
{
saveCategory.SaveToFile(false);
}
MelonPreferences_Category prefsCategory = PrefsCategory;
if (prefsCategory != null)
{
prefsCategory.SaveToFile(false);
}
((MelonBase)this).LoggerInstance.Msg("Saved Preferences successfully");
}
catch (Exception value)
{
((MelonBase)this).LoggerInstance.Error($"An unexpected error has occurred while saving prefs\n{value}");
}
}
internal static RigManager FindRigManager()
{
if (HasFusion && IsConnected && IsFusionLibraryInitialized)
{
return FusionFindRigManager();
}
return Player.RigManager;
}
internal static AmmoInventory GetAmmoInventory()
{
if (HasFusion && IsFusionLibraryInitialized)
{
return FusionGetAmmoInventory();
}
return AmmoInventory.Instance;
}
public void SaveInventory(bool notifications = false)
{
//IL_0265: Unknown result type (might be due to invalid IL or missing references)
//IL_026f: Expected O, but got Unknown
try
{
if (HasFusion && IsConnected && (!IsFusionLibraryInitialized || !mp_fusionSupport.Value))
{
BLHelper.SendNotification("Failure", "Could not save inventory, because either the 'Fusion Support' setting is set to Disabled or the Fusion Support Library did not load correctly", showTitleOnPopup: true, 3.5f, (NotificationType)2);
((MelonBase)this).LoggerInstance.Warning("The Fusion Library is not loaded or the setting 'Fusion Support' is set to Disabled. Try enabling 'Fusion Support' in settings or restarting the game if you have Fusion Support option enabled. The Fusion Support library might have not loaded properly");
return;
}
((MelonBase)this).LoggerInstance.Msg("Saving inventory...");
bool isItemSaved = false;
bool isAmmoSaved = false;
if (mp_itemsaving.Value)
{
((MelonBase)this).LoggerInstance.Msg("Saving items in inventory slots");
bool flag = false;
RigManager val = FindRigManager();
if ((Object)(object)val == (Object)null)
{
((MelonBase)this).LoggerInstance.Warning("RigManager does not exist");
flag = true;
}
if (!flag)
{
CurrentSave.InventorySlots?.Clear();
foreach (InventorySlotReceiver componentsInChild in ((Component)val).GetComponentsInChildren<InventorySlotReceiver>())
{
if ((Object)(object)componentsInChild == (Object)null || ((componentsInChild != null) ? componentsInChild._weaponHost : null) == null || (Object)(object)((componentsInChild != null) ? componentsInChild._weaponHost.GetTransform() : null) == (Object)null || ((componentsInChild != null) ? componentsInChild._weaponHost : null) == null)
{
continue;
}
Gun component = ((Component)componentsInChild._weaponHost.GetTransform()).GetComponent<Gun>();
GunInfo gunInfo = null;
if ((Object)(object)component != (Object)null)
{
gunInfo = GunInfo.Parse(component);
}
Poolee component2 = ((Component)componentsInChild._weaponHost.GetTransform()).GetComponent<Poolee>();
if ((Object)(object)component2 != (Object)null)
{
string name = ((Object)((Component)componentsInChild).transform.parent).name;
if (name.StartsWith("prop"))
{
name = ((Object)((Component)componentsInChild).transform.parent.parent).name;
}
Barcode barcode = ((Scannable)component2.SpawnableCrate).Barcode;
((MelonBase)this).LoggerInstance.Msg($"Slot: {name} / Barcode: {((Object)component2.SpawnableCrate).name} ({((Scannable)component2.SpawnableCrate).Barcode.ID})");
if (gunInfo != null && mp_saveGunData.Value && ((Scannable)component2.SpawnableCrate).Barcode != new Barcode("c1534c5a-5747-42a2-bd08-ab3b47616467"))
{
CurrentSave.InventorySlots.Add(new SaveSlot(name, barcode, gunInfo));
}
else
{
CurrentSave.InventorySlots.Add(new SaveSlot(name, barcode));
}
}
else
{
Logger.Warning("[" + ((Object)((Component)componentsInChild).transform.parent).name + "] Could not find poolee of the spawnable in the inventory slot");
}
}
if (CurrentSave.InventorySlots.Count == 0)
{
((MelonBase)this).LoggerInstance.Msg("No spawnables were found in slots");
}
isItemSaved = true;
}
else
{
((MelonBase)this).LoggerInstance.Error("Could not save inventory, because some required game objects were not found. Items from the earlier save will be kept");
if (notifications)
{
BLHelper.SendNotification("Failure", "Failed to save the inventory, because some required game objects were not found, check the logs or console for more details", showTitleOnPopup: true, 5f, (NotificationType)2);
}
}
}
if (mp_ammosaving.Value)
{
AmmoInventory ammoInventory = GetAmmoInventory();
CurrentSave.LightAmmo = ammoInventory.GetCartridgeCount("light");
((MelonBase)this).LoggerInstance.Msg("Saved Light Ammo: " + CurrentSave.LightAmmo);
CurrentSave.MediumAmmo = ammoInventory.GetCartridgeCount("medium");
((MelonBase)this).LoggerInstance.Msg("Saved Medium Ammo: " + CurrentSave.MediumAmmo);
CurrentSave.HeavyAmmo = ammoInventory.GetCartridgeCount("heavy");
((MelonBase)this).LoggerInstance.Msg("Saved Heavy Ammo: " + CurrentSave.LightAmmo);
isAmmoSaved = true;
}
SavePreferences();
((MelonBase)this).LoggerInstance.Msg("Successfully saved inventory");
if (notifications)
{
BLHelper.SendNotification("Success", "Successfully saved the inventory, the following was saved: " + formatString(), showTitleOnPopup: true, 5f, (NotificationType)3);
}
string formatString()
{
string text = "";
if (isItemSaved)
{
text = (string.IsNullOrWhiteSpace(text) ? "Items" : (text + ", Items"));
}
if (isAmmoSaved)
{
text = (string.IsNullOrWhiteSpace(text) ? "Ammo" : (text + ", Ammo"));
}
if (string.IsNullOrWhiteSpace(text))
{
text = "N/A";
}
return text;
}
}
catch (Exception value)
{
((MelonBase)this).LoggerInstance.Error($"An unexpected error occurred while saving the inventory:\n{value}");
if (notifications)
{
BLHelper.SendNotification("Failure", "Failed to save the inventory, check the logs or console for more details", showTitleOnPopup: true, 5f, (NotificationType)2);
}
}
}
internal static bool RemoveInitialInventoryFromSave()
{
Action action = null;
Enumerator<string, Dictionary<string, Object>> enumerator = DataManager.ActiveSave.Progression.LevelState.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair<string, Dictionary<string, Object>> item = enumerator.Current;
bool changed = false;
Enumerator<string, Object> enumerator2 = item.Value.GetEnumerator();
while (enumerator2.MoveNext())
{
KeyValuePair<string, Object> y = enumerator2.Current;
if (y.Key == "SLZ.Bonelab.initial_inventory" && y.Value != null)
{
Logger.Warning("Found initial inventory in save (Level: " + item.Key + "), removing");
action = (Action)Delegate.Combine(action, (Action)delegate
{
changed = true;
item.Value[y.Key] = null;
});
}
}
action = (Action)Delegate.Combine(action, (Action)delegate
{
if (changed)
{
DataManager.ActiveSave.Progression.LevelState[item.key] = item.value;
}
});
}
action?.Invoke();
return DataManager.TrySaveActiveSave((SaveFlags)2);
}
internal static bool RemoveInitialInventoryFromSave(string barcode)
{
Action a = null;
KeyValuePair<string, string> value = SaveNames.FirstOrDefault((KeyValuePair<string, string> x) => x.Value == barcode);
if (!string.IsNullOrWhiteSpace(value.Key))
{
Dictionary<string, Object> item = DataManager.ActiveSave.Progression.LevelState[value.Key];
bool changed = false;
Enumerator<string, Object> enumerator = item.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair<string, Object> y = enumerator.Current;
if (y.Key == "SLZ.Bonelab.initial_inventory" && y.Value != null)
{
Logger.Warning("Found initial inventory in save (Level: " + value.Key + "), removing");
a = (Action)Delegate.Combine(a, (Action)delegate
{
changed = true;
item[y.Key] = null;
});
}
}
((Action)Delegate.Combine(a, (Action)delegate
{
if (changed)
{
DataManager.ActiveSave.Progression.LevelState[value.Key] = item;
}
}))?.Invoke();
return DataManager.TrySaveActiveSave((SaveFlags)2);
}
return false;
}
internal static bool DoesSaveForLevelExist(string barcode)
{
Enumerator<string, Dictionary<string, Object>> enumerator = DataManager.ActiveSave.Progression.LevelState.GetEnumerator();
while (enumerator.MoveNext())
{
_ = enumerator.Current;
if (!string.IsNullOrWhiteSpace(SaveNames.FirstOrDefault((KeyValuePair<string, string> x) => x.Value == barcode).Key))
{
return true;
}
}
return false;
}
private void SpawnSavedItems(RigManager _rigManager = null)
{
if (HasFusion && IsConnected && (!IsFusionLibraryInitialized || !mp_fusionSupport.Value))
{
((MelonBase)this).LoggerInstance.Warning("The Fusion Library is not loaded or the setting 'Fusion Support' is set to Disabled. Try enabling 'Fusion Support' in settings or restarting the game if you have Fusion Support option enabled. The Fusion Support library might have not loaded properly");
return;
}
if (HasFusion && IsConnected && IsFusionLibraryInitialized)
{
RemoveRigCreateEvent();
}
try
{
List<SaveSlot> inventorySlots = CurrentSave.InventorySlots;
if (inventorySlots != null && inventorySlots.Count >= 1)
{
RigManager val = _rigManager ?? FindRigManager();
if ((Object)(object)val == (Object)null)
{
((MelonBase)this).LoggerInstance.Error("RigManager does not exist, cannot load saved items!");
return;
}
if ((Object)(object)val.inventory == (Object)null)
{
((MelonBase)this).LoggerInstance.Error("Inventory does not exist, cannot load saved items!");
return;
}
if (val.inventory.bodySlots == null)
{
((MelonBase)this).LoggerInstance.Error("Body slots do not exist, cannot load saved items!");
return;
}
List<InventorySlotReceiver> list = ((IEnumerable<InventorySlotReceiver>)((Component)val).GetComponentsInChildren<InventorySlotReceiver>()).ToList();
List<SlotContainer> list2 = ((IEnumerable<SlotContainer>)val.inventory.bodySlots).ToList();
foreach (SaveSlot inventorySlot in CurrentSave.InventorySlots)
{
SaveSlot item = inventorySlot;
Color SlotColor = Colors.GetRandomSlotColor();
MsgPrefix("Looking for slot", item.SlotName, SlotColor);
SlotContainer? obj2 = list2.Find((SlotContainer slot) => ((Object)slot).name == item.SlotName && (Object)(object)slot.inventorySlotReceiver != (Object)null);
InventorySlotReceiver val2 = ((obj2 != null) ? obj2.inventorySlotReceiver : null);
if ((Object)(object)val2 != (Object)null)
{
InventorySlotReceiver receiver2 = val2;
spawn(receiver2);
continue;
}
val2 = list.Find((InventorySlotReceiver slot) => (((Object)((Component)slot).transform.parent).name.StartsWith("prop") ? ((Object)((Component)slot).transform.parent.parent).name : ((Object)((Component)slot).transform.parent).name) == item.SlotName);
if ((Object)(object)val2 != (Object)null)
{
spawn(val2);
}
else
{
((MelonBase)this).LoggerInstance.Warning("[" + item.SlotName + "] No slot was found with the provided name. It is possible that an avatar that was used during the saving had more slots than the current one");
}
void spawn(InventorySlotReceiver receiver)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
SpawnableCrateReference crate;
if (MarrowGame.assetWarehouse.HasCrate(new Barcode(item.Barcode)))
{
crate = new SpawnableCrateReference(item.Barcode);
SpawnableCrateReference obj3 = crate;
if (obj3 != null)
{
((Scannable)((CrateReferenceT<SpawnableCrate>)(object)obj3).Crate).PreloadAssets();
}
if (item.Type == SaveSlot.SpawnableType.Gun && mp_saveGunData.Value && item.Barcode != "c1534c5a-5747-42a2-bd08-ab3b47616467")
{
MsgPrefix($"Spawning to slot: {((Object)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).name} ({item.Barcode})", item.SlotName, SlotColor);
if (HasFusion && IsConnected)
{
FusionSpawnInSlot(((Scannable)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).Barcode, receiver, item.SlotName, SlotColor, action);
}
else
{
receiver.SpawnInSlotAsync(((Scannable)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).Barcode).GetAwaiter().OnCompleted(Action.op_Implicit((Action)notGun));
}
}
else
{
MsgPrefix($"Spawning to slot: {((Object)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).name} ({item.Barcode})", item.SlotName, SlotColor);
if (HasFusion && IsConnected)
{
FusionSpawnInSlot(((Scannable)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).Barcode, receiver, item.SlotName, SlotColor);
MsgPrefix($"Spawned to slot: {((Object)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).name} ({item.Barcode})", item.SlotName, SlotColor);
}
else
{
UniTask<bool> obj4 = receiver.SpawnInSlotAsync(((Scannable)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).Barcode);
Action action = delegate
{
MsgPrefix($"Spawned to slot: {((Object)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).name} ({item.Barcode})", item.SlotName, SlotColor);
};
obj4.GetAwaiter().OnCompleted(Action.op_Implicit(action));
}
}
}
else
{
((MelonBase)this).LoggerInstance.Warning("[" + item.SlotName + "] Could not find crate with the following barcode: " + item.Barcode);
}
void action(GameObject obj)
{
if (item.GunInfo != null && (Object)(object)obj != (Object)null)
{
Il2CppArrayBase<Gun> components = obj.GetComponents<Gun>();
MsgPrefix("Attempting to write GunInfo", item.SlotName, SlotColor);
foreach (Gun item2 in components)
{
item2.UpdateProperties(item.GunInfo, SlotColor, item, ((Object)((CrateReferenceT<SpawnableCrate>)(object)crate).Crate).name, item.Barcode);
}
}
}
void notGun()
{
action(receiver._weaponHost.GetHostGameObject());
}
}
}
}
else
{
((MelonBase)this).LoggerInstance.Msg("No saved items found");
}
((MelonBase)this).LoggerInstance.Msg("Loaded inventory");
BLHelper.SendNotification("Success", "Successfully loaded the inventory", showTitleOnPopup: true, 2.5f, (NotificationType)3);
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("An error occurred while loading the inventory", ex);
BLHelper.SendNotification("Failure", "Failed to load the inventory, check the logs or console for more details", showTitleOnPopup: true, 5f, (NotificationType)2);
}
}
public static void AddSavedAmmo(bool showNotifications = true)
{
if (!Object.CurrentThreadIsMainThread())
{
Logger.Warning("Adding ammo not on the main thread, this may cause crashes due to protected memory");
}
AmmoInventory ammoInventory = GetAmmoInventory();
if ((Object)(object)ammoInventory == (Object)null)
{
Logger.Error("Ammo inventory is null");
return;
}
ammoInventory.ClearAmmo();
Logger.Msg($"Adding light ammo: {CurrentSave.LightAmmo}");
ammoInventory.AddCartridge(ammoInventory.lightAmmoGroup, CurrentSave.LightAmmo);
Logger.Msg($"Adding medium ammo: {CurrentSave.MediumAmmo}");
ammoInventory.AddCartridge(ammoInventory.mediumAmmoGroup, CurrentSave.MediumAmmo);
Logger.Msg($"Adding heavy ammo: {CurrentSave.HeavyAmmo}");
ammoInventory.AddCartridge(ammoInventory.heavyAmmoGroup, CurrentSave.HeavyAmmo);
if (!mp_itemsaving.Value)
{
Logger.Msg("Loaded inventory");
if (showNotifications)
{
BLHelper.SendNotification("Success", "Successfully loaded the inventory", showTitleOnPopup: true, 2.5f, (NotificationType)3);
}
}
}
public void LoadSavedInventory()
{
if (HasFusion && IsConnected && FusionGamemodeCheck())
{
((MelonBase)this).LoggerInstance.Warning("A gamemode is currently running, we cannot load your inventory!");
return;
}
try
{
if (HasFusion && IsConnected && (!IsFusionLibraryInitialized || !mp_fusionSupport.Value))
{
BLHelper.SendNotification("Failure", "Could not load inventory, because either the 'Fusion Support' setting is set to Disabled or the Fusion Support Library did not load correctly", showTitleOnPopup: true, 3.5f, (NotificationType)2);
((MelonBase)this).LoggerInstance.Warning("The Fusion Library is not loaded or the setting 'Fusion Support' is set to Disabled. Try enabling 'Fusion Support' in settings or restarting the game if you have Fusion Support option enabled. The Fusion Support library might have not loaded properly");
return;
}
((MelonBase)this).LoggerInstance.Msg("Loading inventory...");
if (mp_ammosaving.Value)
{
((MelonBase)this).LoggerInstance.Msg("Waiting for Ammo Inventory to be initialized");
if ((Object)(object)GetAmmoInventory() != (Object)null)
{
AddSavedAmmo(mp_showNotifications.Value);
}
else
{
Logger.Warning("Ammo Inventory is empty, awaiting");
LoadAmmoOnAwake = true;
}
}
if (HasFusion)
{
((MelonBase)this).LoggerInstance.Msg("Checking if client is connected to a Fusion server");
FusionSpawnSavedItems();
}
else if (mp_itemsaving.Value)
{
((MelonBase)this).LoggerInstance.Msg("Spawning in slots saved items");
SpawnSavedItems();
}
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("An error occurred while loading the inventory", ex);
BLHelper.SendNotification("Failure", "Failed to load the inventory, check the logs or console for more details", showTitleOnPopup: true, 5f, (NotificationType)2);
}
}
private void LevelUnloadedEvent()
{
if (mp_saveOnLevelUnload.Value)
{
List<string> list = new List<string>(mp_blacklistedLevels.Value);
if (mp_blacklistBONELABlevels.Value)
{
list.AddRange(defaultBlacklistedLevels);
}
if (!list.Contains(levelInfo.barcode))
{
SaveInventory();
}
else
{
((MelonBase)this).LoggerInstance.Warning("Not saving due to the level being blacklisted");
}
}
}
private void LevelLoadedEvent(LevelInfo obj)
{
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: 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_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
if (InitialLoad)
{
if (FailedFLLoad)
{
BLHelper.SendNotification("Failure", "The Fusion Support Library has failed to load, meaning the fusion support for the mod will be disabled. If this will occur again, please report it to the developer (discord @hahoos)", showTitleOnPopup: true, 10f, (NotificationType)2);
IsFusionLibraryInitialized = false;
}
if (!IsLatestVersion && ThunderstorePackage != null)
{
BLHelper.SendNotification(NotificationText.op_Implicit("Update!"), new NotificationText("There is a new version of KeepInventory. Go to Thunderstore and download the latest version which is " + ("v" + ThunderstorePackage.Latest.Version).CreateUnityColor(Color.LimeGreen), Color.white, true), showTitleOnPopup: true, 5f, (NotificationType)1);
}
InitialLoad = false;
}
levelInfo = obj;
List<string> list = new List<string>(mp_blacklistedLevels.Value);
if (mp_blacklistBONELABlevels.Value)
{
list.AddRange(defaultBlacklistedLevels);
}
if (!list.Contains(obj.barcode))
{
if (!mp_loadOnLevelLoad.Value)
{
return;
}
if (DoesSaveForLevelExist(levelInfo.barcode) && mp_initialInventoryRemove.Value)
{
RemoveInitialInventoryFromSave(levelInfo.barcode);
}
if (!HasFusion || !IsConnected || (IsFusionLibraryInitialized && mp_fusionSupport.Value))
{
try
{
((Element)statusElement).ElementName = "Current level is not blacklisted";
((Element)statusElement).ElementColor = Color.green;
LoadSavedInventory();
return;
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("An error occurred while loading the inventory", ex);
BLHelper.SendNotification("Failure", "Failed to load the inventory, check the logs or console for more details", showTitleOnPopup: true, 5f, (NotificationType)2);
return;
}
}
((MelonBase)this).LoggerInstance.Warning("The Fusion Library is not loaded or the setting 'Fusion Support' is set to Disabled. Try enabling 'Fusion Support' in settings or restarting the game if you have Fusion Support option enabled. The Fusion Support library might have not loaded properly");
}
else
{
((MelonBase)this).LoggerInstance.Warning("Not loading inventory because level is blacklisted");
BLHelper.SendNotification("This level is blacklisted from loading/saving inventory", "Blacklisted", showTitleOnPopup: true, 5f, (NotificationType)1);
((Element)statusElement).ElementName = "Current level is blacklisted";
((Element)statusElement).ElementColor = Color.red;
}
}
private void SetupMenu()
{
//IL_000a: 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_002d: 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_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
//IL_020b: Unknown result type (might be due to invalid IL or missing references)
//IL_0224: Unknown result type (might be due to invalid IL or missing references)
//IL_023c: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
Page obj = Page.Root.CreatePage("HAHOOS", Color.white, 0, true).CreatePage("KeepInventory", Color.yellow, 0, true);
Page page = obj.CreatePage("Saving", Color.cyan, 0, true);
page.CreateBoolPref("Save Items", Color.white, ref mp_itemsaving, null, null, prefDefaultValue: true);
page.CreateBoolPref("Save Ammo", Color.white, ref mp_ammosaving, null, null, prefDefaultValue: true);
page.CreateBoolPref("Save Gun Data", Color.white, ref mp_saveGunData, null, null, prefDefaultValue: true);
page.CreateBoolPref("Persistent Save", Color.magenta, ref mp_persistentsave, delegate(bool value)
{
if (value)
{
SaveCategory = MelonPreferences.CreateCategory<Save>("KeepInventory_Save", "Keep Inventory Save");
SaveCategory.SetFilePath(Path.Combine(KI_PreferencesDirectory, "Save.cfg"), true, true);
SaveCategory.GetValue<Save>();
CurrentSave = CurrentSave;
}
else
{
CurrentSave = new Save(CurrentSave);
}
}, null, prefDefaultValue: true);
Page obj2 = obj.CreatePage("Events", Color.yellow, 0, true);
obj2.CreateBoolPref("Save on Level Unload", Color.red, ref mp_saveOnLevelUnload, null, null, prefDefaultValue: true);
obj2.CreateBoolPref("Load on Level Load", Color.green, ref mp_loadOnLevelLoad, null, null, prefDefaultValue: true);
obj2.CreateBoolPref("Automatically Save To File", Color.magenta, ref mp_automaticallySaveToFile, delegate(bool value)
{
if (value)
{
SaveCategory = MelonPreferences.CreateCategory<Save>("KeepInventory_Save", "Keep Inventory Save");
SaveCategory.SetFilePath(Path.Combine(KI_PreferencesDirectory, "Save.cfg"), true, true);
SaveCategory.GetValue<Save>();
CurrentSave = CurrentSave;
}
else
{
CurrentSave = new Save(CurrentSave);
}
}, null, prefDefaultValue: true);
obj2.CreateFunction("Save Current Inventory", Color.white, (Action)delegate
{
SaveInventory(notifications: true);
});
obj2.CreateFunction("Load Saved Inventory", Color.white, (Action)LoadSavedInventory);
obj2.CreateFunction("Save The Current Inventory & Save To File", Color.white, (Action)delegate
{
try
{
SaveInventory(notifications: true);
SavePreferences();
BLHelper.SendNotification("Success", "Successfully saved the current inventory to file!", showTitleOnPopup: true, 2f, (NotificationType)3);
}
catch (Exception value6)
{
((MelonBase)this).LoggerInstance.Error($"An unexpected error has occurred while saving the current inventory to file:\n{value6}");
BLHelper.SendNotification("Failure", "Failed to save the current inventory to file, check the logs or console for more details", showTitleOnPopup: true, 5f, (NotificationType)2);
}
});
obj2.CreateFunction("Save To File", Color.white, (Action)delegate
{
try
{
SavePreferences();
BLHelper.SendNotification("Success", "Successfully saved the current save to file!", showTitleOnPopup: true, 2f, (NotificationType)3);
}
catch (Exception value5)
{
((MelonBase)this).LoggerInstance.Error($"An unexpected error has occurred while saving the current save to file:\n{value5}");
BLHelper.SendNotification("Failure", "Failed to save the current save to file, check the logs or console for more details", showTitleOnPopup: true, 5f, (NotificationType)2);
}
});
Page obj3 = obj.CreatePage("Blacklist", Color.red, 0, true);
obj3.CreateBoolPref("Blacklist BONELAB Levels", Color.cyan, ref mp_blacklistBONELABlevels, null, null, prefDefaultValue: true);
statusElement = obj3.CreateFunction("Blacklist Level from Saving/Loading", Color.red, (Action)delegate
{
//IL_0113: 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 (defaultBlacklistedLevels.Contains(levelInfo.barcode))
{
return;
}
List<string> value2 = mp_blacklistedLevels.Value;
if (value2.Contains(levelInfo.barcode))
{
try
{
int num = value2.IndexOf(levelInfo.barcode);
if (num != -1)
{
value2.RemoveAt(num);
((Element)statusElement).ElementName = "Current Level is not blacklisted";
((Element)statusElement).ElementColor = Color.green;
BLHelper.SendNotification("Success", "Successfully unblacklisted current level (" + levelInfo.title + ") from having the inventory saved and/or loaded!", showTitleOnPopup: true, 2.5f, (NotificationType)3);
}
return;
}
catch (Exception value3)
{
((MelonBase)this).LoggerInstance.Error($"An unexpected error has occurred while unblacklisting the current level\n{value3}");
BLHelper.SendNotification("Failure", "An unexpected error has occurred while unblacklisting the current level, check the console or logs for more details", showTitleOnPopup: true, 3f, (NotificationType)2);
return;
}
}
try
{
value2.Add(levelInfo.barcode);
((Element)statusElement).ElementName = "Current Level is blacklisted";
((Element)statusElement).ElementColor = Color.red;
BLHelper.SendNotification("Success", "Successfully blacklisted current level (" + levelInfo.title + ") from having the inventory saved and/or loaded!", showTitleOnPopup: true, 2.5f, (NotificationType)3);
}
catch (Exception value4)
{
((MelonBase)this).LoggerInstance.Error($"An unexpected error has occurred while removing the current level from blacklist\n{value4}");
BLHelper.SendNotification("Failure", "An unexpected error has occurred while blacklisting the current level, check the console or logs for more details", showTitleOnPopup: true, 3f, (NotificationType)2);
}
});
Page page2 = obj.CreatePage("Other", Color.white, 0, true);
page2.CreateBoolPref("Show Notifications", Color.green, ref mp_showNotifications, null, null, prefDefaultValue: true);
page2.CreateBoolPref("Fusion Support", Color.cyan, ref mp_fusionSupport, null, null, prefDefaultValue: true);
page2.CreateBoolPref("Remove Initial Inventory From Save", Color.red, ref mp_initialInventoryRemove, null, null, prefDefaultValue: true);
FunctionElement obj4 = obj.CreateFunction((IsLatestVersion || ThunderstorePackage == null) ? "Current Version: v1.2.0" : ("Current Version: v1.2.0<br>" + "(Update available!)".CreateUnityColor(Color.LimeGreen)), Color.white, (Action)delegate
{
((MelonBase)this).LoggerInstance.Msg("The current version is v1.2.0!!!!");
});
((Element)obj4).SetProperty((ElementProperties)1);
((Element)obj4).SetTooltip("Version of KeepInventory");
}
private void SetupPreferences()
{
if (!Directory.Exists(KI_PreferencesDirectory))
{
((MelonBase)this).LoggerInstance.Msg("Creating preferences directory");
Directory.CreateDirectory(KI_PreferencesDirectory);
}
PrefsCategory = MelonPreferences.CreateCategory("KeepInventory_Settings");
PrefsCategory.SetFilePath(Path.Combine(KI_PreferencesDirectory, "Config.cfg"));
mp_itemsaving = PrefsCategory.CreateEntry<bool>("ItemSaving", true, "Item Saving", "If true, will save and load items in inventory", false, false, (ValueValidator)null, (string)null);
mp_ammosaving = PrefsCategory.CreateEntry<bool>("AmmoSaving", true, "Ammo Saving", "If true, will save and load ammo in inventory", false, false, (ValueValidator)null, (string)null);
mp_saveGunData = PrefsCategory.CreateEntry<bool>("SaveGunData", true, "Save Gun Data", "If true, will save and load data about guns stored in slots, info such as rounds left etc.", false, false, (ValueValidator)null, (string)null);
mp_persistentsave = PrefsCategory.CreateEntry<bool>("PersistentSave", true, "Persistent Save", "If true, will save and load inventory in a KeepInventory_Save.cfg file to be used between sessions", false, false, (ValueValidator)null, (string)null);
mp_saveOnLevelUnload = PrefsCategory.CreateEntry<bool>("SaveOnLevelUnload", true, "Save On Level Unload", "If true, during level unload, the inventory will be automatically saved", false, false, (ValueValidator)null, (string)null);
mp_loadOnLevelLoad = PrefsCategory.CreateEntry<bool>("LoadOnLevelLoad", true, "Load On Level Load", "If true, the saved inventory will be automatically loaded when you get loaded into a level thats not blacklisted", false, false, (ValueValidator)null, (string)null);
mp_automaticallySaveToFile = PrefsCategory.CreateEntry<bool>("AutomaticallySaveToFile", true, "Automatically Save To File", "If true, the inventory will be automatically saved to a save file if 'Persistent Save' is turned on when the game is quitting", false, false, (ValueValidator)null, (string)null);
mp_blacklistBONELABlevels = PrefsCategory.CreateEntry<bool>("BlacklistBONELABLevels", true, "Blacklist BONELAB Levels", "If true, most of the BONELAB levels (except VoidG114 and BONELAB Hub) will be blacklisted from saving/loading inventory", false, false, (ValueValidator)null, (string)null);
mp_blacklistedLevels = PrefsCategory.CreateEntry<List<string>>("BlacklistedLevels", new List<string>(), "Blacklisted Levels", "List of levels that will not save/load inventory", false, false, (ValueValidator)null, (string)null);
mp_showNotifications = PrefsCategory.CreateEntry<bool>("ShowNotifications", true, "Show Notifications", "If true, notifications will be shown in-game regarding errors or other things", false, false, (ValueValidator)null, (string)null);
mp_fusionSupport = PrefsCategory.CreateEntry<bool>("FusionSupport", true, "Fusion Support", "If true, the mod will work with Fusion. If fusion is detected, you are connected to a server and this setting is turned off, the inventory will not be loaded", false, false, (ValueValidator)null, (string)null);
mp_configVersion = PrefsCategory.CreateEntry<int>("ConfigVersion", 1, "Config Version", "DO NOT CHANGE THIS AT ALL, THIS WILL BE USED FOR MIGRATING CONFIGS AND SHOULD NOT BE CHANGED AT ALL", false, false, (ValueValidator)null, (string)null);
mp_initialInventoryRemove = PrefsCategory.CreateEntry<bool>("RemoveInitialInventory", true, "Remove Initial Inventory", "If true, the mod will remove initial inventory found in save data in a loaded inventory", false, false, (ValueValidator)null, (string)null);
PrefsCategory.SaveToFile(false);
if (mp_persistentsave.Value)
{
SaveCategory = MelonPreferences.CreateCategory<Save>("KeepInventory_Save", "Keep Inventory Save");
SaveCategory.SetFilePath(Path.Combine(KI_PreferencesDirectory, "Save.cfg"), true, true);
SaveCategory.SaveToFile(false);
CurrentSave = SaveCategory.GetValue<Save>();
}
else
{
CurrentSave = new Save();
}
}
}
}
namespace KeepInventory.Utilities
{
public static class Colors
{
public static readonly List<Color> SlotColors = new List<Color>(15)
{
Color.BlueViolet,
Color.LightGreen,
Color.Red,
Color.SlateBlue,
Color.Magenta,
Color.Gold,
Color.Azure,
Color.DarkGreen,
Color.Aquamarine,
Color.DarkRed,
Color.Orange,
Color.HotPink,
Color.Purple,
Color.Lime,
Color.Goldenrod
};
private static readonly List<Color> SlotColors_Blacklist = new List<Color>();
public static Color GetRandomSlotColor()
{
if (SlotColors.Count == SlotColors_Blacklist.Count)
{
SlotColors_Blacklist.Clear();
}
Color random;
do
{
random = Extensions.GetRandom<Color>(SlotColors);
}
while (SlotColors_Blacklist.Contains(random));
SlotColors_Blacklist.Add(random);
return random;
}
public static void ResetSlotColorBlacklist()
{
SlotColors_Blacklist.Clear();
}
public static string ToHEX(this Color color)
{
return $"{color.R:X2}{color.G:X2}{color.B:X2}";
}
public static Color FromHex(string hex)
{
if (string.IsNullOrWhiteSpace(hex) || hex.Length < 6)
{
return Color.White;
}
try
{
return ColorTranslator.FromHtml(hex.StartsWith('#') ? hex : ("#" + hex));
}
catch (Exception)
{
return Color.White;
}
}
public static string CreateUnityColor(this string text, Color color)
{
return $"<color=#{color.ToHEX()}>{text}</color>";
}
}
public class Thunderstore
{
public readonly string UserAgent;
public bool IsV1Deprecated;
public Thunderstore(string userAgent)
{
UserAgent = userAgent;
}
public Thunderstore(string userAgent, bool isV1Deprecated)
: this(userAgent)
{
IsV1Deprecated = isV1Deprecated;
}
public Thunderstore()
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
if (executingAssembly != null)
{
AssemblyName name = executingAssembly.GetName();
if (name != null)
{
UserAgent = $"{name.Name} / {name.Version}";
}
}
}
public Thunderstore(bool isV1Deprecated)
{
IsV1Deprecated = isV1Deprecated;
Assembly executingAssembly = Assembly.GetExecutingAssembly();
if (executingAssembly != null)
{
AssemblyName name = executingAssembly.GetName();
if (name != null)
{
UserAgent = $"{name.Name} / {name.Version}";
}
}
}
public Package GetPackage(string @namespace, string name)
{
Task<HttpResponseMessage> async = new HttpClient
{
DefaultRequestHeaders =
{
{ "User-Agent", UserAgent },
{ "Accept", "application/json" }
}
}.GetAsync($"https://thunderstore.io/api/experimental/package/{@namespace}/{name}/");
async.Wait();
HttpResponseMessage httpResponseMessage = async?.Result;
if (async != null && httpResponseMessage != null && async.IsCompletedSuccessfully)
{
if (httpResponseMessage.IsSuccessStatusCode)
{
Task<string> task = httpResponseMessage.Content.ReadAsStringAsync();
task.Wait();
string text = task?.Result;
if (task != null && text != null && task.IsCompletedSuccessfully)
{
Package package = JsonSerializer.Deserialize<Package>(text);
if (!IsV1Deprecated && package != null)
{
V1PackageMetrics packageMetrics = GetPackageMetrics(@namespace, name);
if (packageMetrics != null)
{
package.TotalDownloads = packageMetrics.Downloads;
package.RatingScore = packageMetrics.RatingScore;
}
}
return package;
}
}
else
{
if (IsThunderstoreError(httpResponseMessage))
{
if (IsPackageNotFound(httpResponseMessage))
{
throw new ThunderstorePackageNotFoundException($"Thunderstore could not find a package with name '{name}' & namespace '{@namespace}'", @namespace, name, httpResponseMessage);
}
throw new ThunderstoreErrorException("Thunderstore API has thrown an unexpected error!", httpResponseMessage);
}
httpResponseMessage.EnsureSuccessStatusCode();
}
}
return null;
}
public V1PackageMetrics GetPackageMetrics(string @namespace, string name)
{
if (IsV1Deprecated)
{
return null;
}
Task<HttpResponseMessage> async = new HttpClient
{
DefaultRequestHeaders =
{
{ "User-Agent", UserAgent },
{ "Accept", "application/json" }
}
}.GetAsync($"https://thunderstore.io/api/v1/package-metrics/{@namespace}/{name}/");
async.Wait();
HttpResponseMessage httpResponseMessage = async?.Result;
if (async != null && httpResponseMessage != null && async.IsCompletedSuccessfully)
{
if (httpResponseMessage.IsSuccessStatusCode)
{
Task<string> task = httpResponseMessage.Content.ReadAsStringAsync();
task.Wait();
string text = task?.Result;
if (task != null && text != null && task.IsCompletedSuccessfully)
{
return JsonSerializer.Deserialize<V1PackageMetrics>(text);
}
}
else
{
if (IsThunderstoreError(httpResponseMessage))
{
if (IsPackageNotFound(httpResponseMessage))
{
throw new ThunderstorePackageNotFoundException($"Thunderstore could not find a package with name '{name}' & namespace '{@namespace}'", @namespace, name, httpResponseMessage);
}
throw new ThunderstoreErrorException("Thunderstore API has thrown an unexpected error!", httpResponseMessage);
}
httpResponseMessage.EnsureSuccessStatusCode();
}
}
return null;
}
public PackageVersion GetPackage(string @namespace, string name, string version)
{
Task<HttpResponseMessage> async = new HttpClient
{
DefaultRequestHeaders =
{
{ "User-Agent", UserAgent },
{ "Accept", "application/json" }
}
}.GetAsync($"https://thunderstore.io/api/experimental/package/{@namespace}/{name}/{version}");
async.Wait();
HttpResponseMessage httpResponseMessage = async?.Result;
if (async != null && httpResponseMessage != null && async.IsCompletedSuccessfully)
{
if (httpResponseMessage.IsSuccessStatusCode)
{
Task<string> task = httpResponseMessage.Content.ReadAsStringAsync();
task.Wait();
string text = task?.Result;
if (task != null && text != null && task.IsCompletedSuccessfully)
{
return JsonSerializer.Deserialize<PackageVersion>(text);
}
}
else
{
if (IsThunderstoreError(httpResponseMessage))
{
if (IsPackageNotFound(httpResponseMessage))
{
throw new ThunderstorePackageNotFoundException($"Thunderstore could not find a package with name '{name}', namespace '{@namespace}' & version '{version}'", @namespace, name, version, httpResponseMessage);
}
throw new ThunderstoreErrorException("Thunderstore API has thrown an unexpected error!", httpResponseMessage);
}
httpResponseMessage.EnsureSuccessStatusCode();
}
}
return null;
}
public bool IsLatestVersion(string @namespace, string name, string currentVersion)
{
SemVersion currentVersion2 = default(SemVersion);
if (SemVersion.TryParse(currentVersion, ref currentVersion2, false))
{
return IsLatestVersion(@namespace, name, currentVersion2);
}
return false;
}
public bool IsLatestVersion(string @namespace, string name, Version currentVersion)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Expected O, but got Unknown
return IsLatestVersion(@namespace, name, new SemVersion(currentVersion));
}
public bool IsLatestVersion(string @namespace, string name, SemVersion currentVersion)
{
if (!IsV1Deprecated)
{
return GetPackageMetrics(@namespace, name)?.IsLatestVersion(currentVersion) ?? false;
}
return GetPackage(@namespace, name)?.IsLatestVersion(currentVersion) ?? false;
}
private static bool IsPackageNotFound(HttpResponseMessage response)
{
if (response.StatusCode != HttpStatusCode.NotFound)
{
return false;
}
Task<string> task = response.Content.ReadAsStringAsync();
task.Wait();
string result = task.Result;
if (string.IsNullOrWhiteSpace(result))
{
return false;
}
ThunderstoreErrorResponse thunderstoreErrorResponse;
try
{
thunderstoreErrorResponse = JsonSerializer.Deserialize<ThunderstoreErrorResponse>(result);
}
catch (JsonException)
{
return false;
}
if (thunderstoreErrorResponse != null)
{
return string.Equals(thunderstoreErrorResponse.Details, "Not found.", StringComparison.OrdinalIgnoreCase);
}
return false;
}
private static bool IsThunderstoreError(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
return false;
}
Task<string> task = response.Content.ReadAsStringAsync();
task.Wait();
string result = task.Result;
if (string.IsNullOrWhiteSpace(result))
{
return false;
}
ThunderstoreErrorResponse thunderstoreErrorResponse;
try
{
thunderstoreErrorResponse = JsonSerializer.Deserialize<ThunderstoreErrorResponse>(result);
}
catch (JsonException)
{
return false;
}
if (thunderstoreErrorResponse != null)
{
return !string.IsNullOrWhiteSpace(thunderstoreErrorResponse.Details);
}
return false;
}
}
public class Package
{
[JsonPropertyName("namespace")]
[JsonInclude]
public string Namespace { get; internal set; }
[JsonPropertyName("name")]
[JsonInclude]
public string Name { get; internal set; }
[JsonPropertyName("full_name")]
[JsonInclude]
public string FullName { get; internal set; }
[JsonPropertyName("owner")]
[JsonInclude]
public string Owner { get; internal set; }
[JsonPropertyName("package_url")]
[JsonInclude]
public string PackageUrl { get; internal set; }
[JsonPropertyName("date_created")]
[JsonInclude]
public DateTime CreatedAt { get; internal set; }
[JsonPropertyName("date_updated")]
[JsonInclude]
public DateTime UpdatedAt { get; internal set; }
[JsonPropertyName("rating_score")]
[JsonInclude]
public int RatingScore { get; internal set; }
[JsonPropertyName("is_pinned")]
[JsonInclude]
public bool IsPinned { get; internal set; }
[JsonPropertyName("is_deprecated")]
[JsonInclude]
public bool IsDeprecated { get; internal set; }
[JsonPropertyName("total_downloads")]
[JsonInclude]
public int TotalDownloads { get; internal set; }
[JsonPropertyName("latest")]
[JsonInclude]
public PackageVersion Latest { get; internal set; }
[JsonPropertyName("community_listings")]
[JsonInclude]
public PackageListing[] CommunityListings { get; internal set; }
public bool IsLatestVersion(string current)
{
if (string.IsNullOrWhiteSpace(current))
{
return false;
}
if (Latest == null || Latest.SemVersion == (SemVersion)null)
{
return false;
}
SemVersion val = default(SemVersion);
if (SemVersion.TryParse(current, ref val, false))
{
return val >= Latest.SemVersion;
}
return false;
}
public bool IsLatestVersion(SemVersion current)
{
if (current == (SemVersion)null)
{
return false;
}
if (Latest == null || Latest.SemVersion == (SemVersion)null)
{
return false;
}
return current >= Latest.SemVersion;
}
public bool IsLatestVersion(Version current)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
if (current == null)
{
return false;
}
if (Latest == null || Latest.SemVersion == (SemVersion)null)
{
return false;
}
return new SemVersion(current) >= Latest.SemVersion;
}
}
public class PackageVersion
{
[JsonPropertyName("namespace")]
[JsonInclude]
public string Namespace { get; internal set; }
[JsonPropertyName("name")]
[JsonInclude]
public string Name { get; internal set; }
[JsonPropertyName("version_number")]
[JsonInclude]
public string Version
{
get
{
return ((object)SemVersion).ToString();
}
internal set
{
SemVersion = SemVersion.Parse(value, false);
}
}
[JsonIgnore]
public SemVersion SemVersion { get; internal set; }
[JsonPropertyName("full_name")]
[JsonInclude]
public string FullName { get; internal set; }
[JsonPropertyName("description")]
[JsonInclude]
public string Description { get; internal set; }
[JsonPropertyName("icon")]
[JsonInclude]
public string Icon { get; internal set; }
[JsonPropertyName("dependencies")]
[JsonInclude]
public List<string> Dependencies { get; internal set; }
[JsonPropertyName("download_url")]
[JsonInclude]
public string DownloadUrl { get; internal set; }
[JsonPropertyName("date_created")]
[JsonInclude]
public DateTime CreatedAt { get; internal set; }
[JsonPropertyName("downloads")]
[JsonInclude]
public int Downloads { get; internal set; }
[JsonPropertyName("website_url")]
[JsonInclude]
public string WebsiteURL { get; internal set; }
[JsonPropertyName("is_active")]
[JsonInclude]
public bool IsActive { get; internal set; }
}
public class PackageListing
{
public enum ReviewStatusEnum
{
UNREVIEWED,
APPROVED,
REJECTED
}
[JsonPropertyName("has_nsfw_content")]
[JsonInclude]
public bool HasNSFWContent { get; internal set; }
[JsonPropertyName("categories")]
[JsonInclude]
public List<string> Categories { get; internal set; }
[JsonPropertyName("community")]
[JsonInclude]
public string Community { get; internal set; }
[JsonPropertyName("review_status")]
[JsonInclude]
public string ReviewStatusString
{
get
{
return ReviewStatus.ToString();
}
internal set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (string.Equals(value, "unreviewed", StringComparison.OrdinalIgnoreCase))
{
ReviewStatus = ReviewStatusEnum.UNREVIEWED;
}
else if (string.Equals(value, "approved", StringComparison.OrdinalIgnoreCase))
{
ReviewStatus = ReviewStatusEnum.APPROVED;
}
else if (string.Equals(value, "rejected", StringComparison.OrdinalIgnoreCase))
{
ReviewStatus = ReviewStatusEnum.REJECTED;
}
}
}
[JsonIgnore]
public ReviewStatusEnum ReviewStatus { get; internal set; }
}
public class V1PackageMetrics
{
[JsonPropertyName("downloads")]
[JsonInclude]
public int Downloads { get; internal set; }
[JsonPropertyName("rating_score")]
[JsonInclude]
public int RatingScore { get; internal set; }
[JsonPropertyName("latest_version")]
[JsonInclude]
public string LatestVersion
{
get
{
return ((object)LatestSemVersion).ToString();
}
internal set
{
LatestSemVersion = SemVersion.Parse(value, false);
}
}
[JsonIgnore]
public SemVersion LatestSemVersion { get; internal set; }
public bool IsLatestVersion(string current)
{
if (string.IsNullOrWhiteSpace(current))
{
return false;
}
if (LatestSemVersion == (SemVersion)null)
{
return false;
}
SemVersion val = default(SemVersion);
if (SemVersion.TryParse(current, ref val, false))
{
return val >= LatestSemVersion;
}
return false;
}
public bool IsLatestVersion(SemVersion current)
{
if (current == (SemVersion)null)
{
return false;
}
if (LatestSemVersion == (SemVersion)null)
{
return false;
}
return current >= LatestSemVersion;
}
public bool IsLatestVersion(Version current)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
if (current == null)
{
return false;
}
if (LatestSemVersion == (SemVersion)null)
{
return false;
}
return new SemVersion(current) >= LatestSemVersion;
}
}
public class ThunderstoreErrorResponse
{
[JsonPropertyName("detail")]
[JsonInclude]
public string Details { get; internal set; }
}
public class ThunderstoreErrorException : Exception
{
public string Details { get; }
public HttpStatusCode HttpStatusCode { get; }
public ThunderstoreErrorException()
{
}
public ThunderstoreErrorException(string message)
: base(message)
{
}
public ThunderstoreErrorException(string message, Exception innerException)
: base(message, innerException)
{
}
public ThunderstoreErrorException(string message, string details, HttpStatusCode httpStatusCode, Exception innerException)
: base(message, innerException)
{
Details = details;
HttpStatusCode = httpStatusCode;
}
public ThunderstoreErrorException(string message, HttpResponseMessage response)
: base(message)
{
if (response.IsSuccessStatusCode)
{
return;
}
HttpStatusCode = response.StatusCode;
Task<string> task = response.Content.ReadAsStringAsync();
task.Wait();
string result = task.Result;
if (string.IsNullOrWhiteSpace(result))
{
Details = string.Empty;
return;
}
ThunderstoreErrorResponse thunderstoreErrorResponse;
try
{
thunderstoreErrorResponse = JsonSerializer.Deserialize<ThunderstoreErrorResponse>(result);
}
catch (JsonException)
{
Details = string.Empty;
return;
}
if (thunderstoreErrorResponse != null)
{
Details = thunderstoreErrorResponse.Details;
}
}
}
public class ThunderstorePackageNotFoundException : ThunderstoreErrorException
{
public string Namespace { get; }
public string Name { get; }
public string Version { get; }
public ThunderstorePackageNotFoundException(string message, string @namespace, string name, string details, HttpStatusCode httpStatusCode, Exception innerException)
: base(message, details, httpStatusCode, innerException)
{
Namespace = @namespace;
Name = name;
}
public ThunderstorePackageNotFoundException(string message, string @namespace, string name, string version, string details, HttpStatusCode httpStatusCode, Exception innerException)
: base(message, details, httpStatusCode, innerException)
{
Namespace = @namespace;
Name = name;
Version = version;
}
public ThunderstorePackageNotFoundException(string message, string @namespace, string name, HttpResponseMessage response)
: base(message, response)
{
Namespace = @namespace;
Name = name;
}
public ThunderstorePackageNotFoundException(string message, string @namespace, string name, string version, HttpResponseMessage response)
: base(message, response)
{
Namespace = @namespace;
Name = name;
Version = version;
}
public ThunderstorePackageNotFoundException()
{
}
public ThunderstorePackageNotFoundException(string message)
: base(message)
{
}
public ThunderstorePackageNotFoundException(string message, Exception innerException)
: base(message, innerException)
{
}
public ThunderstorePackageNotFoundException(string message, string details, HttpStatusCode httpStatusCode, Exception innerException)
: base(message, details, httpStatusCode, innerException)
{
}
public ThunderstorePackageNotFoundException(string message, HttpResponseMessage response)
: base(message, response)
{
}
}
}
namespace KeepInventory.Saves
{
[JsonSourceGenerationOptions(WriteIndented = false)]
public class GunInfo
{
[JsonPropertyName("IsMag")]
public bool IsMag { get; set; }
[JsonPropertyName("IsBulletInChamber")]
public bool IsBulletInChamber { get; set; }
[JsonPropertyName("FireMode")]
public FireMode FireMode { get; set; }
[JsonPropertyName("RoundsLeft")]
public int RoundsLeft { get; set; }
[JsonPropertyName("HammerState")]
public HammerStates HammerState { get; set; }
[JsonPropertyName("SlideState")]
public SlideStates SlideState { get; set; }
[JsonPropertyName("CartridgeState")]
public CartridgeStates CartridgeState { get; set; }
[JsonPropertyName("HasFiredOnce")]
public bool HasFiredOnce { get; set; }
[JsonConstructor]
public GunInfo()
{
}
public static GunInfo Parse(Gun gun)
{
//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)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
GunInfo gunInfo = new GunInfo
{
IsMag = gun.HasMagazine(),
IsBulletInChamber = ((Object)(object)gun.chamberedCartridge != (Object)null),
FireMode = gun.fireMode,
HammerState = gun.hammerState,
SlideState = gun.slideState,
HasFiredOnce = gun.hasFiredOnce,
CartridgeState = gun.cartridgeState
};
if (gun.MagazineState != null)
{
gunInfo.RoundsLeft = gun.MagazineState.AmmoCount;
}
return gunInfo;
}
public MagazineData GetMagazineData(Gun gun)
{
//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)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
return new MagazineData
{
spawnable = gun.defaultMagazine.spawnable,
rounds = RoundsLeft,
platform = gun.defaultMagazine.platform
};
}
public string Serialize()
{
return JsonSerializer.Serialize(this, new JsonSerializerOptions
{
WriteIndented = false
});
}
public static string Serialize(GunInfo gunInfo)
{
return JsonSerializer.Serialize(gunInfo, new JsonSerializerOptions
{
WriteIndented = false
});
}
public static GunInfo Deserialize(string json)
{
return JsonSerializer.Deserialize<GunInfo>(json);
}
}
public class Save
{
[TomlPrecedingComment("The version of the save")]
public int Version = 1;
[TomlPrecedingComment("The amount of light ammo left")]
public int LightAmmo;
[TomlPrecedingComment("The amount of medium ammo left")]
public int MediumAmmo;
[TomlPrecedingComment("The amount of heavy ammo left")]
public int HeavyAmmo;
[TomlPrecedingComment("List of all slots & the spawnables stored in them")]
public List<SaveSlot> InventorySlots = new List<SaveSlot>();
public Save()
{
}
public Save(Save old)
{
LightAmmo = old.LightAmmo;
MediumAmmo = old.MediumAmmo;
HeavyAmmo = old.HeavyAmmo;
InventorySlots = new List<SaveSlot>(old.InventorySlots);
}
}
public class SaveSlot
{
public enum SpawnableType
{
Gun,
Other
}
public string SlotName { get; set; }
public string Barcode { get; set; }
public SpawnableType Type { get; set; }
[TomlNonSerialized]
public GunInfo GunInfo { get; set; }
[TomlProperty("GunInfo")]
public string GunInfo_JSON
{
get
{
return JsonSerializer.Serialize(GunInfo, new JsonSerializerOptions
{
WriteIndented = false
});
}
set
{
if (!string.IsNullOrWhiteSpace(value) && value != "null" && IsJSON(value))
{
GunInfo = JsonSerializer.Deserialize<GunInfo>(value);
}
}
}
public SaveSlot()
{
}
public SaveSlot(string slotName, Barcode barcode)
{
SlotName = slotName;
Barcode = barcode.ID;
Type = SpawnableType.Other;
GunInfo = null;
}
public SaveSlot(string slotName, Barcode barcode, SpawnableType type)
{
SlotName = slotName;
Barcode = barcode.ID;
Type = type;
GunInfo = null;
}
public SaveSlot(string slotName, Barcode barcode, SpawnableType type, GunInfo gunInfo)
{
SlotName = slotName;
Barcode = barcode.ID;
Type = type;
GunInfo = gunInfo;
}
public SaveSlot(string slotName, Barcode barcode, SpawnableType type, string gunInfoJSON)
{
SlotName = slotName;
Barcode = barcode.ID;
Type = type;
GunInfo_JSON = gunInfoJSON;
}
public SaveSlot(string slotName, Barcode barcode, GunInfo gunInfo)
{
SlotName = slotName;
Barcode = barcode.ID;
Type = SpawnableType.Gun;
GunInfo = gunInfo;
}
public SaveSlot(string slotName, Barcode barcode, string gunInfoJSON)
{
SlotName = slotName;
Barcode = barcode.ID;
Type = SpawnableType.Gun;
GunInfo_JSON = gunInfoJSON;
}
private static bool IsJSON(string text)
{
try
{
using (JsonDocument.Parse(text))
{
return true;
}
}
catch (JsonException)
{
return false;
}
}
}
}
namespace KeepInventory.Patches
{
[HarmonyPatch(typeof(AmmoInventory))]
public static class AmmoInventoryPatches
{
[HarmonyPatch("Awake")]
[HarmonyPostfix]
[HarmonyPriority(0)]
public static void Awake(AmmoInventory __instance)
{
if (Core.LoadAmmoOnAwake && Core.mp_ammosaving.Value && !((Object)(object)__instance != (Object)(object)Core.GetAmmoInventory()))
{
Core.LoadAmmoOnAwake = false;
Core.AddSavedAmmo(Core.mp_showNotifications.Value);
}
}
}
}
namespace KeepInventory.Helper
{
internal static class BLHelper
{
private static readonly MelonPreferences_Category prefs = Core.PrefsCategory;
internal static IntElement CreateIntPref(this Page page, string name, Color color, ref MelonPreferences_Entry<int> value, int increment, int minValue, int maxValue, Action<int> callback = null, string prefName = null, int prefDefaultValue = 0)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (value == null || !prefs.HasEntry(((MelonPreferences_Entry)value).Identifier))
{
if (prefName == null)
{
prefName = name;
}
if (!prefs.HasEntry(prefName))
{
value = prefs.CreateEntry<int>(prefName, prefDefaultValue, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
}
}
MelonPreferences_Entry<int> val = value;
IntElement val2 = page.CreateInt(name, color, val.Value, increment, minValue, maxValue, (Action<int>)delegate(int x)
{
val.Value = x;
prefs.SaveToFile(false);
Action<int> action = callback;
if (action != null)
{
Extensions.InvokeActionSafe<int>(action, x);
}
});
if (string.IsNullOrWhiteSpace(((MelonPreferences_Entry)value).Description))
{
((Element)val2).SetTooltip(((MelonPreferences_Entry)value).Description);
}
return val2;
}
internal static FloatElement CreateFloatPref(this Page page, string name, Color color, ref MelonPreferences_Entry<float> value, float increment, float minValue, float maxValue, Action<float> callback = null, string prefName = null, float prefDefaultValue = 0f)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (value == null || !prefs.HasEntry(((MelonPreferences_Entry)value).Identifier))
{
if (prefName == null)
{
prefName = name;
}
if (!prefs.HasEntry(prefName))
{
value = prefs.CreateEntry<float>(prefName, prefDefaultValue, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
}
}
MelonPreferences_Entry<float> val = value;
FloatElement val2 = page.CreateFloat(name, color, val.Value, increment, minValue, maxValue, (Action<float>)delegate(float x)
{
val.Value = x;
prefs.SaveToFile(false);
Action<float> action = callback;
if (action != null)
{
Extensions.InvokeActionSafe<float>(action, x);
}
});
if (string.IsNullOrWhiteSpace(((MelonPreferences_Entry)value).Description))
{
((Element)val2).SetTooltip(((MelonPreferences_Entry)value).Description);
}
return val2;
}
internal static BoolElement CreateBoolPref(this Page page, string name, Color color, ref MelonPreferences_Entry<bool> value, Action<bool> callback = null, string prefName = null, bool prefDefaultValue = false)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (value == null || !prefs.HasEntry(((MelonPreferences_Entry)value).Identifier))
{
if (prefName == null)
{
prefName = name;
}
if (!prefs.HasEntry(prefName))
{
value = prefs.CreateEntry<bool>(prefName, prefDefaultValue, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
}
}
MelonPreferences_Entry<bool> val = value;
BoolElement val2 = page.CreateBool(name, color, val.Value, (Action<bool>)delegate(bool x)
{
val.Value = x;
prefs.SaveToFile(false);
Action<bool> action = callback;
if (action != null)
{
Extensions.InvokeActionSafe<bool>(action, x);
}
});
if (string.IsNullOrWhiteSpace(((MelonPreferences_Entry)value).Description))
{
((Element)val2).SetTooltip(((MelonPreferences_Entry)value).Description);
}
return val2;
}
internal static EnumElement CreateEnumPref<T>(this Page page, string name, Color color, ref MelonPreferences_Entry<T> value, Action<Enum> callback = null, string prefName = null, Enum prefDefaultValue = null) where T : Enum
{
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
if (value == null || !prefs.HasEntry(((MelonPreferences_Entry)value).Identifier))
{
if (prefName == null)
{
prefName = name;
}
if (!prefs.HasEntry(prefName))
{
value = prefs.CreateEntry<T>(prefName, (T)prefDefaultValue, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
}
}
MelonPreferences_Entry<T> val = value;
EnumElement val2 = page.CreateEnum(name, color, (Enum)val.Value, (Action<Enum>)delegate(Enum x)
{
val.Value = (T)x;
prefs.SaveToFile(false);
Action<Enum> action = callback;
if (action != null)
{
Extensions.InvokeActionSafe<Enum>(action, x);
}
});
if (string.IsNullOrWhiteSpace(((MelonPreferences_Entry)value).Description))
{
((Element)val2).SetTooltip(((MelonPreferences_Entry)value).Description);
}
return val2;
}
internal static StringElement CreateStringPref(this Page page, string name, Color color, ref MelonPreferences_Entry<string> value, Action<string> callback = null, string prefName = null, string prefDefaultValue = null)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (value == null || !prefs.HasEntry(((MelonPreferences_Entry)value).Identifier))
{
if (prefName == null)
{
prefName = name;
}
if (!prefs.HasEntry(prefName))
{
value = prefs.CreateEntry<string>(prefName, prefDefaultValue, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
}
}
MelonPreferences_Entry<string> val = value;
StringElement val2 = page.CreateString(name, color, val.Value, (Action<string>)delegate(string x)
{
val.Value = x;
prefs.SaveToFile(false);
Action<string> action = callback;
if (action != null)
{
Extensions.InvokeActionSafe<string>(action, x);
}
});
val2.Value = value.Value;
if (string.IsNullOrWhiteSpace(((MelonPreferences_Entry)value).Description))
{
((Element)val2).SetTooltip(((MelonPreferences_Entry)value).Description);
}
return val2;
}
internal static void SendNotification(string title, string message, bool showTitleOnPopup = false, float popupLength = 2f, NotificationType type = 0, Texture2D customIcon = null)
{
//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)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: 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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Expected O, but got Unknown
MelonPreferences_Entry<bool> mp_showNotifications = Core.mp_showNotifications;
if (mp_showNotifications != null && mp_showNotifications.Value)
{
Notifier.Send(new Notification
{
Title = new NotificationText("KeepInventory | " + title, Color.white, true),
Message = new NotificationText(message, Color.white, true),
ShowTitleOnPopup = showTitleOnPopup,
CustomIcon = customIcon,
PopupLength = popupLength,
Type = type
});
}
}
internal static void SendNotification(NotificationText title, NotificationText message, bool showTitleOnPopup = false, float popupLength = 2f, NotificationType type = 0, Texture2D customIcon = null)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: 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_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
title.Text = "KeepInventory | " + title.Text;
MelonPreferences_Entry<bool> mp_showNotifications = Core.mp_showNotifications;
if (mp_showNotifications != null && mp_showNotifications.Value)
{
Notifier.Send(new Notification
{
Title = title,
Message = message,
ShowTitleOnPopup = showTitleOnPopup,
CustomIcon = customIcon,
PopupLength = popupLength,
Type = type
});
}
}
internal static void SendNotification(Notification notification)
{
MelonPreferences_Entry<bool> mp_showNotifications = Core.mp_showNotifications;
if (mp_showNotifications != null && mp_showNotifications.Value)
{
Notifier.Send(notification);
}
}
}
public static class GunHelper
{
public static void SendFusionMessage(Gun gun, GunInfo info, Color slotColor, SaveSlot slot = null, string name = "N/A", string barcode = "N/A", bool printMessages = true)
{
if (Core.IsConnected)
{
FusionMethods.SendFusionMessage(gun, info);
}
else
{
gun.UpdateProperties(info, slotColor, slot, name, barcode, printMessages, fusionMessage: true);
}
}
public static void UpdateProperties(this Gun gun, GunInfo info, Color slotColor, SaveSlot slot = null, string name = "N/A", string barcode = "N/A", bool printMessages = true, bool fusionMessage = false)
{
string slotName = ((slot == null) ? "N/A" : (string.IsNullOrWhiteSpace(slot.SlotName) ? "N/A" : slot.SlotName));
if ((Object)(object)gun == (Object)null || info == null)
{
return;
}
if (Core.HasFusion && Core.IsConnected && !fusionMessage)
{
if (!Core.IsFusionLibraryInitialized || !Core.mp_fusionSupport.Value)
{
Core.Logger.Warning("[" + slotName + "] The Fusion Library is not loaded or the setting 'Fusion Support' is set to Disabled. To update gun properties in Fusion servers, check if you have the Fusion Library in UserData > KeepInventory (there should be a file called 'KeepInventory.Fusion.dll') or try enabling 'Fusion Support' in settings");
return;
}
if (printMessages)
{
Core.MsgPrefix("Sending request to host to edit gun data for everyone", slotName, slotColor);
}
SendFusionMessage(gun, info, slotColor, slot, name, barcode, printMessages);
}
else
{
if (!((Object)(object)gun != (Object)null))
{
return;
}
if (printMessages)
{
Core.MsgPrefix($"Writing gun info for: {name} ({barcode})", slotName, slotColor);
}
if (info.IsMag && (Object)(object)gun.defaultMagazine != (Object)null && (Object)(object)gun.defaultCartridge != (Object)null)
{
if (printMessages)
{
Core.MsgPrefix("Loading magazine", slotName, slotColor);
}
MagazineData magazineData = info.GetMagazineData(gun);
object obj;
if (magazineData == null)
{
obj = null;
}
else
{
Spawnable spawnable = magazineData.spawnable;
obj = ((spawnable != null) ? spawnable.crateRef : null);
}
if (obj != null && !string.IsNullOrWhiteSpace(magazineData.platform))
{
gun.ammoSocket.ForceLoadAsync(info.GetMagazineData(gun)).GetAwaiter().OnCompleted(Action.op_Implicit((Action)something));
return;
}
if (printMessages)
{
Core.Logger.Warning("[" + slotName + "] Could not get sufficient information for MagazineData, not loading the magazine and rounds left");
}
other();
}
else
{
other();
}
}
void other()
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: 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_024e: Unknown result type (might be due to invalid IL or missing references)
//IL_0253: Unknown result type (might be due to invalid IL or missing references)
//IL_0254: Unknown result type (might be due to invalid IL or missing references)
//IL_026e: Expected I4, but got Unknown
//IL_023e: Unknown result type (might be due to invalid IL or missing references)
//IL_0210: Unknown result type (might be due to invalid IL or missing references)
if (printMessages)
{
Core.MsgPrefix($"Setting fire mode value to {info.FireMode}", slotName, slotColor);
}
gun.fireMode = info.FireMode;
if (printMessages)
{
Core.MsgPrefix($"Setting 'HasFiredOnce' value to {info.HasFiredOnce}", slotName, slotColor);
}
gun.hasFiredOnce = info.HasFiredOnce;
if (printMessages)
{
Core.MsgPrefix($"Setting hammer state to {info.HammerState}", slotName, slotColor);
}
gun.hammerState = info.HammerState;
if (printMessages)
{
Core.MsgPrefix($"Setting slide state to {info.SlideState}", slotName, slotColor);
}
gun.slideState = info.SlideState;
if (!gun.isCharged && info.IsBulletInChamber)
{
if (printMessages)
{
Core.MsgPrefix("Charging gun", slotName, slotColor);
}
gun.Charge();
if (gun._hasMagState)
{
gun.MagazineState.AddCartridge(1, gun.defaultCartridge);
}
if (printMessages)
{
Core.MsgPrefix($"Setting cartridge state to {info.CartridgeState}", slotName, slotColor);
}
gun.cartridgeState = info.CartridgeState;
}
SlideStates slideState = info.SlideState;
switch ((int)slideState)
{
case 4:
gun.SlideLocked();
break;
case 2:
gun.CompleteSlidePull();
break;
case 0:
gun.CompleteSlideReturn();
break;
}
if (printMessages)
{
Core.MsgPrefix($"Spawned to slot: {name} ({barcode})", slotName, slotColor);
}
}
void something()
{
gun.MagazineState.SetCartridge(info.RoundsLeft);
other();
}
}
}
public static class MelonLoggerHelper
{
internal static readonly Color DefaultTextColor = Color.LightGray;
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UseMLMsgPastel(Instance logger, Color textColor, string text)
{
if (logger != null)
{
if (textColor == DefaultTextColor)
{
logger.MsgPastel(text);
}
else
{
logger.MsgPastel(ConsoleExtensions.Pastel(text, textColor));
}
}
}
private static void Internal_MsgPastel(Instance logger, Color textColor, string text)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
//IL_0062: Expected O, but got Unknown
if (Core.MLAssembly == null)
{
return;
}
Version version = Core.MLAssembly.GetName().Version;
if (logger != null && !string.IsNullOrWhiteSpace(text))
{
if (new SemVersion(version.Major, version.Minor, version.Build, "", "") >= new SemVersion(0, 6, 5, "", ""))
{
UseMLMsgPastel(logger, textColor, text);
}
else if (textColor == DefaultTextColor)
{
logger.Msg(text);
}
else
{
logger.Msg(textColor, text);
}
}
}
public static void _MsgPastel(this Instance logger, object obj)
{
Internal_MsgPastel(logger, DefaultTextColor, obj.ToString());
}
public static void _MsgPastel(this Instance logger, string txt)
{
Internal_MsgPastel(logger, DefaultTextColor, txt);
}
public static void _MsgPastel(this Instance logger, string txt, params object[] args)
{
Internal_MsgPastel(logger, DefaultTextColor, string.Format(txt, args));
}
public static void _MsgPastel(this Instance logger, Color txt_color, object obj)
{
Internal_MsgPastel(logger, txt_color, obj.ToString());
}
public static void _MsgPastel(this Instance logger, Color txt_color, string txt)
{
Internal_MsgPastel(logger, txt_color, txt);
}
public static void _MsgPastel(this Instance logger, Color txt_color, string txt, params object[] args)
{
Internal_MsgPastel(logger, txt_color, string.Format(txt, args));
}
}
}