using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using AzuExtendedPlayerInventory; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: AssemblyTitle("QuickStackStore")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("QuickStackStore")] [assembly: AssemblyCopyright("Copyright © Goldenrevolver 2022")] [assembly: AssemblyTrademark("")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: ComVisible(false)] [assembly: Guid("beeb50d8-ebd2-4791-9866-4bbf2d810422")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyFileVersion("1.4.13.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.13.0")] [module: UnverifiableCode] namespace QuickStackStore { [BepInIncompatibility("virtuacode.valheim.trashitems")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("goldenrevolver.quick_stack_store", "Quick Stack - Store - Sort - Trash - Restock", "1.4.13")] public class QuickStackStorePlugin : BaseUnityPlugin { public const string GUID = "goldenrevolver.quick_stack_store"; public const string NAME = "Quick Stack - Store - Sort - Trash - Restock"; public const string VERSION = "1.4.13"; protected void Start() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (CompatibilitySupport.HasOutdatedMUCPlugin()) { Helper.LogO("This mod is not compatible with versions of Multi User Chest earlier than 0.4.0, aborting start"); return; } if (API.IsLoaded()) { CompatibilitySupport.isUsingAzuEPIWithAPI = true; if (CompatibilitySupport.HasAzuEPIWithQuickslotCompatibleAPI()) { CompatibilitySupport.isUsingAzuEPIWithQuickslotCompatibleAPI = true; } } string text = "QuickStackStore.Resources"; BorderRenderer.border = Helper.LoadSprite(text + ".border.png", new Rect(0f, 0f, 1024f, 1024f)); TrashModule.trashSprite = Helper.LoadSprite(text + ".trash.png", new Rect(0f, 0f, 64f, 64f)); TrashModule.bgSprite = Helper.LoadSprite(text + ".trashmask.png", new Rect(0f, 0f, 96f, 112f)); QSSConfig.LoadConfig((BaseUnityPlugin)(object)this); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "goldenrevolver.quick_stack_store"); } } [HarmonyPatch(typeof(FejdStartup))] internal class FejdStartupPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void FejdStartupAwakePatch() { LocalizationLoader.SetupTranslations(); QSSConfig.ConfigTemplate_SettingChanged(null, null); } } internal sealed class ConfigurationManagerAttributes { public bool? ShowRangeAsPercent; public Action CustomDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func ObjToStr; public Func StrToObj; internal static ConfigDescription CustomDisplay(string category, string displayName, string description, AcceptableValueBase acceptableValues = null) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown return new ConfigDescription(description, acceptableValues, new object[1] { new ConfigurationManagerAttributes { Category = category, DispName = displayName } }); } internal static ConfigDescription CustomCategory(string category, AcceptableValueBase acceptableValues = null) { return CustomCategoryWithDescription(category, string.Empty, acceptableValues); } internal static ConfigDescription CustomCategoryWithDescription(string category, string description, AcceptableValueBase acceptableValues = null) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown return new ConfigDescription(description, acceptableValues, new object[1] { new ConfigurationManagerAttributes { Category = category } }); } internal static ConfigDescription MUCSettingDisplay(string overwriteName, string category, string description, AcceptableValueBase acceptableValues = null) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown if (CompatibilitySupport.HasPlugin("com.maxsch.valheim.MultiUserChest")) { return new ConfigDescription("Area quick stacking and area restocking is always allowed while using 'Multi User Chest'.", acceptableValues, new object[1] { new ConfigurationManagerAttributes { DispName = overwriteName, Category = category, ReadOnly = true, CustomDrawer = delegate { CustomLabelDrawer("Enabled ('Multi User Chest' is installed)"); } } }); } return CustomCategoryWithDescription(category, description, acceptableValues); } internal static ConfigDescription HiddenDisplay(Func condition, string description, AcceptableValueBase acceptableValues = null) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown if (condition()) { return new ConfigDescription(description, acceptableValues, new object[1] { new ConfigurationManagerAttributes { Browsable = false, ReadOnly = true } }); } return new ConfigDescription(description, acceptableValues, Array.Empty()); } internal static ConfigDescription HiddenTrashingDisplay(string description, AcceptableValueBase acceptableValues = null) { return HiddenDisplay(CompatibilitySupport.DisallowAllTrashCanFeatures, description, acceptableValues); } internal static ConfigDescription TrashingCategoryHideNotificationDisplay(string description, AcceptableValueBase acceptableValues = null) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown if (CompatibilitySupport.DisallowAllTrashCanFeatures()) { return new ConfigDescription("Force disabled due to using other mod that adds trashing/ recycling", acceptableValues, new object[1] { new ConfigurationManagerAttributes { DispName = "Trashing", ReadOnly = true, CustomDrawer = delegate { CustomLabelDrawer("Force disabled for compatibility reasons"); } } }); } return new ConfigDescription(description, acceptableValues, Array.Empty()); } internal static ConfigDescription ForceEnabledDisplay(Func condition, string description, AcceptableValueBase acceptableValues = null) { return SeeOnlyDisplay(condition, description, "Force enabled for better compatibility with one of your installed mods. " + description, "Force enabled for compatibility reasons", acceptableValues); } internal static ConfigDescription ForceDisabledDisplay(Func condition, string description, AcceptableValueBase acceptableValues = null) { return SeeOnlyDisplay(condition, description, "Force disabled for better compatibility with one of your installed mods. " + description, "Force disabled for compatibility reasons", acceptableValues); } internal static ConfigDescription SeeOnlyDisplay(Func condition, string description, string overwriteDescription, string overwriteLabel, AcceptableValueBase acceptableValues = null) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown if (condition()) { return new ConfigDescription(overwriteDescription, acceptableValues, new object[1] { new ConfigurationManagerAttributes { ReadOnly = true, CustomDrawer = delegate { CustomLabelDrawer(overwriteLabel); } } }); } return new ConfigDescription(description, acceptableValues, Array.Empty()); } private static void CustomLabelDrawer(string labelText) { GUILayout.Label(labelText, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } } internal class LocalizationLoader { private const string keyPrefix = "quickstackstore_"; public static string[] supportedEmbeddedLanguages = new string[10] { "English", "Chinese", "Russian", "French", "Portuguese_Brazilian", "Polish", "Swedish", "Korean", "Italian", "Ukrainian" }; private const string embeddedLanguagePathFormat = "QuickStackStore.Translations.QuickStackStore.{0}.json"; private const string loadingLog = "Loading {0} translation file for language: {1}"; private const string failedLoadLog = "Failed loading {0} translation file for language: {1}"; private const string external = "external"; private const string embedded = "embedded"; internal static void SetupTranslations() { string selectedLanguage = Localization.instance.GetSelectedLanguage(); LocalizationConfig.FixTakeAllDefaultText(Localization.instance, selectedLanguage); string[] files = Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), "QuickStackStore.*.json", SearchOption.AllDirectories); bool flag = false; string[] array = files; foreach (string path in array) { string text = Path.GetFileNameWithoutExtension(path).Split(new char[1] { '.' })[1]; if (text == selectedLanguage) { Helper.Log(string.Format("Loading {0} translation file for language: {1}", "external", selectedLanguage), QSSConfig.DebugSeverity.Everything); if (!LoadExternalLanguageFile(selectedLanguage, path)) { Helper.LogO(string.Format("Failed loading {0} translation file for language: {1}", "external", selectedLanguage)); } else { flag = true; } break; } } if (!flag && selectedLanguage != "English" && supportedEmbeddedLanguages.Contains(selectedLanguage)) { Helper.Log(string.Format("Loading {0} translation file for language: {1}", "embedded", selectedLanguage), QSSConfig.DebugSeverity.Everything); if (!LoadEmbeddedLanguageFile(selectedLanguage)) { Helper.LogO(string.Format("Failed loading {0} translation file for language: {1}", "embedded", selectedLanguage)); } } Helper.Log(string.Format("Loading {0} translation file for language: {1}", "embedded", "English"), QSSConfig.DebugSeverity.Everything); if (!LoadEmbeddedLanguageFile("English")) { Helper.LogO(string.Format("Failed loading {0} translation file for language: {1}", "embedded", "English")); } } internal static bool LoadExternalLanguageFile(string language, string path) { string text = File.ReadAllText(path); if (text == null) { return false; } return ParseStringToLanguage(language, text); } internal static bool LoadEmbeddedLanguageFile(string language) { string text = ReadEmbeddedTextFile($"QuickStackStore.Translations.QuickStackStore.{language}.json"); if (text == null) { return false; } return ParseStringToLanguage(language, text); } internal static bool ParseStringToLanguage(string language, string translationAsString) { Dictionary dictionary = new DeserializerBuilder().IgnoreFields().Build().Deserialize>(translationAsString); if (dictionary == null || dictionary.Count == 0) { return false; } foreach (KeyValuePair item in dictionary) { AddForLanguage(language, item.Key, item.Value); } return true; } internal static void AddForLanguage(string language, string key, string value) { string text = "quickstackstore_" + key.ToLower(); bool flag = Localization.instance.GetSelectedLanguage() == language; bool flag2 = language == "English" && !Localization.instance.m_translations.ContainsKey(text); if (flag || flag2) { Localization.instance.AddWord(text, value); } } public static string ReadEmbeddedTextFile(string path) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(path); if (manifestResourceStream == null) { return null; } using MemoryStream memoryStream = new MemoryStream(); manifestResourceStream.CopyTo(memoryStream); byte[] array = ((memoryStream.Length > 0) ? memoryStream.ToArray() : null); return (array != null) ? Encoding.UTF8.GetString(array) : null; } } internal static class ServerSyncWrapper { internal static ConfigEntry BindSyncLocker(this ConfigFile configFile, ConfigSync serverSyncInstance, string group, string name, T value, ConfigDescription description) where T : IConvertible { ConfigEntry val = configFile.Bind(group, name, value, description); serverSyncInstance.AddLockingConfigEntry(val); return val; } internal static ConfigEntry BindSyncLocker(this ConfigFile configFile, ConfigSync serverSyncInstance, string group, string name, T value, string description) where T : IConvertible { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return configFile.BindSyncLocker(serverSyncInstance, group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty())); } internal static ConfigEntry BindSynced(this ConfigFile configFile, ConfigSync serverSyncInstance, string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { ConfigEntry val = configFile.Bind(group, name, value, description); SyncedConfigEntry syncedConfigEntry = serverSyncInstance.AddConfigEntry(val); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val; } internal static ConfigEntry BindSynced(this ConfigFile configFile, ConfigSync serverSyncInstance, string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown return configFile.BindSynced(serverSyncInstance, group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty()), synchronizedSetting); } } internal class FavoritingMode { private static bool hasCurrentlyToggledFavoriting; private const string blackStar = "★"; private const string whiteStar = "☆"; internal static bool HasCurrentlyToggledFavoriting { get { return hasCurrentlyToggledFavoriting; } set { //IL_0035: Unknown result type (might be due to invalid IL or missing references) hasCurrentlyToggledFavoriting = value; if (Object.op_Implicit((Object)(object)ButtonRenderer.favoritingTogglingButtonText)) { if (QSSConfig.FavoriteConfig.FavoriteToggleButtonStyle.Value == QSSConfig.FavoriteToggleButtonStyle.TextStarInItemFavoriteColor) { string text = ColorUtility.ToHtmlStringRGB(QSSConfig.FavoriteConfig.BorderColorFavoritedItem.Value); ((TMP_Text)ButtonRenderer.favoritingTogglingButtonText).text = "" + (value ? "★" : "☆") + ""; } else { ((TMP_Text)ButtonRenderer.favoritingTogglingButtonText).text = (value ? "★" : "☆"); } } } } internal static void RefreshDisplay() { HasCurrentlyToggledFavoriting = HasCurrentlyToggledFavoriting; } internal static void ToggleFavoriteToggling() { HasCurrentlyToggledFavoriting = !HasCurrentlyToggledFavoriting; } internal static bool IsInFavoritingMode() { //IL_000d: 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) return HasCurrentlyToggledFavoriting || QSSConfig.FavoriteConfig.FavoritingModifierKeybind1.Value.IsKeyHeld() || QSSConfig.FavoriteConfig.FavoritingModifierKeybind2.Value.IsKeyHeld(); } } [HarmonyPatch] public static class KeybindChecker { [HarmonyPatch(typeof(Player))] public static class Player_Update_Patch { [HarmonyPatch("Update")] [HarmonyPostfix] public static void Postfix_Patch(Player __instance) { if (!((Object)(object)Player.m_localPlayer != (Object)(object)__instance) && !IgnoreKeyPresses()) { if (ZInput.IsGamepadActive() && QSSConfig.ControllerConfig.UseHardcodedControllerSupport.Value) { HandleControllerKeys(__instance); } else { HandleGenericKeys(__instance); } } } private static void HandleGenericKeys(Player player) { //IL_001d: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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) if (QSSConfig.GeneralConfig.OverrideKeybindBehavior.Value == QSSConfig.OverrideKeybindBehavior.DisableAllNewHotkeys) { return; } if (QSSConfig.QuickStackConfig.QuickStackKeybind.Value.IsKeyDown()) { QuickStackModule.DoQuickStack(player); } else if (QSSConfig.RestockConfig.RestockKeybind.Value.IsKeyDown()) { RestockModule.DoRestock(player); } else { if (!InventoryGui.IsVisible()) { return; } if (QSSConfig.SortConfig.SortKeybind.Value.IsKeyDown()) { SortModule.DoSort(player); return; } if (!CompatibilitySupport.DisallowAllTrashCanFeatures()) { if (QSSConfig.TrashConfig.QuickTrashKeybind.Value.IsKeyDown()) { TrashModule.AttemptQuickTrash(); return; } if (QSSConfig.TrashConfig.TrashKeybind.Value.IsKeyDown()) { TrashModule.TrashOrTrashFlagItem(usedFromHotkey: true); return; } } if (QSSConfig.StoreTakeAllConfig.TakeAllKeybind.Value.IsKeyDown()) { StoreTakeAllModule.DoTakeAllWithKeybind(player); } else if (QSSConfig.StoreTakeAllConfig.StoreAllKeybind.Value.IsKeyDown()) { StoreTakeAllModule.DoStoreAllWithKeybind(player); } } } private static void HandleControllerKeys(Player player) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (!InventoryGui.IsVisible()) { return; } if (ZInput.GetButtonDown("JoyBack")) { SortModule.DoSort(player); } else if (ZInput.GetButtonDown("JoyRStick")) { StoreTakeAllModule.DoStoreAllWithKeybind(player); } else if (QSSConfig.ControllerConfig.ControllerDPadUsageInInventoryGrid.Value != 0 && (QSSConfig.ControllerConfig.ControllerDPadUsageInInventoryGrid.Value != QSSConfig.DPadUsage.KeybindsWhileHoldingModifierKey || QSSConfig.ControllerConfig.ControllerDPadUsageModifierKeybind.Value.IsKeyHeld())) { if (ZInput.GetButtonDown("JoyDPadDown")) { QuickStackModule.DoQuickStack(player); } else if (ZInput.GetButtonDown("JoyDPadUp")) { RestockModule.DoRestock(player); } else if (ZInput.GetButtonDown("JoyDPadLeft")) { FavoritingMode.ToggleFavoriteToggling(); } else if (!CompatibilitySupport.DisallowAllTrashCanFeatures() && ZInput.GetButtonDown("JoyDPadRight")) { TrashModule.TrashOrTrashFlagItem(); } } } } internal const string joyTranslationPrefix = "KEY_"; internal const string joyGetButtonDownPrefix = "Joy"; internal const string joySort = "Back"; internal const string joyStoreAll = "RStick"; internal const string joyQuickStack = "DPadDown"; internal const string joyRestock = "DPadUp"; internal const string joyFavoriteToggling = "DPadLeft"; internal const string joyTrash = "DPadRight"; public static bool IgnoreKeyPresses() { return IgnoreKeyPressesDueToPlayer(Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZNetScene.instance) || Minimap.IsOpen() || Menu.IsVisible() || Console.IsVisible() || StoreGui.IsVisible() || TextInput.IsVisible() || (Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus()) || (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.InPasswordDialog()) || (Object.op_Implicit((Object)(object)TextViewer.instance) && TextViewer.instance.IsVisible()); } private static bool IgnoreKeyPressesDueToPlayer(Player player) { return !Object.op_Implicit((Object)(object)player) || ((Character)player).InCutscene() || ((Character)player).IsTeleporting() || ((Character)player).IsDead() || ((Character)player).InPlaceMode(); } public static bool IsKeyDown(this KeyboardShortcut shortcut) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func)Input.GetKey); } public static bool IsKeyHeld(this KeyboardShortcut shortcut) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func)Input.GetKey); } } [HarmonyPatch(typeof(Localization))] internal class LocalizationPatch { [HarmonyPatch("SetupLanguage")] [HarmonyPostfix] private static void SetupLanguagePatch(Localization __instance, string language) { LocalizationConfig.FixTakeAllDefaultText(__instance, language); } } internal class LocalizationConfig { public static ConfigEntry RestockLabelCharacter; public static ConfigEntry QuickStackLabelCharacter; public static ConfigEntry SortLabelCharacter; public static ConfigEntry QuickStackResultMessageNothing; public static ConfigEntry QuickStackResultMessageNone; public static ConfigEntry QuickStackResultMessageOne; public static ConfigEntry QuickStackResultMessageMore; public static ConfigEntry RestockResultMessageNothing; public static ConfigEntry RestockResultMessageNone; public static ConfigEntry RestockResultMessagePartial; public static ConfigEntry RestockResultMessageFull; public static ConfigEntry QuickStackLabel; public static ConfigEntry StoreAllLabel; public static ConfigEntry SortLabel; public static ConfigEntry RestockLabel; public static ConfigEntry TrashLabel; public static ConfigEntry TakeAllLabel; public static ConfigEntry SortByInternalNameLabel; public static ConfigEntry SortByTranslatedNameLabel; public static ConfigEntry SortByValueLabel; public static ConfigEntry SortByWeightLabel; public static ConfigEntry SortByTypeLabel; public static ConfigEntry TrashConfirmationOkayButton; public static ConfigEntry QuickTrashConfirmation; public static ConfigEntry CantTrashFavoritedItemWarning; public static ConfigEntry CantTrashFlagFavoritedItemWarning; public static ConfigEntry CantTrashHotkeyBarItemWarning; public static ConfigEntry CantFavoriteTrashFlaggedItemWarning; public static ConfigEntry FavoritedItemTooltip; public static ConfigEntry TrashFlaggedItemTooltip; public const string takeAllKey = "inventory_takeall"; internal static string GetRelevantTranslation(ConfigEntry config, string configName) { return (!Utility.IsNullOrWhiteSpace(config?.Value)) ? config.Value : Localization.instance.Translate("quickstackstore_" + configName.ToLower()); } internal static void FixTakeAllDefaultText(Localization localization, string language) { if (localization.m_translations.ContainsKey("inventory_takeall")) { switch (language) { case "English": localization.m_translations["inventory_takeall"] = "Take All"; break; case "Russian": localization.m_translations["inventory_takeall"] = "взять всё"; break; case "French": localization.m_translations["inventory_takeall"] = "Tout Prendre"; break; case "Portuguese_Brazilian": localization.m_translations["inventory_takeall"] = "Pegar Tudo"; break; } } } } internal class AreaStackRestockHelper { internal static bool IsTrueSingleplayer() { return !ZNet.m_openServer && !ZNet.m_publicServer && Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && !ZNet.instance.IsDedicated() && ZNet.instance.GetConnectedPeers().Count == 0; } private static bool CheckWard(Container container) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) return !container.m_checkGuardStone || PrivateArea.CheckAccess(((Component)container).transform.position, 0f, true, false); } private static bool CheckContainerPrivacy(Container container, long playerID) { return container.CheckAccess(playerID); } private static bool CheckPieceConfigs(Container container) { if (Object.op_Implicit((Object)(object)container.m_piece)) { return container.m_piece.IsPlacedByPlayer() || QSSConfig.QuickStackRestockConfig.AllowAreaStackingToPhysicalNonPlayerBuiltContainers.Value; } return container.m_name == "piece_chest_drawer" || QSSConfig.QuickStackRestockConfig.AllowAreaStackingToNonPhysicalContainers.Value; } private static bool IsInUseClientSide(Container container) { return container.IsInUse() || (Object.op_Implicit((Object)(object)container.m_wagon) && container.m_wagon.InUse()); } private static bool IsInUseServerSide(Container container) { return container.m_nview.GetZDO().GetInt("InUse", 0) == 1; } private static bool IsInUse(Container container) { return IsInUseServerSide(container) || IsInUseClientSide(container); } private static bool IsExcludedContainer(Container container) { Player component = ((Component)container.m_nview).GetComponent(); return Object.op_Implicit((Object)(object)component) && (Object)(object)component != (Object)(object)Player.m_localPlayer; } private static bool IsNonMUCExcludedContainer(Container container) { bool flag = false; return flag | Object.op_Implicit((Object)(object)((Component)((Component)container).transform.root).GetComponentInChildren()); } internal static bool ShouldAffectNonOwnerContainer(Container container, long playerID, bool isSinglePlayer) { bool flag = !IsExcludedContainer(container) && CheckContainerPrivacy(container, playerID) && CheckWard(container) && CheckPieceConfigs(container); if (CompatibilitySupport.HasPlugin("com.maxsch.valheim.MultiUserChest")) { return flag; } if (!isSinglePlayer && IsNonMUCExcludedContainer(container)) { return false; } return flag && !IsInUse(container); } internal static void SetNonMUCContainerInUse(Container container, bool isInUse) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) container.m_inUse = isInUse; if (QSSConfig.QuickStackRestockConfig.SuppressContainerSoundAndVisuals.Value) { container.m_nview.GetZDO().Set("InUse", isInUse ? 1 : 0); } else { container.SetInUse(isInUse); } ZDOMan.instance.ForceSendZDO(ZNet.GetUID(), container.m_nview.GetZDO().m_uid); } } public static class CompatibilitySupport { public enum RandyStatus { Disabled, EnabledWithoutQuickSlots, EnabledWithQuickSlots } private static MethodInfo IsComfyArmorSlot; private static MethodInfo IsRestrictedContainer; private static FieldInfo IsQuiverEnabled; private static FieldInfo QuiverRowIndex; private static FieldInfo AedenAddEquipmentRow; private static FieldInfo OdinExAddEquipmentRow; private static FieldInfo OdinQOLAddEquipmentRow; private static FieldInfo AzuEPIAddEquipmentRow; private static FieldInfo RandyQuickSlotsEnabled; public const string aeden = "aedenthorn.ExtendedPlayerInventory"; public const string comfy = "com.bruce.valheim.comfyquickslots"; public const string odinPlus = "com.odinplusqol.mod"; public const string odinExInv = "odinplusqol.OdinsExtendedInventory"; public const string randy = "randyknapp.mods.equipmentandquickslots"; public const string azuEPI = "Azumatt.AzuExtendedPlayerInventory"; public const string auga = "randyknapp.mods.auga"; public static bool isUsingAzuEPIWithAPI = false; public static bool isUsingAzuEPIWithQuickslotCompatibleAPI = false; public const string betterArchery = "ishid4.mods.betterarchery"; public const string smartContainers = "flueno.SmartContainers"; public const string backpacks = "org.bepinex.plugins.backpacks"; public const string multiUserChest = "com.maxsch.valheim.MultiUserChest"; public const string jewelCrafting = "org.bepinex.plugins.jewelcrafting"; public const string recyclePlus = "TastyChickenLegs.RecyclePlus"; public const string dynamicStoragePiles = "com.maxsch.valheim.DynamicStoragePiles"; public const string currencyPockets = "Azumatt.CurrencyPocket"; public static System.Version mucUpdateVersion = new System.Version(0, 4, 0); public static System.Version azuEPIOnOffUpdate = new System.Version(1, 2, 0); public static System.Version azuEPIQuickSlotAPIUpdate = new System.Version(1, 3, 2); public static bool HasAedenLikeEquipOrQuickSlotPlugin() { return HasPlugin("aedenthorn.ExtendedPlayerInventory") || HasPlugin("odinplusqol.OdinsExtendedInventory") || HasPlugin("com.odinplusqol.mod") || (HasPlugin("Azumatt.AzuExtendedPlayerInventory") && !isUsingAzuEPIWithAPI); } public static bool AllowAreaStackingRestocking() { return AreaStackRestockHelper.IsTrueSingleplayer() || HasPlugin("com.maxsch.valheim.MultiUserChest") || QSSConfig.QuickStackRestockConfig.AllowAreaStackingInMultiplayerWithoutMUC.Value; } public static bool DisallowAllTrashCanFeatures() { return HasPlugin("TastyChickenLegs.RecyclePlus"); } public static bool ShouldBlockChangesToTakeAllButton() { return QSSConfig.StoreTakeAllConfig.NeverMoveTakeAllButton.Value || ShouldBlockChangesToTakeAllButtonDueToPlugin(); } public static bool ShouldBlockChangesToTakeAllButtonDueToPlugin() { return HasPlugin("flueno.SmartContainers") || HasPlugin("org.bepinex.plugins.backpacks") || HasPlugin("org.bepinex.plugins.jewelcrafting"); } public static bool HasOutdatedMUCPlugin() { if (Chainloader.PluginInfos.ContainsKey("com.maxsch.valheim.MultiUserChest")) { PluginInfo val = Chainloader.PluginInfos["com.maxsch.valheim.MultiUserChest"]; return val.Metadata.Version < mucUpdateVersion; } return false; } public static bool HasAzuEPIWithQuickslotCompatibleAPI() { if (Chainloader.PluginInfos.ContainsKey("Azumatt.AzuExtendedPlayerInventory")) { PluginInfo val = Chainloader.PluginInfos["Azumatt.AzuExtendedPlayerInventory"]; return val.Metadata.Version >= azuEPIQuickSlotAPIUpdate; } return false; } public static bool HasPlugin(string guid) { return Chainloader.PluginInfos.ContainsKey(guid); } public static RandyStatus HasRandyPlugin() { if (!HasPlugin("randyknapp.mods.equipmentandquickslots")) { return RandyStatus.Disabled; } RandyStatus result = RandyStatus.EnabledWithQuickSlots; if (RandyQuickSlotsEnabled == null) { Assembly assembly = Assembly.Load("EquipmentAndQuickSlots"); if (assembly != null) { Type type = assembly.GetTypes().First((Type a) => a.IsClass && a.Name == "EquipmentAndQuickSlots"); FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); RandyQuickSlotsEnabled = fields.First((FieldInfo t) => t.Name?.ToLower() == "QuickSlotsEnabled".ToLower()); } } if (RandyQuickSlotsEnabled?.GetValue(null) is ConfigEntry val && !val.Value) { result = RandyStatus.EnabledWithoutQuickSlots; } return result; } public static bool HasPluginThatRequiresMiniButtonVMove() { return HasAedenLikeEquipOrQuickSlotPlugin() || (HasPlugin("Azumatt.AzuExtendedPlayerInventory") && isUsingAzuEPIWithAPI); } public static bool IsEquipSlot(int inventoryHeight, int inventoryWidth, Vector2i itemPos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return InternalIsEquipOrQuickSlot(inventoryHeight, inventoryWidth, itemPos, includeRestockableSlots: false); } public static bool IsEquipOrQuickSlot(int inventoryHeight, int inventoryWidth, Vector2i itemPos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return InternalIsEquipOrQuickSlot(inventoryHeight, inventoryWidth, itemPos, includeRestockableSlots: true); } private static bool InternalIsEquipOrQuickSlot(int inventoryHeight, int inventoryWidth, Vector2i itemPos, bool includeRestockableSlots) { //IL_0022: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) if (HasPlugin("aedenthorn.ExtendedPlayerInventory") && IsAedenLikeEquipOrQuickSlot(ref AedenAddEquipmentRow, "ExtendedPlayerInventory", "BepInExPlugin", "addEquipmentRow", inventoryHeight, itemPos, includeRestockableSlots)) { return true; } if (HasPlugin("odinplusqol.OdinsExtendedInventory") && IsAedenLikeEquipOrQuickSlot(ref OdinExAddEquipmentRow, "OdinsExtendedInventory", "OdinsExtendedInventoryPlugin", "addEquipmentRow", inventoryHeight, itemPos, includeRestockableSlots)) { return true; } if (HasPlugin("com.odinplusqol.mod") && IsAedenLikeEquipOrQuickSlot(ref OdinQOLAddEquipmentRow, "OdinQOL", "QuickAccessBar", "AddEquipmentRow", inventoryHeight, itemPos, includeRestockableSlots)) { return true; } if (HasPlugin("Azumatt.AzuExtendedPlayerInventory") && !isUsingAzuEPIWithAPI && IsAedenLikeEquipOrQuickSlot(ref AzuEPIAddEquipmentRow, "AzuExtendedPlayerInventory", "AzuExtendedPlayerInventoryPlugin", "AddEquipmentRow", inventoryHeight, itemPos, includeRestockableSlots)) { return true; } if (HasPlugin("Azumatt.AzuExtendedPlayerInventory") && isUsingAzuEPIWithAPI && IsNewAzuEPIEquipOrQuickSlot(inventoryHeight, inventoryWidth, itemPos, includeRestockableSlots)) { return true; } if (HasPlugin("com.bruce.valheim.comfyquickslots") && IsComfyEquipOrQuickSlot(inventoryHeight, itemPos, includeRestockableSlots)) { return true; } if (HasPlugin("ishid4.mods.betterarchery") && IsBetterArcheryQuiverSlot(itemPos, includeRestockableSlots)) { return true; } return false; } private static bool HasAedenLikeEquipmentRow(ref FieldInfo fieldInfo, string assemblyName, string className, string fieldName) { if (fieldInfo == null) { Assembly assembly = Assembly.Load(assemblyName); if (assembly != null) { Type type = assembly.GetTypes().First((Type a) => a.IsClass && a.Name == className); FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); fieldInfo = fields.First((FieldInfo t) => t.Name?.ToLower() == fieldName.ToLower()); } } if (fieldInfo == AzuEPIAddEquipmentRow && Chainloader.PluginInfos["Azumatt.AzuExtendedPlayerInventory"].Metadata.Version >= azuEPIOnOffUpdate) { object? obj = fieldInfo?.GetValue(null); ConfigEntryBase val = (ConfigEntryBase)((obj is ConfigEntryBase) ? obj : null); return val != null && (int)val.BoxedValue != 0; } return fieldInfo?.GetValue(null) is ConfigEntry val2 && val2.Value; } private static bool IsNewAzuEPIEquipOrQuickSlot(int inventoryHeight, int inventoryWidth, Vector2i itemPos, bool includeRestockableSlots) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!HasAedenLikeEquipmentRow(ref AzuEPIAddEquipmentRow, "AzuExtendedPlayerInventory", "AzuExtendedPlayerInventoryPlugin", "AddEquipmentRow")) { return false; } if (!includeRestockableSlots && isUsingAzuEPIWithQuickslotCompatibleAPI) { foreach (ItemData quickSlotsItem in API.GetQuickSlotsItems()) { if (quickSlotsItem.m_gridPos == itemPos) { return false; } } } int addedRows = API.GetAddedRows(inventoryWidth); for (int i = 1; i <= addedRows; i++) { if (itemPos.y == inventoryHeight - i) { return true; } } return false; } private static bool IsAedenLikeEquipOrQuickSlot(ref FieldInfo fieldInfo, string assemblyName, string className, string fieldName, int inventoryHeight, Vector2i itemPos, bool checkForRestockableSlots) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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) if (!HasAedenLikeEquipmentRow(ref fieldInfo, assemblyName, className, fieldName)) { return false; } return itemPos.y == inventoryHeight - 1 && (checkForRestockableSlots || itemPos.x < 5 || itemPos.x > 7); } private static bool IsComfyEquipOrQuickSlot(int inventoryHeight, Vector2i itemPos, bool includeRestockableSlots) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if (IsComfyArmorSlot == null) { Assembly assembly = Assembly.Load("ComfyQuickSlots"); if (assembly != null) { Type type = assembly.GetTypes().First((Type a) => a.IsClass && a.Name == "QuickSlotsManager"); MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); IsComfyArmorSlot = methods.First((MethodInfo t) => t.Name?.ToLower() == "IsArmorSlot".ToLower() && t.GetParameters().Length == 1); } } object obj = IsComfyArmorSlot?.Invoke(null, new object[1] { itemPos }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { return true; } if (includeRestockableSlots) { obj = IsComfyArmorSlot?.Invoke(null, new object[1] { (object)new Vector2i(itemPos.x - 3, itemPos.y) }); bool flag2 = default(bool); int num2; if (obj is bool) { flag2 = (bool)obj; num2 = 1; } else { num2 = 0; } if (((uint)num2 & (flag2 ? 1u : 0u)) != 0) { return true; } } return false; } public static bool TryGetRestrictedContainer(string containerName, out string allowedItem) { allowedItem = null; if (!HasPlugin("com.maxsch.valheim.DynamicStoragePiles")) { return false; } if (IsRestrictedContainer == null) { Assembly assembly = Assembly.Load("DynamicStoragePiles"); if (assembly != null) { Type type = assembly.GetTypes().First((Type a) => a.IsClass && a.Name == "RestrictContainers"); MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); IsRestrictedContainer = methods.First((MethodInfo t) => t.Name?.ToLower() == "IsRestrictedContainer".ToLower()); } } object[] array = new object[2] { containerName, null }; object obj = IsRestrictedContainer?.Invoke(null, array); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { allowedItem = (string)array[1]; return true; } return false; } private static bool IsBetterArcheryQuiverSlot(Vector2i itemPos, bool includeRestockableSlots) { //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0151: 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_015a: Unknown result type (might be due to invalid IL or missing references) if (IsQuiverEnabled == null || QuiverRowIndex == null) { Assembly assembly = Assembly.Load("BetterArchery"); if (assembly != null) { Type type = assembly.GetTypes().First((Type a) => a.IsClass && a.Name == "BetterArchery"); FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); IsQuiverEnabled = fields.First((FieldInfo t) => t.Name?.ToLower() == "ConfigQuiverEnabled".ToLower()); QuiverRowIndex = fields.First((FieldInfo t) => t.Name?.ToLower() == "QuiverRowIndex".ToLower()); } } if (!(IsQuiverEnabled?.GetValue(null) is ConfigEntry val) || !val.Value) { return false; } if (QuiverRowIndex?.GetValue(null) is int num) { if (num == 0) { return false; } if (itemPos.y == num && (includeRestockableSlots || itemPos.x < 0 || itemPos.x > 2)) { return true; } if (itemPos.y == num - 1) { return true; } } return false; } } internal class ContainerFinder { public static List AllContainers = new List(); public static List FindContainersInRange(Vector3 point, float range) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); foreach (Container allContainer in AllContainers) { if (Object.op_Implicit((Object)(object)allContainer) && Object.op_Implicit((Object)(object)((Component)allContainer).transform) && Object.op_Implicit((Object)(object)allContainer.m_nview) && allContainer.m_nview.HasOwner() && Vector3.Distance(point, ((Component)allContainer).transform.position) < range) { list.Add(allContainer); } } stopwatch.Stop(); Helper.Log($"Found {list.Count} container/s out of {AllContainers.Count} in range in {stopwatch.Elapsed}", QSSConfig.DebugSeverity.AlsoSpeedTests); return list; } } [HarmonyPatch(typeof(Container))] internal static class PatchContainer { [HarmonyPostfix] [HarmonyPatch("Awake")] internal static void Awake(Container __instance) { ContainerFinder.AllContainers.Add(__instance); } [HarmonyPatch("OnDestroyed")] [HarmonyPostfix] internal static void OnDestroyed(Container __instance) { ContainerFinder.AllContainers.Remove(__instance); } } public static class Helper { internal static void Log(object s, QSSConfig.DebugSeverity debugSeverity = QSSConfig.DebugSeverity.Normal) { if (debugSeverity > (QSSConfig.DebugConfig.DebugSeverity?.Value ?? QSSConfig.DebugSeverity.Normal)) { return; } string text = "Quick Stack - Store - Sort - Trash - Restock 1.4.13: " + ((s != null) ? s.ToString() : "null"); ConfigEntry showDebugLogs = QSSConfig.DebugConfig.ShowDebugLogs; if (showDebugLogs != null && showDebugLogs.Value == QSSConfig.DebugLevel.Log) { Debug.Log((object)text); return; } ConfigEntry showDebugLogs2 = QSSConfig.DebugConfig.ShowDebugLogs; if (showDebugLogs2 != null && showDebugLogs2.Value == QSSConfig.DebugLevel.Warning) { Debug.LogWarning((object)text); } } internal static void LogO(object s, QSSConfig.DebugLevel OverrideLevel = QSSConfig.DebugLevel.Warning) { string text = "Quick Stack - Store - Sort - Trash - Restock 1.4.13: " + ((s != null) ? s.ToString() : "null"); switch (OverrideLevel) { case QSSConfig.DebugLevel.Log: Debug.Log((object)text); break; case QSSConfig.DebugLevel.Warning: Debug.LogWarning((object)text); break; } } internal static int CompareSlotOrder(Vector2i a, Vector2i b) { //IL_0008: 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) int num = -a.y.CompareTo(b.y); if (QSSConfig.GeneralConfig.UseTopDownLogicForEverything.Value) { num *= -1; } return (num != 0) ? num : a.x.CompareTo(b.x); } public static Sprite LoadSprite(string path, Rect size, Vector2? pivot = null, int units = 100) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (!pivot.HasValue) { pivot = new Vector2(0.5f, 0.5f); } Assembly executingAssembly = Assembly.GetExecutingAssembly(); Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(path); Texture2D val = new Texture2D((int)((Rect)(ref size)).width, (int)((Rect)(ref size)).height, (TextureFormat)4, false, true); using MemoryStream memoryStream = new MemoryStream(); manifestResourceStream.CopyTo(memoryStream); ImageConversion.LoadImage(val, memoryStream.ToArray()); val.Apply(); return Sprite.Create(val, size, pivot.Value, (float)units); } } internal class QuickStackModule { private static bool ShouldQuickStackItem(ItemData item, UserConfig playerConfig, int inventoryHeight, int inventoryWidth, bool includeHotbar) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) return item.m_shared.m_maxStackSize > 1 && (item.m_gridPos.y > 0 || includeHotbar) && !playerConfig.IsItemNameOrSlotFavorited(item) && !CompatibilitySupport.IsEquipOrQuickSlot(inventoryHeight, inventoryWidth, item.m_gridPos); } private static bool ShouldAreaQuickStack(Container currentContainer) { return QSSConfig.QuickStackConfig.QuickStackToNearbyRange.Value > 0f && ((Object)(object)currentContainer == (Object)null || QSSConfig.QuickStackConfig.QuickStackHotkeyBehaviorWhenContainerOpen.Value != 0) && CompatibilitySupport.AllowAreaStackingRestocking(); } internal static void DoQuickStack(Player player, bool onlyQuickStackToCurrentContainer = false, Container currentContainerOverride = null) { //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Invalid comparison between Unknown and I4 //IL_01f4: Unknown result type (might be due to invalid IL or missing references) if (((Character)player).IsTeleporting() || !Object.op_Implicit((Object)(object)InventoryGui.instance.m_container)) { return; } InventoryGui.instance.SetupDragItem((ItemData)null, (Inventory)null, 0); UserConfig playerConfig = UserConfig.GetPlayerConfig(player.GetPlayerID()); bool includeHotbar = QSSConfig.GeneralConfig.OverrideHotkeyBarBehavior.Value != 0 && QSSConfig.QuickStackConfig.QuickStackIncludesHotkeyBar.Value; List list = ((Humanoid)player).m_inventory.m_inventory.Where((ItemData itm) => ShouldQuickStackItem(itm, playerConfig, ((Humanoid)player).m_inventory.GetHeight(), ((Humanoid)player).m_inventory.GetWidth(), includeHotbar)).ToList(); if (list.Count == 0 && QSSConfig.QuickStackConfig.ShowQuickStackResultMessage.Value) { ((Character)player).Message((MessageType)2, LocalizationConfig.GetRelevantTranslation(LocalizationConfig.QuickStackResultMessageNothing, "QuickStackResultMessageNothing"), 0, (Sprite)null); return; } list.Sort((ItemData a, ItemData b) => -1 * Helper.CompareSlotOrder(a.m_gridPos, b.m_gridPos)); List list2 = null; if (QSSConfig.QuickStackConfig.QuickStackTrophiesIntoSameContainer.Value) { list2 = new List(); for (int num = list.Count - 1; num >= 0; num--) { ItemData val = list[num]; if ((int)val.m_shared.m_itemType == 13) { list.RemoveAt(num); list2.Insert(0, val); } } } int num2 = 0; Container val2 = (Object.op_Implicit((Object)(object)currentContainerOverride) ? currentContainerOverride : InventoryGui.instance.m_currentContainer); if ((Object)(object)val2 != (Object)null) { num2 = QuickStackIntoThisContainer(list2, list, ((Humanoid)player).m_inventory, val2.m_inventory); } if (onlyQuickStackToCurrentContainer || !ShouldAreaQuickStack(val2)) { ReportQuickStackResult(player, num2); return; } List list3 = ContainerFinder.FindContainersInRange(((Component)player).transform.position, QSSConfig.QuickStackConfig.QuickStackToNearbyRange.Value); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); if (list3.Count > 0) { num2 += QuickStackIntoMultipleContainers(list2, list, player, list3); } stopwatch.Stop(); Helper.Log($"Quick stacking time: {stopwatch.Elapsed}", QSSConfig.DebugSeverity.AlsoSpeedTests); ReportQuickStackResult(player, num2); } private static int QuickStackIntoThisContainer(List trophies, List nonTrophies, Inventory playerInventory, Inventory container, bool callPlayerInvChanged = true) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 int num = 0; Helper.Log($"Starting quick stack: inventory count: {playerInventory.m_inventory.Count}, container count: {container.m_inventory.Count}", QSSConfig.DebugSeverity.Everything); if (QSSConfig.QuickStackConfig.QuickStackTrophiesIntoSameContainer.Value && trophies != null && trophies.Count > 0) { for (int num2 = container.m_inventory.Count - 1; num2 >= 0; num2--) { ItemData val = container.m_inventory[num2]; if ((int)val.m_shared.m_itemType == 13) { for (int num3 = trophies.Count - 1; num3 >= 0; num3--) { ItemData val2 = trophies[num3]; if (container.AddItem(val2)) { playerInventory.RemoveItem(val2); trophies.RemoveAt(num3); num++; } } break; } } } if (nonTrophies != null && nonTrophies.Count > 0) { if (container.m_inventory.Count == 0) { if (CompatibilitySupport.TryGetRestrictedContainer(container.m_name, out var allowedItem)) { num = GetQuickStackCountIntoThisContainer(nonTrophies, playerInventory, container, num, allowedItem, checkDropPrefabName: true); } } else { for (int num4 = container.m_inventory.Count - 1; num4 >= 0; num4--) { string name = container.m_inventory[num4].m_shared.m_name; num = GetQuickStackCountIntoThisContainer(nonTrophies, playerInventory, container, num, name, checkDropPrefabName: false); } } } Helper.Log($"Finished quick stack: Removed {num} stacks (remember that these merge with non full stacks in the container first). Inventory count: {playerInventory.m_inventory.Count}, container count: {container.m_inventory.Count}", QSSConfig.DebugSeverity.Everything); if (callPlayerInvChanged) { playerInventory.Changed(); } return num; } private static int GetQuickStackCountIntoThisContainer(List nonTrophies, Inventory playerInventory, Inventory container, int movedStackCount, string containerItemName, bool checkDropPrefabName) { for (int num = nonTrophies.Count - 1; num >= 0; num--) { ItemData val = nonTrophies[num]; bool flag = ((!checkDropPrefabName || !Object.op_Implicit((Object)(object)val.m_dropPrefab)) ? (containerItemName == val.m_shared.m_name) : (containerItemName == ((Object)val.m_dropPrefab).name)); if (flag && container.AddItem(val)) { playerInventory.RemoveItem(val); nonTrophies.RemoveAt(num); movedStackCount++; } } return movedStackCount; } private static int QuickStackIntoMultipleContainers(List trophies, List nonTrophies, Player player, List containers) { int num = 0; bool isSinglePlayer = AreaStackRestockHelper.IsTrueSingleplayer(); foreach (Container container in containers) { if (AreaStackRestockHelper.ShouldAffectNonOwnerContainer(container, player.GetPlayerID(), isSinglePlayer)) { if (CompatibilitySupport.HasPlugin("com.maxsch.valheim.MultiUserChest")) { num += QuickStackIntoThisContainer(trophies, nonTrophies, ((Humanoid)player).m_inventory, container.m_inventory, callPlayerInvChanged: false); continue; } container.m_nview.ClaimOwnership(); AreaStackRestockHelper.SetNonMUCContainerInUse(container, isInUse: true); num += QuickStackIntoThisContainer(trophies, nonTrophies, ((Humanoid)player).m_inventory, container.m_inventory, callPlayerInvChanged: false); AreaStackRestockHelper.SetNonMUCContainerInUse(container, isInUse: false); } } ((Humanoid)player).m_inventory.Changed(); return num; } public static void ReportQuickStackResult(Player player, int movedCount) { if (QSSConfig.QuickStackConfig.ShowQuickStackResultMessage.Value) { ((Character)player).Message((MessageType)2, movedCount switch { 0 => LocalizationConfig.GetRelevantTranslation(LocalizationConfig.QuickStackResultMessageNone, "QuickStackResultMessageNone"), 1 => LocalizationConfig.GetRelevantTranslation(LocalizationConfig.QuickStackResultMessageOne, "QuickStackResultMessageOne"), _ => string.Format(LocalizationConfig.GetRelevantTranslation(LocalizationConfig.QuickStackResultMessageMore, "QuickStackResultMessageMore"), movedCount), }, 0, (Sprite)null); } } } [HarmonyPatch(typeof(Container))] public static class StackAllPatch { [HarmonyPrefix] [HarmonyPatch("RPC_StackResponse")] public static bool ContainerStackAllPatch(Container __instance, bool granted) { if (!QSSConfig.QuickStackConfig.ChangeHoldToStackFeatureToUseModdedQuickStackingLogic.Value) { return true; } if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return false; } if (granted) { QuickStackModule.DoQuickStack(Player.m_localPlayer, onlyQuickStackToCurrentContainer: true, __instance); } else { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_inuse", 0, (Sprite)null); } return false; } } internal struct RestockData { internal ItemData itemData; internal int potentialCurrentStackSize; internal int maximumWantedStackSize; public RestockData(ItemData itemData, int potentialCurrentStackSize, int maximumWantedStackSize) { this.itemData = itemData; this.potentialCurrentStackSize = potentialCurrentStackSize; this.maximumWantedStackSize = maximumWantedStackSize; } } internal class RestockModule { private static bool ShouldRestockItem(ItemData item, UserConfig playerConfig, int inventoryHeight, int inventoryWidth, bool includeHotbar) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Invalid comparison between Unknown and I4 int configBasedMaxStackSize = GetConfigBasedMaxStackSize(item.m_shared); ItemType itemType = item.m_shared.m_itemType; return configBasedMaxStackSize > 1 && configBasedMaxStackSize > item.m_stack && (item.m_customData == null || item.m_customData.Count == 0) && (item.m_gridPos.y > 0 || includeHotbar) && (!QSSConfig.RestockConfig.RestockOnlyAmmoAndConsumables.Value || (int)itemType == 9 || (int)itemType == 2) && (!QSSConfig.RestockConfig.RestockOnlyFavoritedItems.Value || playerConfig.IsItemNameOrSlotFavorited(item)) && !CompatibilitySupport.IsEquipSlot(inventoryHeight, inventoryWidth, item.m_gridPos); } private static int GetConfigBasedMaxStackSize(SharedData shared) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 int num = shared.m_maxStackSize; int num2 = 0; if ((int)shared.m_itemType == 9) { num2 = QSSConfig.RestockConfig.RestockStackSizeLimitAmmo.Value; } else if ((int)shared.m_itemType == 2) { num2 = QSSConfig.RestockConfig.RestockStackSizeLimitConsumables.Value; } if (num2 <= 0) { num2 = QSSConfig.RestockConfig.RestockStackSizeLimitGeneral.Value; } if (num2 > 0) { num = Math.Min(num, num2); } return num; } private static bool ShouldAreaRestock(Container currentContainer) { return QSSConfig.RestockConfig.RestockFromNearbyRange.Value > 0f && ((Object)(object)currentContainer == (Object)null || QSSConfig.RestockConfig.RestockHotkeyBehaviorWhenContainerOpen.Value != 0) && CompatibilitySupport.AllowAreaStackingRestocking(); } internal static void DoRestock(Player player, bool RestockOnlyFromCurrentContainerOverride = false) { //IL_01ae: Unknown result type (might be due to invalid IL or missing references) if (((Character)player).IsTeleporting() || !Object.op_Implicit((Object)(object)InventoryGui.instance.m_container)) { return; } InventoryGui.instance.SetupDragItem((ItemData)null, (Inventory)null, 0); UserConfig playerConfig = UserConfig.GetPlayerConfig(player.GetPlayerID()); bool includeHotbar = QSSConfig.GeneralConfig.OverrideHotkeyBarBehavior.Value != 0 && QSSConfig.RestockConfig.RestockIncludesHotkeyBar.Value; List list = (from itemData in ((Humanoid)player).m_inventory.m_inventory where ShouldRestockItem(itemData, playerConfig, ((Humanoid)player).m_inventory.GetHeight(), ((Humanoid)player).m_inventory.GetWidth(), includeHotbar) select new RestockData(itemData, itemData.m_stack, GetConfigBasedMaxStackSize(itemData.m_shared))).ToList(); int count = list.Count; if (count == 0 && QSSConfig.RestockConfig.ShowRestockResultMessage.Value) { ((Character)player).Message((MessageType)2, LocalizationConfig.GetRelevantTranslation(LocalizationConfig.RestockResultMessageNothing, "RestockResultMessageNothing"), 0, (Sprite)null); return; } list.Sort((RestockData a, RestockData b) => -1 * Helper.CompareSlotOrder(a.itemData.m_gridPos, b.itemData.m_gridPos)); int num = 0; HashSet hashSet = new HashSet(); Container currentContainer = InventoryGui.instance.m_currentContainer; if ((Object)(object)currentContainer != (Object)null) { num = RestockFromThisContainer(list, ((Humanoid)player).m_inventory, currentContainer.m_inventory, hashSet); } if (RestockOnlyFromCurrentContainerOverride || !ShouldAreaRestock(currentContainer)) { ReportRestockResult(player, num, hashSet.Count, count); return; } List list2 = ContainerFinder.FindContainersInRange(((Component)player).transform.position, QSSConfig.RestockConfig.RestockFromNearbyRange.Value); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); if (list2.Count > 0) { num += RestockFromMultipleContainers(list, player, list2, hashSet); } stopwatch.Stop(); Helper.Log($"Restocking time: {stopwatch.Elapsed}", QSSConfig.DebugSeverity.AlsoSpeedTests); ReportRestockResult(player, num, hashSet.Count, count); } private static int RestockFromThisContainer(List itemsToRestock, Inventory playerInventory, Inventory container, HashSet partiallyFilledStacks, bool callPlayerInvChanged = true) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) if (itemsToRestock != null && itemsToRestock.Count <= 0) { return 0; } int num = 0; for (int num2 = itemsToRestock.Count - 1; num2 >= 0; num2--) { RestockData restockData = itemsToRestock[num2]; for (int num3 = container.m_inventory.Count - 1; num3 >= 0; num3--) { ItemData val = container.m_inventory[num3]; if ((val.m_customData == null || val.m_customData.Count <= 0) && !(val.m_shared.m_name != restockData.itemData.m_shared.m_name) && val.m_quality == restockData.itemData.m_quality) { int num4 = Math.Min(restockData.maximumWantedStackSize - restockData.potentialCurrentStackSize, val.m_stack); if (num4 > 0) { restockData.potentialCurrentStackSize += num4; partiallyFilledStacks.Add(restockData.itemData.m_gridPos); playerInventory.MoveItemToThis(container, val, num4, restockData.itemData.m_gridPos.x, restockData.itemData.m_gridPos.y); } if (restockData.potentialCurrentStackSize == restockData.maximumWantedStackSize) { itemsToRestock.RemoveAt(num2); num++; break; } } } } if (callPlayerInvChanged) { playerInventory.Changed(); } return num; } private static int RestockFromMultipleContainers(List itemsToRestock, Player player, List containers, HashSet partialRestockCounter) { int num = 0; bool isSinglePlayer = AreaStackRestockHelper.IsTrueSingleplayer(); foreach (Container container in containers) { if (AreaStackRestockHelper.ShouldAffectNonOwnerContainer(container, player.GetPlayerID(), isSinglePlayer)) { if (CompatibilitySupport.HasPlugin("com.maxsch.valheim.MultiUserChest")) { num += RestockFromThisContainer(itemsToRestock, ((Humanoid)player).m_inventory, container.m_inventory, partialRestockCounter, callPlayerInvChanged: false); continue; } container.m_nview.ClaimOwnership(); AreaStackRestockHelper.SetNonMUCContainerInUse(container, isInUse: true); num += RestockFromThisContainer(itemsToRestock, ((Humanoid)player).m_inventory, container.m_inventory, partialRestockCounter, callPlayerInvChanged: false); AreaStackRestockHelper.SetNonMUCContainerInUse(container, isInUse: false); } } ((Humanoid)player).m_inventory.Changed(); return num; } public static void ReportRestockResult(Player player, int movedCount, int partiallyFilledCount, int totalCount) { if (QSSConfig.RestockConfig.ShowRestockResultMessage.Value) { string text; if (movedCount == 0 && partiallyFilledCount == 0) { text = string.Format(LocalizationConfig.GetRelevantTranslation(LocalizationConfig.RestockResultMessageNone, "RestockResultMessageNone"), totalCount); } else if (movedCount < totalCount) { text = string.Format(LocalizationConfig.GetRelevantTranslation(LocalizationConfig.RestockResultMessagePartial, "RestockResultMessagePartial"), partiallyFilledCount, totalCount); } else if (movedCount == totalCount) { text = string.Format(LocalizationConfig.GetRelevantTranslation(LocalizationConfig.RestockResultMessageFull, "RestockResultMessageFull"), totalCount); } else { text = $"Invalid restock: Restocked more items than we originally had ({movedCount}/{totalCount})"; Helper.LogO(text); } ((Character)player).Message((MessageType)2, text, 0, (Sprite)null); } } } [HarmonyPatch(typeof(InventoryGui))] internal class TakeAllPatch { [HarmonyPrefix] [HarmonyPatch("OnTakeAll")] internal static bool ContextSensitiveTakeAll(InventoryGui __instance) { if (!QSSConfig.StoreTakeAllConfig.ChestsUseImprovedTakeAllLogic.Value) { return true; } if (!Object.op_Implicit((Object)(object)__instance.m_currentContainer) || Object.op_Implicit((Object)(object)((Component)__instance.m_currentContainer).GetComponent())) { return true; } StoreTakeAllModule.TakeAllItemsInOrder(Player.m_localPlayer); return false; } } internal class StoreTakeAllModule { internal static void DoTakeAllWithKeybind(Player player) { if (Object.op_Implicit((Object)(object)InventoryGui.instance) && InventoryGui.IsVisible() && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { InventoryGui.instance.OnTakeAll(); } } internal static void DoStoreAllWithKeybind(Player player) { if (Object.op_Implicit((Object)(object)InventoryGui.instance) && InventoryGui.IsVisible() && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { StoreAllItemsInOrder(player); } } private static bool ShouldStoreItem(ItemData item, UserConfig playerConfig, int inventoryHeight, int inventoryWidth, bool includeHotbar) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) return (item.m_gridPos.y > 0 || includeHotbar) && (QSSConfig.StoreTakeAllConfig.StoreAllIncludesEquippedItems.Value || !item.m_equipped) && !playerConfig.IsItemNameOrSlotFavorited(item) && !CompatibilitySupport.IsEquipOrQuickSlot(inventoryHeight, inventoryWidth, item.m_gridPos); } internal static void TakeAllItemsInOrder(Player player) { if (Object.op_Implicit((Object)(object)InventoryGui.instance.m_currentContainer)) { Inventory inventory = InventoryGui.instance.m_currentContainer.m_inventory; Inventory inventory2 = ((Humanoid)player).m_inventory; MoveAllItemsInOrder(player, inventory, inventory2, takeAllOverride: true); } } internal static void StoreAllItemsInOrder(Player player) { if (Object.op_Implicit((Object)(object)InventoryGui.instance.m_currentContainer)) { Inventory inventory = ((Humanoid)player).m_inventory; Inventory inventory2 = InventoryGui.instance.m_currentContainer.m_inventory; MoveAllItemsInOrder(player, inventory, inventory2); } } internal static void MoveAllItemsInOrder(Player player, Inventory fromInventory, Inventory toInventory, bool takeAllOverride = false) { if (((Character)player).IsTeleporting()) { return; } InventoryGui.instance.SetupDragItem((ItemData)null, (Inventory)null, 0); List list; if (takeAllOverride) { list = new List(fromInventory.m_inventory); } else { UserConfig playerConfig = UserConfig.GetPlayerConfig(player.GetPlayerID()); bool includeHotbar = QSSConfig.GeneralConfig.OverrideHotkeyBarBehavior.Value != 0 && QSSConfig.StoreTakeAllConfig.StoreAllIncludesHotkeyBar.Value; list = fromInventory.m_inventory.Where((ItemData item) => ShouldStoreItem(item, playerConfig, fromInventory.GetHeight(), fromInventory.GetWidth(), includeHotbar)).ToList(); } list.Sort((ItemData a, ItemData b) => Helper.CompareSlotOrder(a.m_gridPos, b.m_gridPos)); int num = 0; foreach (ItemData item in list) { if (toInventory.AddItem(item)) { fromInventory.RemoveItem(item); num++; if (item.m_equipped) { ((Humanoid)Player.m_localPlayer).RemoveEquipAction(item); ((Humanoid)Player.m_localPlayer).UnequipItem(item, false); } } } if (takeAllOverride) { Helper.Log($"Moved {num} item/s from container to player inventory"); } else { Helper.Log($"Moved {num} item/s from player inventory to container"); } toInventory.Changed(); fromInventory.Changed(); } } public static class SortModule { public static int[] TypeToCategory = new int[24] { 0, 2, 4, 7, 7, 8, 10, 10, 0, 6, 0, 10, 10, 1, 7, 7, 0, 10, 9, 7, 7, 3, 7, 5 }; private static bool ShouldSortItem(ItemData item, UserConfig playerConfig, int inventoryHeight, int inventoryWidth, bool includeHotbar) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) return !playerConfig.IsItemNameFavorited(item.m_shared) && ShouldSortSlot(item.m_gridPos, playerConfig, inventoryHeight, inventoryWidth, includeHotbar); } private static bool ShouldSortSlot(Vector2i slot, UserConfig playerConfig, int playerInventoryHeight, int playerInventoryWidth, bool includeHotbar) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) return (slot.y > 0 || includeHotbar) && !playerConfig.IsSlotFavorited(slot) && !CompatibilitySupport.IsEquipOrQuickSlot(playerInventoryHeight, playerInventoryWidth, slot); } public static void DoSort(Player player) { Container currentContainer = InventoryGui.instance.m_currentContainer; UserConfig playerConfig = UserConfig.GetPlayerConfig(player.GetPlayerID()); if ((Object)(object)currentContainer != (Object)null) { switch (QSSConfig.SortConfig.SortHotkeyBehaviorWhenContainerOpen.Value) { case QSSConfig.SortBehavior.OnlySortContainer: SortContainer(InventoryGui.instance.m_currentContainer); break; case QSSConfig.SortBehavior.SortBoth: SortContainer(InventoryGui.instance.m_currentContainer); SortPlayerInv(((Humanoid)player).m_inventory, playerConfig); break; } } else { SortPlayerInv(((Humanoid)player).m_inventory, playerConfig); } } public static IComparable SortByGetter(ItemData item) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected I4, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) switch (QSSConfig.SortConfig.SortCriteria.Value) { case QSSConfig.SortCriteriaEnum.TranslatedName: return Localization.instance.Localize(item.m_shared.m_name); case QSSConfig.SortCriteriaEnum.Value: return item.m_shared.m_value; case QSSConfig.SortCriteriaEnum.Weight: return item.m_shared.m_weight; case QSSConfig.SortCriteriaEnum.Type: { int num = (int)item.m_shared.m_itemType; if (num < 0 || num > 23) { return num; } return TypeToCategory[item.m_shared.m_itemType]; } default: return item.m_shared.m_name; } } public static int SortCompare(ItemData a, ItemData b) { int num = SortByGetter(a).CompareTo(SortByGetter(b)); if (!QSSConfig.SortConfig.SortInAscendingOrder.Value) { num *= -1; } if (num == 0) { num = a.m_shared.m_name.CompareTo(b.m_shared.m_name); } if (num == 0) { num = -a.m_quality.CompareTo(b.m_quality); } if (num == 0) { num = -a.m_stack.CompareTo(b.m_stack); } return num; } public static void SortContainer(Container container) { if (container.m_nview.IsOwner()) { SortInternal(container.m_inventory); } else { container.m_nview.InvokeRPC("QuickStackStore_RequestSort", Array.Empty()); } } public static void SortPlayerInv(Inventory inventory, UserConfig playerConfig) { SortInternal(inventory, playerConfig); } internal static void SortInternal(Inventory inventory, UserConfig playerConfig = null) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); bool includeHotbar = playerConfig == null || (QSSConfig.GeneralConfig.OverrideHotkeyBarBehavior.Value != 0 && QSSConfig.SortConfig.SortIncludesHotkeyBar.Value); List allowedSlots = GetAllowedSlots(inventory, includeHotbar, playerConfig); List list = ((playerConfig != null) ? inventory.m_inventory.Where((ItemData item) => ShouldSortItem(item, playerConfig, inventory.GetHeight(), inventory.GetWidth(), includeHotbar)).ToList() : new List(inventory.m_inventory)); if (QSSConfig.SortConfig.SortMergesStacks.Value) { MergeStacks(list, inventory); } list.Sort((ItemData a, ItemData b) => SortCompare(a, b)); for (int i = 0; i < list.Count; i++) { Helper.Log($"Sorting item from ({list[i].m_gridPos}) to ({allowedSlots[i]})", QSSConfig.DebugSeverity.Everything); list[i].m_gridPos = allowedSlots[i]; } stopwatch.Stop(); Helper.Log($"Sorting time: {stopwatch.Elapsed}", QSSConfig.DebugSeverity.AlsoSpeedTests); inventory.Changed(); } private static List GetAllowedSlots(Inventory inventory, bool includeHotbar, UserConfig playerConfig) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) List list = new List(); int i; int num; if (QSSConfig.GeneralConfig.UseTopDownLogicForEverything.Value) { i = ((!includeHotbar) ? 1 : 0); num = inventory.GetHeight(); } else { i = -inventory.GetHeight() + 1; num = (includeHotbar ? 1 : 0); } HashSet hashSet = new HashSet(); if (playerConfig != null) { foreach (ItemData item in inventory.m_inventory) { if (playerConfig.IsItemNameFavorited(item.m_shared)) { hashSet.Add(item.m_gridPos); } } } Vector2i val = default(Vector2i); for (; i < num; i++) { for (int j = 0; j < inventory.GetWidth(); j++) { ((Vector2i)(ref val))..ctor(j, Math.Abs(i)); if (playerConfig == null || (!hashSet.Contains(val) && (!QSSConfig.SortConfig.SortLeavesEmptyFavoritedSlotsEmpty.Value || !playerConfig.IsSlotFavorited(val)) && !CompatibilitySupport.IsEquipOrQuickSlot(inventory.GetHeight(), inventory.GetWidth(), val))) { list.Add(val); } } } return list; } internal static void MergeStacks(List toMerge, Inventory inventory) { List> list = (from itm in toMerge where itm.m_stack < itm.m_shared.m_maxStackSize && (itm.m_customData == null || itm.m_customData.Count == 0) group itm by new { itm.m_shared.m_name, itm.m_quality } into grouping select grouping.ToList()).ToList(); foreach (List item in list) { if (item.Count <= 1) { continue; } int num = 0; foreach (ItemData item2 in item) { num += item2.m_stack; } int maxStackSize = item.First().m_shared.m_maxStackSize; int num2 = num; foreach (ItemData item3 in item) { if (num2 <= 0) { item3.m_stack = 0; inventory.RemoveItem(item3); toMerge.Remove(item3); } else { item3.m_stack = Math.Min(maxStackSize, num2); num2 -= item3.m_stack; } } } } } [HarmonyPatch(typeof(Container))] public static class ContainerPatch { internal const string rpc_requestSort = "QuickStackStore_RequestSort"; [HarmonyPatch("Awake")] [HarmonyPostfix] public static void ContainerAwakePatch(Container __instance) { if (!Object.op_Implicit((Object)(object)__instance.m_nview)) { __instance.m_nview = (Object.op_Implicit((Object)(object)__instance.m_rootObjectOverride) ? ((Component)__instance.m_rootObjectOverride).GetComponent() : ((Component)__instance).GetComponent()); } if (Object.op_Implicit((Object)(object)__instance.m_nview)) { __instance.m_nview.Unregister("QuickStackStore_RequestSort"); __instance.m_nview.Register("QuickStackStore_RequestSort", (Action)delegate(long l) { RPC_RequestSort(l, __instance); }); } } public static void RPC_RequestSort(long _, Container container) { if (container.m_nview.IsOwner()) { SortModule.SortInternal(container.m_inventory); } } } [HarmonyPatch(typeof(Player))] internal static class PlayerPatch { [HarmonyPostfix] [HarmonyPatch("Start")] internal static void StartPatch(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { QSSConfig.ResetAllFavoritingData_SettingChanged(null, null); } } } internal class QSSConfig { internal class GeneralConfig { public static ConfigEntry ConfigTemplate; public static ConfigEntry OverrideButtonDisplay; public static ConfigEntry OverrideKeybindBehavior; public static ConfigEntry OverrideHotkeyBarBehavior; public static ConfigEntry UseTopDownLogicForEverything; } internal class ControllerConfig { public static ConfigEntry ControllerDPadUsageInInventoryGrid; public static ConfigEntry ControllerDPadUsageModifierKeybind; public static ConfigEntry RemoveControllerButtonHintFromTakeAllButton; public static ConfigEntry UseHardcodedControllerSupport; } internal class FavoriteConfig { public static ConfigEntry BorderColorFavoritedItem; public static ConfigEntry BorderColorFavoritedItemOnFavoritedSlot; public static ConfigEntry BorderColorFavoritedSlot; public static ConfigEntry BorderColorTrashFlaggedItem; public static ConfigEntry BorderColorTrashFlaggedItemOnFavoritedSlot; public static ConfigEntry DisplayFavoriteToggleButton; public static ConfigEntry DisplayTooltipHint; public static ConfigEntry FavoritingModifierKeybind1; public static ConfigEntry FavoritingModifierKeybind2; public static ConfigEntry FavoriteToggleButtonStyle; } internal class QuickStackRestockConfig { public static ConfigSync AreaStackRestockServerSync; public static ConfigEntry AllowAreaStackingInMultiplayerWithoutMUC; public static ConfigEntry AllowAreaStackingToNonPhysicalContainers; public static ConfigEntry AllowAreaStackingToPhysicalNonPlayerBuiltContainers; public static ConfigEntry SuppressContainerSoundAndVisuals; public static ConfigEntry ToggleAreaStackRestockConfigServerSync; } internal class QuickStackConfig { public static ConfigEntry ChangeHoldToStackFeatureToUseModdedQuickStackingLogic; public static ConfigEntry DisplayQuickStackButtons; public static ConfigEntry HideBaseGamePlaceStacksButton; public static ConfigEntry QuickStackHotkeyBehaviorWhenContainerOpen; public static ConfigEntry QuickStackIncludesHotkeyBar; public static ConfigEntry QuickStackKeybind; public static ConfigEntry QuickStackToNearbyRange; public static ConfigEntry QuickStackTrophiesIntoSameContainer; public static ConfigEntry ShowQuickStackResultMessage; } internal class RestockConfig { public static ConfigEntry DisplayRestockButtons; public static ConfigEntry RestockFromNearbyRange; public static ConfigEntry RestockHotkeyBehaviorWhenContainerOpen; public static ConfigEntry RestockIncludesHotkeyBar; public static ConfigEntry RestockKeybind; public static ConfigEntry RestockOnlyAmmoAndConsumables; public static ConfigEntry RestockOnlyFavoritedItems; public static ConfigEntry RestockStackSizeLimitAmmo; public static ConfigEntry RestockStackSizeLimitConsumables; public static ConfigEntry RestockStackSizeLimitGeneral; public static ConfigEntry ShowRestockResultMessage; } internal class StoreTakeAllConfig { public static ConfigEntry ChestsUseImprovedTakeAllLogic; public static ConfigEntry DisplayStoreAllButton; public static ConfigEntry NeverMoveTakeAllButton; public static ConfigEntry StoreAllKeybind; public static ConfigEntry StoreAllIncludesEquippedItems; public static ConfigEntry StoreAllIncludesHotkeyBar; public static ConfigEntry TakeAllKeybind; } internal class SortConfig { public static ConfigEntry AutoSort; public static ConfigEntry DisplaySortButtons; public static ConfigEntry DisplaySortCriteriaInLabel; public static ConfigEntry SortCriteria; public static ConfigEntry SortHotkeyBehaviorWhenContainerOpen; public static ConfigEntry SortInAscendingOrder; public static ConfigEntry SortIncludesHotkeyBar; public static ConfigEntry SortKeybind; public static ConfigEntry SortLeavesEmptyFavoritedSlotsEmpty; public static ConfigEntry SortMergesStacks; } internal class TrashConfig { public static ConfigEntry AlwaysConsiderTrophiesTrashFlagged; public static ConfigEntry DisplayTrashCanUI; public static ConfigEntry EnableQuickTrash; public static ConfigEntry PreventAutoPickupOfTrashFlaggedItems; public static ConfigEntry QuickTrashKeybind; public static ConfigEntry ShowConfirmDialogForNormalItem; public static ConfigEntry ShowConfirmDialogForQuickTrash; public static ConfigEntry TrashingCanAffectHotkeyBar; public static ConfigEntry TrashKeybind; public static ConfigEntry TrashLabelColor; } internal class DebugConfig { public static ConfigEntry ShowDebugLogs; public static ConfigEntry DebugSeverity; public static ConfigEntry ResetAllFavoritingData; } public enum OverrideButtonDisplay { DisableAllNewButtons, UseIndividualConfigOptions } public enum OverrideKeybindBehavior { DisableAllNewHotkeys, UseIndividualConfigOptions } public enum OverrideHotkeyBarBehavior { NeverAffectHotkeyBar, UseIndividualConfigOptions } public enum ShowConfirmDialogOption { Never, WhenNotTrashFlagged, Always } public enum ShowTwoButtons { Both, OnlyInventoryButton, OnlyContainerButton, BothButDependingOnContext, Disabled } public enum QuickStackBehavior { QuickStackOnlyToCurrentContainer, QuickStackToBoth } public enum RestockBehavior { RestockOnlyFromCurrentContainer, RestockFromBoth } public enum SortBehavior { OnlySortContainer, SortBoth } public enum SortCriteriaEnum { InternalName, TranslatedName, Value, Weight, Type } public enum AutoSortBehavior { Never, SortContainerOnOpen, SortPlayerInventoryOnOpen, Both } internal enum DebugLevel { Disabled, Log, Warning } internal enum DebugSeverity { Normal, AlsoSpeedTests, Everything } internal enum ResetFavoritingData { No, YesDeleteAllMyFavoritingData } internal enum FavoritingToggling { Disabled, EnabledTopButton, EnabledBottomButton } internal enum FavoriteToggleButtonStyle { DefaultTextStar, TextStarInItemFavoriteColor } internal enum DPadUsage { InventorySlotMovement, Keybinds, KeybindsWhileHoldingModifierKey } internal enum ConfigTemplate { NotCurrentlyLoadingTemplate, BasicControllerKeybinds, CustomControllerKeybinds, MouseAndKeyboardWithButtons, MouseAndKeyboardWithHotkeys, GoldensChoice, ResetToDefault } public static ConfigFile Config; internal static readonly List keyBinds = new List(); internal static void LoadConfig(BaseUnityPlugin plugin) { Config = plugin.Config; Config.SaveOnConfigSet = false; LoadConfigInternal(plugin); Config.Save(); Config.SaveOnConfigSet = true; } private static void LoadConfigInternal(BaseUnityPlugin plugin) { //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Expected O, but got Unknown //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) //IL_0882: Unknown result type (might be due to invalid IL or missing references) //IL_0a0f: Unknown result type (might be due to invalid IL or missing references) //IL_0a81: Unknown result type (might be due to invalid IL or missing references) //IL_0ba9: Unknown result type (might be due to invalid IL or missing references) //IL_0ccc: Unknown result type (might be due to invalid IL or missing references) //IL_0d83: Unknown result type (might be due to invalid IL or missing references) //IL_0dd3: Unknown result type (might be due to invalid IL or missing references) if (Config == null) { Helper.LogO("Internal config load was called without its wrapper. This is slower but still works."); Config = plugin.Config; } string text = "overridden by OverrideButtonDisplay"; string text2 = "overridden by OverrideKeybindBehavior"; string text3 = "overridden by OverrideHotkeyBarBehavior"; string text4 = "What to do when the hotkey is pressed while you have a container open."; string text5 = "Which of the two buttons to display (" + text + "). Selecting BothButDependingOnContext will hide the mini button while a container is open. The hotkey works independently."; string description = "How close the searched through containers have to be."; string text6 = "disallowing quick stacking, storing, sorting and trashing"; string text7 = "While holding this, left clicking on items or right clicking on slots favorites them, " + text6 + ", or trash flags them if you are hovering an item on the trash can."; string format = "Allows to set a custom stack size limit for {0} items in case you don't want them to restock to their maximum stack size. Use zero or negative numbers disable this."; string text8 = "0 - General"; GeneralConfig.ConfigTemplate = Config.Bind(text8, "ConfigTemplate", ConfigTemplate.NotCurrentlyLoadingTemplate, "Immediately or at the next startup, resets the config and applies the selected config template. Does not change any custom keybinds!"); GeneralConfig.ConfigTemplate.SettingChanged += ConfigTemplate_SettingChanged; GeneralConfig.OverrideButtonDisplay = Config.Bind(text8, "OverrideButtonDisplay", OverrideButtonDisplay.UseIndividualConfigOptions, "Override to disable all new UI elements no matter the current individual setting of each of them."); GeneralConfig.OverrideButtonDisplay.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin, includeTrashButton: true); }; GeneralConfig.OverrideHotkeyBarBehavior = Config.Bind(text8, "OverrideHotkeyBarBehavior", OverrideHotkeyBarBehavior.NeverAffectHotkeyBar, "Override to never affect the hotkey bar with any feature no matter the individual setting of each of them. Recommended to turn off if you are actually using favoriting."); GeneralConfig.OverrideKeybindBehavior = Config.Bind(text8, "OverrideKeybindBehavior", OverrideKeybindBehavior.UseIndividualConfigOptions, "Override to disable all new keybinds no matter the current individual setting of each of them."); bool oldValue = false; if (TryGetOldConfigValue(new ConfigDefinition(text8, "DisableAllNewButtons"), ref oldValue)) { GeneralConfig.OverrideButtonDisplay.Value = ((!oldValue) ? OverrideButtonDisplay.UseIndividualConfigOptions : OverrideButtonDisplay.DisableAllNewButtons); } if (TryGetOldConfigValue(new ConfigDefinition(text8, "DisableAllNewKeybinds"), ref oldValue)) { GeneralConfig.OverrideKeybindBehavior.Value = ((!oldValue) ? OverrideKeybindBehavior.UseIndividualConfigOptions : OverrideKeybindBehavior.DisableAllNewHotkeys); } if (TryGetOldConfigValue(new ConfigDefinition(text8, "NeverAffectHotkeyBar"), ref oldValue)) { GeneralConfig.OverrideHotkeyBarBehavior.Value = ((!oldValue) ? OverrideHotkeyBarBehavior.UseIndividualConfigOptions : OverrideHotkeyBarBehavior.NeverAffectHotkeyBar); } GeneralConfig.UseTopDownLogicForEverything = Config.Bind(text8, "UseTopDownLogicForEverything", false, "Whether to always put items into the top first row (affects the entire game) rather than top or bottom first depending on the item type (base game uses top first only for weapons and tools, bottom first for the rest). Recommended to keep off."); text8 = "0.1 - Controller General"; ControllerConfig.ControllerDPadUsageInInventoryGrid = Config.Bind(text8, "ControllerDPadUsageInInventoryGrid", DPadUsage.Keybinds, "In the base game the DPad and the left stick are both used for slot movement inside the inventory grid. This allows you to exclude the DPad from this to get more keys for keybinds."); ControllerConfig.ControllerDPadUsageModifierKeybind = Config.Bind(text8, "ControllerDPadUsageModifierKeybind", new KeyboardShortcut((KeyCode)0, Array.Empty()), string.Format("When {0} is set to {1}, then holding this prevents slot movement in the inventory grid with the DPad.", "ControllerDPadUsageInInventoryGrid", DPadUsage.KeybindsWhileHoldingModifierKey)); ControllerConfig.RemoveControllerButtonHintFromTakeAllButton = Config.Bind(text8, "RemoveControllerButtonHintFromTakeAllButton", false, "Remove the button hint from the 'Take All' button while using a controller for consistency. Especially useful when using the new keybind TakeAllKeybind."); ControllerConfig.RemoveControllerButtonHintFromTakeAllButton.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; ControllerConfig.UseHardcodedControllerSupport = Config.Bind(text8, "UseHardcodedControllerSupport", true, "Whether to enable the hardcoded controller bindings including UI hints while a controller is used. This disables custom hotkeys."); ControllerConfig.UseHardcodedControllerSupport.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; text8 = "1 - Favoriting"; FavoriteConfig.BorderColorFavoritedItem = Config.Bind(text8, "BorderColorFavoritedItem", new Color(1f, 0.8482759f, 0f), "Color of the border for slots containing favorited items."); FavoriteConfig.BorderColorFavoritedItem.SettingChanged += delegate { FavoritingMode.RefreshDisplay(); }; FavoriteConfig.BorderColorFavoritedItemOnFavoritedSlot = Config.Bind(text8, "BorderColorFavoritedItemOnFavoritedSlot", new Color(0.5f, 0.67413795f, 0.5f), "Color of the border of a favorited slot that also contains a favorited item."); FavoriteConfig.BorderColorFavoritedSlot = Config.Bind(text8, "BorderColorFavoritedSlot", new Color(0f, 0.5f, 1f), "Color of the border for favorited slots."); FavoriteConfig.BorderColorTrashFlaggedItem = Config.Bind(text8, "BorderColorTrashFlaggedItem", new Color(0.5f, 0f, 0f), ConfigurationManagerAttributes.HiddenTrashingDisplay("Color of the border for slots containing trash flagged items.")); FavoriteConfig.BorderColorTrashFlaggedItemOnFavoritedSlot = Config.Bind(text8, "BorderColorTrashFlaggedItemOnFavoritedSlot", Color.black, ConfigurationManagerAttributes.HiddenTrashingDisplay("Color of the border of a favorited slot that also contains a trash flagged item.")); FavoriteConfig.DisplayFavoriteToggleButton = Config.Bind(text8, "DisplayFavoriteToggleButton", FavoritingToggling.EnabledTopButton, "Whether to display a button to toggle favoriting mode on or off, allowing to favorite without holding any hotkey (" + text + "). This can also be used to trash flag. The hotkeys work independently."); FavoriteConfig.DisplayFavoriteToggleButton.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; if (TryGetOldConfigValue(new ConfigDefinition(text8, "FavoritingModifierToggles"), ref oldValue)) { FavoriteConfig.DisplayFavoriteToggleButton.Value = (oldValue ? FavoritingToggling.EnabledTopButton : FavoritingToggling.Disabled); } FavoriteConfig.DisplayTooltipHint = Config.Bind(text8, "DisplayTooltipHint", true, "Whether to add additional info the item tooltip of a favorited or trash flagged item."); FavoriteConfig.FavoritingModifierKeybind1 = Config.Bind(text8, "FavoritingModifierKeybind1", new KeyboardShortcut((KeyCode)308, Array.Empty()), text7 + " Identical to FavoritingModifierKeybind2."); FavoriteConfig.FavoritingModifierKeybind2 = Config.Bind(text8, "FavoritingModifierKeybind2", new KeyboardShortcut((KeyCode)307, Array.Empty()), text7 + " Identical to FavoritingModifierKeybind1."); KeyCodeBackwardsCompatibility(FavoriteConfig.FavoritingModifierKeybind1, text8, "FavoritingModifierKey1"); KeyCodeBackwardsCompatibility(FavoriteConfig.FavoritingModifierKeybind2, text8, "FavoritingModifierKey2"); FavoriteConfig.FavoriteToggleButtonStyle = Config.Bind(text8, "FavoriteToggleButtonStyle", FavoriteToggleButtonStyle.TextStarInItemFavoriteColor, "The style of the favorite toggling button enabled with DisplayFavoriteToggleButton."); FavoriteConfig.FavoriteToggleButtonStyle.SettingChanged += delegate { FavoritingMode.RefreshDisplay(); }; text8 = "2 - Quick Stacking and Restocking"; string category = "2.0 - Area Quick Stacking and Restocking"; QuickStackRestockConfig.AreaStackRestockServerSync = new ConfigSync("goldenrevolver.quick_stack_store") { DisplayName = "Quick Stack - Store - Sort - Trash - Restock", CurrentVersion = "1.4.13", MinimumRequiredVersion = "1.4.13", ModRequired = false }; QuickStackRestockConfig.AllowAreaStackingInMultiplayerWithoutMUC = Config.BindSynced(QuickStackRestockConfig.AreaStackRestockServerSync, text8, "AllowAreaStackingInMultiplayerWithoutMUC", value: false, ConfigurationManagerAttributes.MUCSettingDisplay("AllowAreaStackingInMultiplayer", category, "Whether you can use area quick stacking and area restocking in multiplayer while 'Multi User Chest' is not installed. While this is almost always safe, it can fail because no actual network requests are getting sent. Ship containers are inherently especially vulnerable and are therefore excluded.")); QuickStackRestockConfig.AllowAreaStackingInMultiplayerWithoutMUC.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; QuickStackRestockConfig.AllowAreaStackingToNonPhysicalContainers = Config.BindSynced(QuickStackRestockConfig.AreaStackRestockServerSync, text8, "AllowAreaStackingToNonPhysicalContainers", value: true, ConfigurationManagerAttributes.CustomCategoryWithDescription(category, "Allow stacking to or restocking from containers without a physical piece object in the world, like backpacks.")); QuickStackRestockConfig.AllowAreaStackingToPhysicalNonPlayerBuiltContainers = Config.BindSynced(QuickStackRestockConfig.AreaStackRestockServerSync, text8, "AllowAreaStackingToPhysicalNonPlayerBuiltContainers", value: false, ConfigurationManagerAttributes.CustomCategoryWithDescription(category, "Allow stacking to or restocking from containers like dungeon chests or probably some modded containers.")); QuickStackRestockConfig.SuppressContainerSoundAndVisuals = Config.BindSynced(QuickStackRestockConfig.AreaStackRestockServerSync, text8, "SuppressContainerSoundAndVisuals", value: true, ConfigurationManagerAttributes.CustomCategoryWithDescription(category, "Whether when a feature checks multiple containers in an area, they actually play opening sounds and visuals. Disable if the suppression causes incompatibilities.")); QuickStackRestockConfig.ToggleAreaStackRestockConfigServerSync = Config.BindSyncLocker(QuickStackRestockConfig.AreaStackRestockServerSync, text8, "ToggleAreaStackRestockConfigServerSync", value: true, ConfigurationManagerAttributes.CustomCategoryWithDescription(category, "Whether the config settings about area quick stacking and area restocking (including range) of the host/ server get applied to all other users using this mod. Does nothing if the host/ server does not have this mod installed.")); text8 = "2.1 - Quick Stacking"; QuickStackConfig.ChangeHoldToStackFeatureToUseModdedQuickStackingLogic = Config.Bind(text8, "ChangeHoldToStackFeatureToUseModdedQuickStackingLogic", true, "Whether to override the behavior when holding open on a container that you are hovering on with the modded quick stacking behavior. Does not override the behavior of the default 'Place Stacks' button, if it's still enabled."); QuickStackConfig.DisplayQuickStackButtons = Config.Bind(text8, "DisplayQuickStackButtons", ShowTwoButtons.BothButDependingOnContext, text5); QuickStackConfig.DisplayQuickStackButtons.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; QuickStackConfig.HideBaseGamePlaceStacksButton = Config.Bind(text8, "HideBaseGamePlaceStacksButton", true, ConfigurationManagerAttributes.ForceEnabledDisplay(() => CompatibilitySupport.HasRandyPlugin() == CompatibilitySupport.RandyStatus.EnabledWithQuickSlots, "Whether to hide the 'Place Stacks' button that uses the base game quick stacking logic. Modded buttons are moved automatically based on this setting. Force enabled when using 'Randy's Equipment and Quick Slot' mod.")); QuickStackConfig.HideBaseGamePlaceStacksButton.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; QuickStackConfig.QuickStackHotkeyBehaviorWhenContainerOpen = Config.Bind(text8, "QuickStackHotkeyBehaviorWhenContainerOpen", QuickStackBehavior.QuickStackOnlyToCurrentContainer, text4); QuickStackConfig.QuickStackIncludesHotkeyBar = Config.Bind(text8, "QuickStackIncludesHotkeyBar", true, "Whether to also quick stack items from the hotkey bar (" + text3 + ")."); QuickStackConfig.QuickStackKeybind = Config.Bind(text8, "QuickStackKeybind", new KeyboardShortcut((KeyCode)112, Array.Empty()), "The hotkey to start quick stacking to the current or nearby containers (depending on QuickStackHotkeyBehaviorWhenContainerOpen, " + text2 + ")."); KeyCodeBackwardsCompatibility(QuickStackConfig.QuickStackKeybind, text8, "QuickStackKey"); QuickStackConfig.QuickStackToNearbyRange = Config.BindSynced(QuickStackRestockConfig.AreaStackRestockServerSync, text8, "QuickStackToNearbyRange", 10f, ConfigurationManagerAttributes.CustomCategoryWithDescription(category, description)); QuickStackConfig.QuickStackToNearbyRange.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; QuickStackConfig.QuickStackTrophiesIntoSameContainer = Config.Bind(text8, "QuickStackTrophiesIntoSameContainer", false, "Whether to put all types of trophies in the container if any trophy is found in that container."); QuickStackConfig.ShowQuickStackResultMessage = Config.Bind(text8, "ShowQuickStackResultMessage", true, "Whether to show the central screen report message after quick stacking."); text8 = "2.2 - Quick Restocking"; RestockConfig.DisplayRestockButtons = Config.Bind(text8, "DisplayRestockButtons", ShowTwoButtons.BothButDependingOnContext, text5); RestockConfig.DisplayRestockButtons.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; RestockConfig.RestockFromNearbyRange = Config.BindSynced(QuickStackRestockConfig.AreaStackRestockServerSync, text8, "RestockFromNearbyRange", 10f, ConfigurationManagerAttributes.CustomCategoryWithDescription(category, description)); RestockConfig.RestockFromNearbyRange.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; RestockConfig.RestockHotkeyBehaviorWhenContainerOpen = Config.Bind(text8, "RestockHotkeyBehaviorWhenContainerOpen", RestockBehavior.RestockOnlyFromCurrentContainer, text4); RestockConfig.RestockIncludesHotkeyBar = Config.Bind(text8, "RestockIncludesHotkeyBar", true, "Whether to also try to restock items currently in the hotkey bar (" + text3 + ")."); RestockConfig.RestockKeybind = Config.Bind(text8, "RestockKeybind", new KeyboardShortcut((KeyCode)108, Array.Empty()), "The hotkey to start restocking from the current or nearby containers (depending on RestockHotkeyBehaviorWhenContainerOpen, " + text2 + ")."); KeyCodeBackwardsCompatibility(RestockConfig.RestockKeybind, text8, "RestockKey"); RestockConfig.RestockOnlyAmmoAndConsumables = Config.Bind(text8, "RestockOnlyAmmoAndConsumables", true, "Whether restocking should only restock ammo and consumable or every stackable item (like materials). Also affected by RestockOnlyFavoritedItems."); RestockConfig.RestockOnlyFavoritedItems = Config.Bind(text8, "RestockOnlyFavoritedItems", false, "Whether restocking should only restock favorited items or items on favorited slots or every stackable item. Also affected by RestockOnlyAmmoAndConsumables."); RestockConfig.RestockStackSizeLimitAmmo = Config.Bind(text8, "RestockStackSizeLimitAmmo", 0, string.Format(format, "ammo")); RestockConfig.RestockStackSizeLimitConsumables = Config.Bind(text8, "RestockStackSizeLimitConsumables", 0, string.Format(format, "consumable")); RestockConfig.RestockStackSizeLimitGeneral = Config.Bind(text8, "RestockStackSizeLimitGeneral", 0, string.Format(format, "all") + " The stack size limits for ammo or consumables from their respective config setting (RestockStackSizeLimitAmmo and RestockStackSizeLimitConsumables) take priority if they are also enabled."); RestockConfig.ShowRestockResultMessage = Config.Bind(text8, "ShowRestockResultMessage", true, "Whether to show the central screen report message after restocking."); text8 = "3 - Store and Take All"; StoreTakeAllConfig.ChestsUseImprovedTakeAllLogic = Config.Bind(text8, "ChestsUseImprovedTakeAllLogic", true, "Whether to use the improved logic for 'Take All' for non tomb stones. Disable if needed for compatibility."); StoreTakeAllConfig.DisplayStoreAllButton = Config.Bind(text8, "DisplayStoreAllButton", true, "Whether to display the 'Store All' button in containers (" + text + ")."); StoreTakeAllConfig.DisplayStoreAllButton.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; StoreTakeAllConfig.NeverMoveTakeAllButton = Config.Bind(text8, "NeverMoveTakeAllButton", false, ConfigurationManagerAttributes.ForceEnabledDisplay(CompatibilitySupport.ShouldBlockChangesToTakeAllButtonDueToPlugin, "Disallows my mod from moving the 'Take All' button. Enable for compatibility with other mods (when certain mods are detected, this setting is force enabled). If it was already moved, then you need to log out and back in (since I don't even allow to reset the position, since I don't know if that position is valid with your installed mods).")); StoreTakeAllConfig.StoreAllKeybind = Config.Bind(text8, "StoreAllKeybind", new KeyboardShortcut((KeyCode)0, Array.Empty()), "The hotkey to use 'Store All' on the currently opened container (" + text2 + ")."); StoreTakeAllConfig.StoreAllIncludesEquippedItems = Config.Bind(text8, "StoreAllIncludesEquippedItems", false, "Whether to also unequip and store non favorited equipped items or exclude them."); StoreTakeAllConfig.StoreAllIncludesHotkeyBar = Config.Bind(text8, "StoreAllIncludesHotkeyBar", true, "Whether to also store all non favorited items from the hotkey bar (" + text3 + ")."); StoreTakeAllConfig.TakeAllKeybind = Config.Bind(text8, "TakeAllKeybind", new KeyboardShortcut((KeyCode)0, Array.Empty()), "The hotkey to use 'Take All' on the currently opened container (" + text2 + ")."); text8 = "4 - Sorting"; SortConfig.AutoSort = Config.Bind(text8, "AutoSort", AutoSortBehavior.Never, "Automatically let the mod sort the player inventory every time you open it, as well as every container you open. This respects your other sorting config options."); SortConfig.DisplaySortButtons = Config.Bind(text8, "DisplaySortButtons", ShowTwoButtons.Both, text5); SortConfig.DisplaySortButtons.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; SortConfig.DisplaySortCriteriaInLabel = Config.Bind(text8, "DisplaySortCriteriaInLabel", false, "Whether to display the current sort criteria in the inventory sort button as a reminder. The author thinks the button is a bit too small for it to look good."); SortConfig.DisplaySortCriteriaInLabel.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin); }; SortConfig.SortCriteria = Config.Bind(text8, "SortCriteria", SortCriteriaEnum.Type, "The sort criteria the sort button uses. Ties are broken by internal name, quality and stack size."); SortConfig.SortHotkeyBehaviorWhenContainerOpen = Config.Bind(text8, "SortHotkeyBehaviorWhenContainerOpen", SortBehavior.OnlySortContainer, text4); SortConfig.SortInAscendingOrder = Config.Bind(text8, "SortInAscendingOrder", true, "Whether the current first sort criteria should be used in ascending or descending order."); SortConfig.SortIncludesHotkeyBar = Config.Bind(text8, "SortIncludesHotkeyBar", true, "Whether to also sort non favorited items from the hotkey bar (" + text3 + ")."); SortConfig.SortKeybind = Config.Bind(text8, "SortKeybind", new KeyboardShortcut((KeyCode)111, Array.Empty()), "The hotkey to sort the inventory or the current container or both (depending on SortHotkeyBehaviorWhenContainerOpen, " + text2 + ")."); KeyCodeBackwardsCompatibility(SortConfig.SortKeybind, text8, "SortKey"); SortConfig.SortLeavesEmptyFavoritedSlotsEmpty = Config.Bind(text8, "SortLeavesEmptyFavoritedSlotsEmpty", true, "Whether sort treats empty favorited slots as occupied and leaves them empty, so you don't accidentally put items on them."); SortConfig.SortMergesStacks = Config.Bind(text8, "SortMergesStacks", true, "Whether to merge stacks after sorting or keep them as separate non full stacks."); text8 = "5 - Trashing"; TrashConfig.AlwaysConsiderTrophiesTrashFlagged = Config.Bind(text8, "AlwaysConsiderTrophiesTrashFlagged", false, ConfigurationManagerAttributes.HiddenTrashingDisplay("Whether to always consider trophies as trash flagged, allowing for immediate trashing or to be affected by quick trashing.")); TrashConfig.DisplayTrashCanUI = Config.Bind(text8, "DisplayTrashCanUI", true, ConfigurationManagerAttributes.TrashingCategoryHideNotificationDisplay("Whether to display the trash can UI element (" + text + "). Hotkeys work independently.")); TrashConfig.DisplayTrashCanUI.SettingChanged += delegate { ButtonRenderer.OnButtonRelevantSettingChanged(plugin, includeTrashButton: true); }; TrashConfig.EnableQuickTrash = Config.Bind(text8, "EnableQuickTrash", true, ConfigurationManagerAttributes.HiddenTrashingDisplay("Whether quick trashing can be called with the hotkey or be clicking on the trash can while not holding anything.")); TrashConfig.PreventAutoPickupOfTrashFlaggedItems = Config.Bind(text8, "PreventAutoPickupOfTrashFlaggedItems", false, ConfigurationManagerAttributes.HiddenTrashingDisplay("Whether a trash flagged item should additionally no longer be automatically picked up in the world by walking near it. It can still be manually picked up by using the interact button.")); TrashConfig.QuickTrashKeybind = Config.Bind(text8, "QuickTrashKeybind", new KeyboardShortcut((KeyCode)0, Array.Empty()), ConfigurationManagerAttributes.HiddenTrashingDisplay("The hotkey to perform a quick trash on the player inventory, deleting all trash flagged items (" + text2 + ").")); KeyCodeBackwardsCompatibility(TrashConfig.QuickTrashKeybind, text8, "QuickTrashHotkey"); TrashConfig.ShowConfirmDialogForNormalItem = Config.Bind(text8, "ShowConfirmDialogForNormalItem", ShowConfirmDialogOption.WhenNotTrashFlagged, ConfigurationManagerAttributes.HiddenTrashingDisplay("When to show a confirmation dialog while doing a non quick trash.")); TrashConfig.ShowConfirmDialogForQuickTrash = Config.Bind(text8, "ShowConfirmDialogForQuickTrash", true, ConfigurationManagerAttributes.HiddenTrashingDisplay("Whether to show a confirmation dialog while doing a quick trash.")); TrashConfig.TrashingCanAffectHotkeyBar = Config.Bind(text8, "TrashingCanAffectHotkeyBar", true, ConfigurationManagerAttributes.HiddenTrashingDisplay("Whether trashing and quick trashing can trash items that are currently in the hotkey bar (" + text3 + ").")); TrashConfig.TrashKeybind = Config.Bind(text8, "TrashKeybind", new KeyboardShortcut((KeyCode)127, Array.Empty()), ConfigurationManagerAttributes.HiddenTrashingDisplay("The hotkey to trash the currently held item (" + text2 + ").")); KeyCodeBackwardsCompatibility(TrashConfig.TrashKeybind, text8, "TrashHotkey"); TrashConfig.TrashLabelColor = Config.Bind(text8, "TrashLabelColor", new Color(1f, 0.8482759f, 0f), ConfigurationManagerAttributes.HiddenTrashingDisplay("The color of the text below the trash can in the player inventory.")); text8 = "8 - Debugging"; DebugConfig.ShowDebugLogs = Config.Bind(text8, "ShowDebugLogs", DebugLevel.Disabled, "Enable debug logs into the console. Optionally set it to print as warnings, so the yellow color is easier to spot. Some important prints ignore this setting."); DebugConfig.ResetAllFavoritingData = Config.Bind(text8, "ResetAllFavoritingData", ResetFavoritingData.No, "This deletes all the favoriting of your items and slots, as well as trash flagging, the next time the mod checks for it (either on loading a character or on config change while ingame), and then resets this config back to 'No'."); DebugConfig.ResetAllFavoritingData.SettingChanged -= ResetAllFavoritingData_SettingChanged; DebugConfig.ResetAllFavoritingData.SettingChanged += ResetAllFavoritingData_SettingChanged; DebugConfig.DebugSeverity = Config.Bind(text8, "DebugSeverity", DebugSeverity.Normal, $"Filters which kind of debug messages are shown when {DebugConfig.ShowDebugLogs} is not disabled. Only use {DebugSeverity.Everything} for testing."); text8 = "9 - Localization"; LocalizationConfig.TrashLabel = Config.Bind(text8, "TrashLabel", string.Empty, string.Empty); LocalizationConfig.TrashLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.QuickStackLabel = Config.Bind(text8, "QuickStackLabel", string.Empty, string.Empty); LocalizationConfig.QuickStackLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.StoreAllLabel = Config.Bind(text8, "StoreAllLabel", string.Empty, string.Empty); LocalizationConfig.StoreAllLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.TakeAllLabel = Config.Bind(text8, "TakeAllLabel", string.Empty, string.Empty); LocalizationConfig.TakeAllLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.RestockLabel = Config.Bind(text8, "RestockLabel", string.Empty, string.Empty); LocalizationConfig.RestockLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.SortLabel = Config.Bind(text8, "SortLabel", string.Empty, string.Empty); LocalizationConfig.SortLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.QuickStackLabelCharacter = Config.Bind(text8, "QuickStackLabelCharacter", string.Empty, string.Empty); LocalizationConfig.QuickStackLabelCharacter.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.SortLabelCharacter = Config.Bind(text8, "SortLabelCharacter", string.Empty, string.Empty); LocalizationConfig.SortLabelCharacter.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.RestockLabelCharacter = Config.Bind(text8, "RestockLabelCharacter", string.Empty, string.Empty); LocalizationConfig.RestockLabelCharacter.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.SortByInternalNameLabel = Config.Bind(text8, "SortByInternalNameLabel", string.Empty, string.Empty); LocalizationConfig.SortByInternalNameLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.SortByTranslatedNameLabel = Config.Bind(text8, "SortByTranslatedNameLabel", string.Empty, string.Empty); LocalizationConfig.SortByTranslatedNameLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.SortByValueLabel = Config.Bind(text8, "SortByValueLabel", string.Empty, string.Empty); LocalizationConfig.SortByValueLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.SortByWeightLabel = Config.Bind(text8, "SortByWeightLabel", string.Empty, string.Empty); LocalizationConfig.SortByWeightLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.SortByTypeLabel = Config.Bind(text8, "SortByTypeLabel", string.Empty, string.Empty); LocalizationConfig.SortByTypeLabel.SettingChanged += delegate { ButtonRenderer.OnButtonTextTranslationSettingChanged(); }; LocalizationConfig.QuickStackResultMessageNothing = Config.Bind(text8, "QuickStackResultMessageNothing", string.Empty, string.Empty); LocalizationConfig.QuickStackResultMessageNone = Config.Bind(text8, "QuickStackResultMessageNone", string.Empty, string.Empty); LocalizationConfig.QuickStackResultMessageOne = Config.Bind(text8, "QuickStackResultMessageOne", string.Empty, string.Empty); LocalizationConfig.QuickStackResultMessageMore = Config.Bind(text8, "QuickStackResultMessageMore", string.Empty, string.Empty); LocalizationConfig.RestockResultMessageNothing = Config.Bind(text8, "RestockResultMessageNothing", string.Empty, string.Empty); LocalizationConfig.RestockResultMessageNone = Config.Bind(text8, "RestockResultMessageNone", string.Empty, string.Empty); LocalizationConfig.RestockResultMessagePartial = Config.Bind(text8, "RestockResultMessagePartial", string.Empty, string.Empty); LocalizationConfig.RestockResultMessageFull = Config.Bind(text8, "RestockResultMessageFull", string.Empty, string.Empty); LocalizationConfig.TrashConfirmationOkayButton = Config.Bind(text8, "TrashConfirmationOkayButton", string.Empty, string.Empty); LocalizationConfig.QuickTrashConfirmation = Config.Bind(text8, "QuickTrashConfirmation", string.Empty, string.Empty); LocalizationConfig.CantTrashFavoritedItemWarning = Config.Bind(text8, "CantTrashFavoritedItemWarning", string.Empty, string.Empty); LocalizationConfig.CantTrashHotkeyBarItemWarning = Config.Bind(text8, "CantTrashHotkeyBarItemWarning", string.Empty, string.Empty); LocalizationConfig.CantTrashFlagFavoritedItemWarning = Config.Bind(text8, "CantTrashFlagFavoritedItemWarning", string.Empty, string.Empty); LocalizationConfig.CantFavoriteTrashFlaggedItemWarning = Config.Bind(text8, "CantFavoriteTrashFlaggedItemWarning", string.Empty, string.Empty); LocalizationConfig.FavoritedItemTooltip = Config.Bind(text8, "FavoritedItemTooltip", string.Empty, string.Empty); LocalizationConfig.TrashFlaggedItemTooltip = Config.Bind(text8, "TrashFlaggedItemTooltip", string.Empty, string.Empty); keyBinds.Clear(); keyBinds.Add((ConfigEntryBase)(object)ControllerConfig.ControllerDPadUsageModifierKeybind); keyBinds.Add((ConfigEntryBase)(object)FavoriteConfig.FavoritingModifierKeybind1); keyBinds.Add((ConfigEntryBase)(object)FavoriteConfig.FavoritingModifierKeybind2); keyBinds.Add((ConfigEntryBase)(object)QuickStackConfig.QuickStackKeybind); keyBinds.Add((ConfigEntryBase)(object)TrashConfig.QuickTrashKeybind); keyBinds.Add((ConfigEntryBase)(object)RestockConfig.RestockKeybind); keyBinds.Add((ConfigEntryBase)(object)SortConfig.SortKeybind); keyBinds.Add((ConfigEntryBase)(object)StoreTakeAllConfig.StoreAllKeybind); keyBinds.Add((ConfigEntryBase)(object)StoreTakeAllConfig.TakeAllKeybind); keyBinds.Add((ConfigEntryBase)(object)TrashConfig.TrashKeybind); } internal static void ConfigTemplate_SettingChanged(object sender, EventArgs e) { GeneralConfig.ConfigTemplate.SettingChanged -= ConfigTemplate_SettingChanged; ApplyTemplate(GeneralConfig.ConfigTemplate.Value); GeneralConfig.ConfigTemplate.Value = ConfigTemplate.NotCurrentlyLoadingTemplate; GeneralConfig.ConfigTemplate.SettingChanged += ConfigTemplate_SettingChanged; } internal static void ApplyTemplate(ConfigTemplate template) { if (GeneralConfig.ConfigTemplate.Value == ConfigTemplate.NotCurrentlyLoadingTemplate) { return; } HashSet hashSet = new HashSet(keyBinds.Select((ConfigEntryBase a) => a.Definition.Key)); foreach (KeyValuePair item in Config) { if (!hashSet.Contains(item.Key.Key)) { item.Value.BoxedValue = item.Value.DefaultValue; } } switch (template) { case ConfigTemplate.BasicControllerKeybinds: GeneralConfig.OverrideKeybindBehavior.Value = OverrideKeybindBehavior.DisableAllNewHotkeys; ControllerConfig.UseHardcodedControllerSupport.Value = true; ControllerConfig.ControllerDPadUsageInInventoryGrid.Value = DPadUsage.Keybinds; ControllerConfig.RemoveControllerButtonHintFromTakeAllButton.Value = false; break; case ConfigTemplate.CustomControllerKeybinds: GeneralConfig.OverrideKeybindBehavior.Value = OverrideKeybindBehavior.UseIndividualConfigOptions; FavoriteConfig.DisplayFavoriteToggleButton.Value = FavoritingToggling.Disabled; ControllerConfig.UseHardcodedControllerSupport.Value = false; ControllerConfig.ControllerDPadUsageInInventoryGrid.Value = DPadUsage.InventorySlotMovement; ControllerConfig.RemoveControllerButtonHintFromTakeAllButton.Value = true; break; case ConfigTemplate.MouseAndKeyboardWithButtons: GeneralConfig.OverrideKeybindBehavior.Value = OverrideKeybindBehavior.DisableAllNewHotkeys; break; case ConfigTemplate.MouseAndKeyboardWithHotkeys: GeneralConfig.OverrideButtonDisplay.Value = OverrideButtonDisplay.DisableAllNewButtons; GeneralConfig.OverrideKeybindBehavior.Value = OverrideKeybindBehavior.UseIndividualConfigOptions; break; case ConfigTemplate.GoldensChoice: GeneralConfig.OverrideKeybindBehavior.Value = OverrideKeybindBehavior.DisableAllNewHotkeys; GeneralConfig.OverrideButtonDisplay.Value = OverrideButtonDisplay.UseIndividualConfigOptions; GeneralConfig.OverrideHotkeyBarBehavior.Value = OverrideHotkeyBarBehavior.UseIndividualConfigOptions; QuickStackRestockConfig.AllowAreaStackingInMultiplayerWithoutMUC.Value = true; RestockConfig.RestockOnlyAmmoAndConsumables.Value = false; RestockConfig.RestockOnlyFavoritedItems.Value = true; break; } Config.Save(); } internal static void ResetAllFavoritingData_SettingChanged(object sender, EventArgs e) { ConfigEntry resetAllFavoritingData = DebugConfig.ResetAllFavoritingData; if (resetAllFavoritingData != null && resetAllFavoritingData.Value == ResetFavoritingData.YesDeleteAllMyFavoritingData) { DebugConfig.ResetAllFavoritingData.SettingChanged -= ResetAllFavoritingData_SettingChanged; DebugConfig.ResetAllFavoritingData.Value = ResetFavoritingData.No; DebugConfig.ResetAllFavoritingData.SettingChanged += ResetAllFavoritingData_SettingChanged; if ((Object)(object)Player.m_localPlayer != (Object)null) { UserConfig playerConfig = UserConfig.GetPlayerConfig(Player.m_localPlayer.GetPlayerID()); playerConfig.ResetAllFavoriting(); } } } public static bool TryGetOldConfigValue(ConfigDefinition configDefinition, ref T oldValue, bool removeIfFound = true) { if (!TomlTypeConverter.CanConvert(typeof(T))) { throw new ArgumentException(string.Format("Type {0} is not supported by the config system. Supported types: {1}", typeof(T), string.Join(", ", (from x in TomlTypeConverter.GetSupportedTypes() select x.Name).ToArray()))); } try { object obj = AccessTools.FieldRefAccess("_ioLock").Invoke(Config); Dictionary dictionary = (Dictionary)AccessTools.PropertyGetter(typeof(ConfigFile), "OrphanedEntries").Invoke(Config, new object[0]); lock (obj) { if (dictionary.TryGetValue(configDefinition, out var value)) { oldValue = (T)TomlTypeConverter.ConvertToValue(value, typeof(T)); if (removeIfFound) { dictionary.Remove(configDefinition); } return true; } } } catch (Exception ex) { Helper.LogO("Error getting orphaned entry: " + ex.StackTrace); } return false; } public static void KeyCodeBackwardsCompatibility(ConfigEntry configEntry, string sectionName, string oldEntry) { //IL_0002: 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_0012: Expected O, but got Unknown //IL_0018: 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) KeyCode oldValue = (KeyCode)0; if (TryGetOldConfigValue(new ConfigDefinition(sectionName, oldEntry), ref oldValue)) { configEntry.Value = new KeyboardShortcut(oldValue, Array.Empty()); } } } internal class ButtonRenderer { internal class MainButtonUpdate { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__0_4; public static UnityAction <>9__0_5; public static UnityAction <>9__0_6; public static UnityAction <>9__0_7; public static UnityAction <>9__0_0; public static UnityAction <>9__0_1; public static UnityAction <>9__0_2; internal void b__0_4() { SortModule.SortPlayerInv(((Humanoid)Player.m_localPlayer).m_inventory, UserConfig.GetPlayerConfig(Player.m_localPlayer.GetPlayerID())); } internal void b__0_5() { RestockModule.DoRestock(Player.m_localPlayer); } internal void b__0_6() { QuickStackModule.DoQuickStack(Player.m_localPlayer); } internal void b__0_7() { FavoritingMode.ToggleFavoriteToggling(); } internal void b__0_0() { QuickStackModule.DoQuickStack(Player.m_localPlayer, onlyQuickStackToCurrentContainer: true); } internal void b__0_1() { StoreTakeAllModule.StoreAllItemsInOrder(Player.m_localPlayer); } internal void b__0_2() { RestockModule.DoRestock(Player.m_localPlayer, RestockOnlyFromCurrentContainerOverride: true); } } internal static void UpdateInventoryGuiButtons(InventoryGui __instance) { //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: 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) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Expected O, but got Unknown //IL_0541: Unknown result type (might be due to invalid IL or missing references) //IL_0546: Unknown result type (might be due to invalid IL or missing references) //IL_054c: Expected O, but got Unknown //IL_0993: Unknown result type (might be due to invalid IL or missing references) //IL_0a3a: Unknown result type (might be due to invalid IL or missing references) //IL_09c4: Unknown result type (might be due to invalid IL or missing references) //IL_09c9: Unknown result type (might be due to invalid IL or missing references) //IL_09cf: Expected O, but got Unknown //IL_068a: Unknown result type (might be due to invalid IL or missing references) //IL_068f: Unknown result type (might be due to invalid IL or missing references) //IL_0695: Expected O, but got Unknown //IL_0add: Unknown result type (might be due to invalid IL or missing references) //IL_0b01: Unknown result type (might be due to invalid IL or missing references) //IL_0b0b: Expected O, but got Unknown //IL_0a6b: Unknown result type (might be due to invalid IL or missing references) //IL_0a70: Unknown result type (might be due to invalid IL or missing references) //IL_0a76: Expected O, but got Unknown //IL_08cc: Unknown result type (might be due to invalid IL or missing references) //IL_08f9: Unknown result type (might be due to invalid IL or missing references) //IL_0927: Unknown result type (might be due to invalid IL or missing references) //IL_092c: Unknown result type (might be due to invalid IL or missing references) //IL_0932: Expected O, but got Unknown //IL_081a: Unknown result type (might be due to invalid IL or missing references) //IL_081f: Unknown result type (might be due to invalid IL or missing references) //IL_0825: Expected O, but got Unknown if (!hasOpenedInventoryOnce || (Object)(object)__instance != (Object)(object)InventoryGui.instance) { return; } if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { FavoritingMode.HasCurrentlyToggledFavoriting = false; QSSConfig.AutoSortBehavior value = QSSConfig.SortConfig.AutoSort.Value; if (value == QSSConfig.AutoSortBehavior.SortPlayerInventoryOnOpen || value == QSSConfig.AutoSortBehavior.Both) { SortModule.SortPlayerInv(((Humanoid)Player.m_localPlayer).m_inventory, UserConfig.GetPlayerConfig(Player.m_localPlayer.GetPlayerID())); } if (Object.op_Implicit((Object)(object)__instance.m_currentContainer) && (value == QSSConfig.AutoSortBehavior.SortContainerOnOpen || value == QSSConfig.AutoSortBehavior.Both)) { SortModule.SortContainer(__instance.m_currentContainer); } } RectTransform val = default(RectTransform); if (!Object.op_Implicit((Object)(object)__instance.m_takeAllButton) || !((Component)__instance.m_takeAllButton).TryGetComponent(ref val)) { return; } ControllerButtonHintHelper.FixTakeAllButtonControllerHint(__instance); if (origButtonLength == -1f) { origButtonLength = val.sizeDelta.x; origButtonPosition = ((Transform)val).localPosition; } if (val.sizeDelta.x == origButtonLength) { val.SetSizeWithCurrentAnchors((Axis)0, origButtonLength * 0.9f); } int num = 0; bool value2 = QSSConfig.StoreTakeAllConfig.DisplayStoreAllButton.Value; QSSConfig.ShowTwoButtons value3 = QSSConfig.QuickStackConfig.DisplayQuickStackButtons.Value; QSSConfig.ShowTwoButtons value4 = QSSConfig.RestockConfig.DisplayRestockButtons.Value; QSSConfig.ShowTwoButtons value5 = QSSConfig.SortConfig.DisplaySortButtons.Value; if (QSSConfig.GeneralConfig.OverrideButtonDisplay.Value != 0) { if (value2) { num++; } if (value3.ShouldSpawnContainerButton()) { num++; } if (value4.ShouldSpawnContainerButton()) { num++; } if (value5.ShouldSpawnContainerButton()) { num++; } } float num2 = val.sizeDelta.y + 8f; Vector3 val2 = ((Transform)val).localPosition; if (((Transform)val).localPosition == origButtonPosition) { if (num <= 1) { val2 -= new Vector3(origButtonLength / 2f * 0.100000024f, 0f); } else { val2 = OppositePositionOfTakeAllButton(); bool flag = !value3.ShouldSpawnContainerButton(); val2 += new Vector3(origButtonLength - 1f, flag ? 0f : (0f - num2)); } if (!CompatibilitySupport.ShouldBlockChangesToTakeAllButton()) { ((Transform)val).localPosition = val2; } } if (QSSConfig.GeneralConfig.OverrideButtonDisplay.Value == QSSConfig.OverrideButtonDisplay.DisableAllNewButtons) { return; } int num3 = 0; bool hasSpawnedCurrencyPocketUI = false; Transform val3; if (CompatibilitySupport.HasPlugin("Azumatt.CurrencyPocket")) { hasSpawnedCurrencyPocketUI = hasCompletedOpeningInventoryOnce; val3 = ((Component)__instance.m_player).transform.Find("CoinPocketUI"); } else { val3 = ((Component)__instance.m_player).transform.Find("Weight"); } CompatibilitySupport.RandyStatus randyStatus = CompatibilitySupport.HasRandyPlugin(); if (value5.ShouldSpawnMiniInventoryButton()) { bool flag2 = value5.ShouldShowMiniInventoryButton(__instance); if ((Object)(object)sortInventoryButton == (Object)null) { sortInventoryButton = CreateMiniButton(__instance, "sortInventoryButton", "Back"); ((Component)sortInventoryButton).gameObject.SetActive(flag2); if (flag2) { ((MonoBehaviour)__instance).StartCoroutine(WaitAFrameToRepositionMiniButton(__instance, ((Component)sortInventoryButton).transform, val3, ++num3, randyStatus, hasSpawnedCurrencyPocketUI)); } ButtonClickedEvent onClick = sortInventoryButton.onClick; object obj = <>c.<>9__0_4; if (obj == null) { UnityAction val4 = delegate { SortModule.SortPlayerInv(((Humanoid)Player.m_localPlayer).m_inventory, UserConfig.GetPlayerConfig(Player.m_localPlayer.GetPlayerID())); }; <>c.<>9__0_4 = val4; obj = (object)val4; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } else { ((Component)sortInventoryButton).gameObject.SetActive(flag2); if (flag2) { RepositionMiniButton(__instance, ((Component)sortInventoryButton).transform, val3, ++num3, randyStatus, hasSpawnedCurrencyPocketUI); } } } bool flag3 = CompatibilitySupport.AllowAreaStackingRestocking(); if (flag3 && value4.ShouldSpawnMiniInventoryButton() && QSSConfig.RestockConfig.RestockFromNearbyRange.Value > 0f) { bool flag4 = value4.ShouldShowMiniInventoryButton(__instance) && (!Object.op_Implicit((Object)(object)__instance.m_currentContainer) || randyStatus != CompatibilitySupport.RandyStatus.EnabledWithQuickSlots); if ((Object)(object)restockAreaButton == (Object)null) { restockAreaButton = CreateMiniButton(__instance, "restockAreaButton", "DPadUp"); ((Component)restockAreaButton).gameObject.SetActive(flag4); if (flag4) { ((MonoBehaviour)__instance).StartCoroutine(WaitAFrameToRepositionMiniButton(__instance, ((Component)restockAreaButton).transform, val3, ++num3, randyStatus, hasSpawnedCurrencyPocketUI)); } ButtonClickedEvent onClick2 = restockAreaButton.onClick; object obj2 = <>c.<>9__0_5; if (obj2 == null) { UnityAction val5 = delegate { RestockModule.DoRestock(Player.m_localPlayer); }; <>c.<>9__0_5 = val5; obj2 = (object)val5; } ((UnityEvent)onClick2).AddListener((UnityAction)obj2); } else { ((Component)restockAreaButton).gameObject.SetActive(flag4); if (flag4) { RepositionMiniButton(__instance, ((Component)restockAreaButton).transform, val3, ++num3, randyStatus, hasSpawnedCurrencyPocketUI); } } } if (flag3 && value3.ShouldSpawnMiniInventoryButton() && QSSConfig.QuickStackConfig.QuickStackToNearbyRange.Value > 0f) { bool flag5 = value3.ShouldShowMiniInventoryButton(__instance) && (!Object.op_Implicit((Object)(object)__instance.m_currentContainer) || randyStatus != CompatibilitySupport.RandyStatus.EnabledWithQuickSlots); if ((Object)(object)quickStackAreaButton == (Object)null) { quickStackAreaButton = CreateMiniButton(__instance, "quickStackAreaButton", "DPadDown"); ((Component)quickStackAreaButton).gameObject.SetActive(flag5); if (flag5) { ((MonoBehaviour)__instance).StartCoroutine(WaitAFrameToRepositionMiniButton(__instance, ((Component)quickStackAreaButton).transform, val3, ++num3, randyStatus, hasSpawnedCurrencyPocketUI)); } ButtonClickedEvent onClick3 = quickStackAreaButton.onClick; object obj3 = <>c.<>9__0_6; if (obj3 == null) { UnityAction val6 = delegate { QuickStackModule.DoQuickStack(Player.m_localPlayer); }; <>c.<>9__0_6 = val6; obj3 = (object)val6; } ((UnityEvent)onClick3).AddListener((UnityAction)obj3); } else { ((Component)quickStackAreaButton).gameObject.SetActive(flag5); if (flag5) { RepositionMiniButton(__instance, ((Component)quickStackAreaButton).transform, val3, ++num3, randyStatus, hasSpawnedCurrencyPocketUI); } } } QSSConfig.FavoritingToggling value6 = QSSConfig.FavoriteConfig.DisplayFavoriteToggleButton.Value; if (value6 != 0) { int existingMiniButtons; Transform anchor; if (value6 == QSSConfig.FavoritingToggling.EnabledBottomButton || CompatibilitySupport.HasPlugin("Azumatt.CurrencyPocket")) { existingMiniButtons = ++num3; anchor = val3; } else { existingMiniButtons = -1; anchor = ((Component)__instance.m_player).transform.Find("Armor"); } bool flag6 = !Object.op_Implicit((Object)(object)__instance.m_currentContainer) || randyStatus != CompatibilitySupport.RandyStatus.EnabledWithQuickSlots; if ((Object)(object)favoritingTogglingButton == (Object)null) { favoritingTogglingButton = CreateMiniButton(__instance, "favoritingTogglingButton", "DPadLeft"); ((Component)favoritingTogglingButton).gameObject.SetActive(flag6); favoritingTogglingButtonText = ((Component)((Component)favoritingTogglingButton).transform.Find("Text")).GetComponent(); FavoritingMode.RefreshDisplay(); if (flag6) { ((MonoBehaviour)__instance).StartCoroutine(WaitAFrameToRepositionMiniButton(__instance, ((Component)favoritingTogglingButton).transform, anchor, existingMiniButtons, randyStatus, hasSpawnedCurrencyPocketUI)); } ButtonClickedEvent onClick4 = favoritingTogglingButton.onClick; object obj4 = <>c.<>9__0_7; if (obj4 == null) { UnityAction val7 = delegate { FavoritingMode.ToggleFavoriteToggling(); }; <>c.<>9__0_7 = val7; obj4 = (object)val7; } ((UnityEvent)onClick4).AddListener((UnityAction)obj4); } else { ((Component)favoritingTogglingButton).gameObject.SetActive(flag6); if (flag6) { RepositionMiniButton(__instance, ((Component)favoritingTogglingButton).transform, anchor, existingMiniButtons, randyStatus, hasSpawnedCurrencyPocketUI); } } } int num4 = 0; if (value3.ShouldSpawnContainerButton()) { if ((Object)(object)quickStackToContainerButton == (Object)null) { quickStackToContainerButton = CreateBigButton(__instance, "quickStackToContainerButton", "DPadDown"); if (CompatibilitySupport.ShouldBlockChangesToTakeAllButton() && randyStatus != CompatibilitySupport.RandyStatus.EnabledWithQuickSlots) { MoveButtonToIndex(ref quickStackToContainerButton, val2, 0f, num, 1); } else { bool forcePutAtOppositeOfTakeAll = randyStatus == CompatibilitySupport.RandyStatus.EnabledWithQuickSlots || CompatibilitySupport.HasPlugin("Azumatt.CurrencyPocket"); MoveButtonToIndex(ref quickStackToContainerButton, val2, 0f - num2, num, 1, forcePutAtOppositeOfTakeAll); } ButtonClickedEvent onClick5 = quickStackToContainerButton.onClick; object obj5 = <>c.<>9__0_0; if (obj5 == null) { UnityAction val8 = delegate { QuickStackModule.DoQuickStack(Player.m_localPlayer, onlyQuickStackToCurrentContainer: true); }; <>c.<>9__0_0 = val8; obj5 = (object)val8; } ((UnityEvent)onClick5).AddListener((UnityAction)obj5); } ((Component)quickStackToContainerButton).gameObject.SetActive(value3.ShouldShowContainerButton(__instance)); } if (value2) { if ((Object)(object)storeAllButton == (Object)null) { storeAllButton = CreateBigButton(__instance, "storeAllButton", "RStick"); MoveButtonToIndex(ref storeAllButton, val2, num2, num, ++num4); ButtonClickedEvent onClick6 = storeAllButton.onClick; object obj6 = <>c.<>9__0_1; if (obj6 == null) { UnityAction val9 = delegate { StoreTakeAllModule.StoreAllItemsInOrder(Player.m_localPlayer); }; <>c.<>9__0_1 = val9; obj6 = (object)val9; } ((UnityEvent)onClick6).AddListener((UnityAction)obj6); } ((Component)storeAllButton).gameObject.SetActive((Object)(object)__instance.m_currentContainer != (Object)null); } if (value4.ShouldSpawnContainerButton()) { if ((Object)(object)restockFromContainerButton == (Object)null) { restockFromContainerButton = CreateBigButton(__instance, "restockFromContainerButton", "DPadUp"); MoveButtonToIndex(ref restockFromContainerButton, val2, num2, num, ++num4); ButtonClickedEvent onClick7 = restockFromContainerButton.onClick; object obj7 = <>c.<>9__0_2; if (obj7 == null) { UnityAction val10 = delegate { RestockModule.DoRestock(Player.m_localPlayer, RestockOnlyFromCurrentContainerOverride: true); }; <>c.<>9__0_2 = val10; obj7 = (object)val10; } ((UnityEvent)onClick7).AddListener((UnityAction)obj7); } ((Component)restockFromContainerButton).gameObject.SetActive(value4.ShouldShowContainerButton(__instance)); } if (value5.ShouldSpawnContainerButton()) { if ((Object)(object)sortContainerButton == (Object)null) { sortContainerButton = CreateBigButton(__instance, "sortContainerButton", "Back"); MoveButtonToIndex(ref sortContainerButton, val2, num2, num, ++num4); ((UnityEvent)sortContainerButton.onClick).AddListener((UnityAction)delegate { SortModule.SortContainer(__instance.m_currentContainer); }); } ((Component)sortContainerButton).gameObject.SetActive(value5.ShouldShowContainerButton(__instance)); } if (!CompatibilitySupport.ShouldBlockChangesToTakeAllButton()) { ((Component)val).gameObject.SetActive((Object)(object)__instance.m_currentContainer != (Object)null); } RectTransform val11 = default(RectTransform); if (Object.op_Implicit((Object)(object)__instance.m_stackAllButton) && ((Component)__instance.m_stackAllButton).TryGetComponent(ref val11)) { bool active = randyStatus != CompatibilitySupport.RandyStatus.EnabledWithQuickSlots && !QSSConfig.QuickStackConfig.HideBaseGamePlaceStacksButton.Value; ((Component)val11).gameObject.SetActive(active); } OnButtonTextTranslationSettingChanged(includeTrashButton: false); } } internal static bool hasOpenedInventoryOnce = false; internal static bool hasCompletedOpeningInventoryOnce = false; internal static float origButtonLength = -1f; internal static Vector3 origButtonPosition; internal static TextMeshProUGUI favoritingTogglingButtonText; internal static Button favoritingTogglingButton; internal static Button quickStackAreaButton; internal static Button sortInventoryButton; internal static Button restockAreaButton; internal static Button quickStackToContainerButton; internal static Button storeAllButton; internal static Button sortContainerButton; internal static Button restockFromContainerButton; private const float shrinkFactor = 0.9f; private const int vPadding = 8; private const int hAlign = 1; private const int miniButtonSize = 38; private const int miniButtonHPadding = 2; private const float normalMiniButtonVOffset = -56f; private const float lowerMiniButtonVOffset = -75f; private static void MoveButtonToIndex(ref Button buttonToMove, Vector3 startVector, float vOffset, int visibleExtraButtons, int buttonsBelowTakeAll, bool forcePutAtOppositeOfTakeAll = false) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_004d: 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) if (visibleExtraButtons == 1 || forcePutAtOppositeOfTakeAll) { ((Component)buttonToMove).transform.localPosition = OppositePositionOfTakeAllButton(); return; } ((Component)buttonToMove).transform.localPosition = startVector; Transform transform = ((Component)buttonToMove).transform; transform.localPosition -= new Vector3(0f, (float)buttonsBelowTakeAll * vOffset); } private static Vector3 OppositePositionOfTakeAllButton() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0031: Unknown result type (might be due to invalid IL or missing references) float num = origButtonLength / 2f * 0.100000024f; return origButtonPosition + new Vector3(440f + num, 0f); } public static string SortCriteriaToShortHumanReadableString(QSSConfig.SortCriteriaEnum sortingCriteria) { return sortingCriteria switch { QSSConfig.SortCriteriaEnum.InternalName => LocalizationConfig.GetRelevantTranslation(LocalizationConfig.SortByInternalNameLabel, "SortByInternalNameLabel"), QSSConfig.SortCriteriaEnum.TranslatedName => LocalizationConfig.GetRelevantTranslation(LocalizationConfig.SortByTranslatedNameLabel, "SortByTranslatedNameLabel"), QSSConfig.SortCriteriaEnum.Value => LocalizationConfig.GetRelevantTranslation(LocalizationConfig.SortByValueLabel, "SortByValueLabel"), QSSConfig.SortCriteriaEnum.Weight => LocalizationConfig.GetRelevantTranslation(LocalizationConfig.SortByWeightLabel, "SortByWeightLabel"), QSSConfig.SortCriteriaEnum.Type => LocalizationConfig.GetRelevantTranslation(LocalizationConfig.SortByTypeLabel, "SortByTypeLabel"), _ => "invalid", }; } private static Button CreateAbstractButton(InventoryGui instance, string name, string joyHint, Transform parent) { UIGamePad component = ((Component)instance.m_takeAllButton).GetComponent(); bool enabled = ((Behaviour)component).enabled; ((Behaviour)component).enabled = false; Button val = Object.Instantiate