Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of OpenKeep v1.8.0
plugins\OpenKeep.dll
Decompiled 16 hours ago
The result has been truncated due to the large size, download it to view full contents!
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.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Charter; using ConfigReload; using HarmonyLib; using ItemCopies; using Microsoft.CodeAnalysis; using OpenKeep.Batch; using OpenKeep.Capacity; using OpenKeep.Carts; using OpenKeep.Core; using OpenKeep.Homestead; using OpenKeep.Reach; using OpenKeep.Salvage; using OpenKeep.Shared; using OpenKeep.Signs; using OpenKeep.Stacks; using OpenKeep.Stow; using PatchGuard; using PlateColumn; using SyncedConfig; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; using YamlConfig; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; 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: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("OpenKeep")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("OpenKeep: storage and inventory for Valheim")] [assembly: AssemblyFileVersion("1.8.0.0")] [assembly: AssemblyInformationalVersion("1.8.0+9a329d5c191afce69442cfc563644a5560c4fc74")] [assembly: AssemblyProduct("OpenKeep")] [assembly: AssemblyTitle("OpenKeep")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.8.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OpenKeep { [BepInPlugin("milkyteam.openkeep", "OpenKeep", "1.8.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "milkyteam.openkeep"; public const string PluginName = "OpenKeep"; public const string PluginVersion = "1.8.0"; public static ManualLogSource Log { get; private set; } public static SyncedConfiguration Synced { get; private set; } public static ConfigEntry<bool> LockConfiguration { get; private set; } public static Plugin Instance { get; private set; } private void Awake() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Synced = new SyncedConfiguration((BaseUnityPlugin)(object)this, ((BaseUnityPlugin)this).Logger, "OpenKeep", "1.8.0"); LockConfiguration = Synced.BindLocking("General", "Lock Configuration", defaultValue: true, "[Server Only] Clients cannot change synced settings while connected to a server that has this on."); InitializeModules(); Harmony harmony = new Harmony("milkyteam.openkeep"); int num = PatchEverything(harmony); StacksModule.HookSpawns(harmony); Synced.Finish(harmony); Log.LogInfo((object)("Loading [OpenKeep 1.8.0]" + ((num > 0) ? $" with {num} failed patches, see above" : ""))); Guard.Install(harmony, ((BaseUnityPlugin)this).Logger, Assembly.GetExecutingAssembly()); } private static void InitializeModules() { CoreModule.Initialize(Synced); ReachModule.Initialize(Synced); StowModule.Initialize(Synced); SalvageModule.Initialize(Synced); StacksModule.Initialize(Synced); CapacityModule.Initialize(Synced); CartsModule.Initialize(Synced); SignsModule.Initialize(Synced); HomesteadModule.Initialize(Synced); SharedModule.Initialize(Synced); BatchModule.Initialize(Synced); } private void Update() { Synced.YamlEditor.Update(); } private void OnGUI() { Synced.YamlEditor.OnGUI(); } private static int PatchEverything(Harmony harmony) { int num = 0; Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly()); foreach (Type type in typesFromAssembly) { if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length != 0) { try { harmony.CreateClassProcessor(type).Patch(); } catch (Exception ex) { num++; Log.LogError((object)("Patch " + type.FullName + " failed to apply: " + ex.Message)); } } } return num; } } } namespace OpenKeep.Stow { [HarmonyPatch(typeof(InventoryGui), "Show")] public static class AutoSortPatch { [HarmonyPrefix] public static void Prefix(InventoryGui __instance, out bool __state) { __state = InventoryGui.IsVisible(); } [HarmonyPostfix] public static void Postfix(Container container, bool __state) { if (StowSettings.Enabled.Value && !((Object)(object)Player.m_localPlayer == (Object)null)) { if ((Object)(object)container != (Object)null && StowSettings.AutoSortContainers.Value) { Sorting.SortContainer(container, quiet: true); } if (!__state && StowSettings.AutoSortInventory.Value) { Sorting.SortPlayer(Player.m_localPlayer, quiet: true); } } } } internal sealed class ChestBatch { private readonly Container container; private readonly string word; private int pending; private bool finished; public bool Shared { get; } public int Moved { get; private set; } public bool Waiting => pending > 0; public ChestBatch(Container container, string word) { this.container = container; this.word = word; Shared = StowTargets.IsShared(container); } public void Put(ItemData item, int amount, int credit) { pending++; StackMover.Reserve(item); ChestWriter.Put(container, item, amount, null, delegate(bool ok) { StackMover.Release(item); Reply(ok, credit); }); } public void Take(ItemData item, int amount, int credit) { pending++; ChestWriter.Take(container, item, amount, delegate(bool ok) { Reply(ok, credit); }); } public void Finish() { finished = true; } private void Reply(bool ok, int credit) { pending--; if (ok) { Moved += credit; } if (finished && pending == 0) { Report(); } } private void Report() { if (Moved > 0) { Messages.Center(StowWords.Format(word, Moved, StowTargets.Name(container))); } } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] public static class ClickRouting { [HarmonyPrefix] public static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Modifier mod) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 if (!StowSettings.Enabled.Value || item == null || (Object)(object)__instance.m_dragGo != (Object)null || (Object)(object)grid != (Object)(object)__instance.m_playerGrid) { return true; } if ((int)mod == 3 || !Keys.Held(StowSettings.RouteModifier)) { return true; } Routing.Route(item); return false; } } public static class Cycling { private const float WheelCooldown = 0.25f; private static float lastWheel; public static void Poll(InventoryGui gui) { if (!((Object)(object)gui.m_currentContainer == (Object)null)) { if (Keys.Pressed(StowSettings.CyclePreviousKey)) { Cycle(-1); } else if (Keys.Pressed(StowSettings.CycleNextKey)) { Cycle(1); } else if (StowSettings.CycleWithWheel.Value) { PollWheel(gui); } } } private static void PollWheel(InventoryGui gui) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) float mouseScrollWheel = ZInput.GetMouseScrollWheel(); if (mouseScrollWheel == 0f || Time.time - lastWheel < 0.25f || Keys.TextInputActive || (Object)(object)gui.m_containerGrid == (Object)null) { return; } Transform transform = ((Component)gui.m_containerGrid).transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (!((Object)(object)val == (Object)null)) { Rect rect = val.rect; if (((Rect)(ref rect)).Contains(Vector2.op_Implicit(((Transform)val).InverseTransformPoint(ZInput.pointerPosition)))) { lastWheel = Time.time; Cycle((!(mouseScrollWheel > 0f)) ? 1 : (-1)); } } } public static void Cycle(int direction) { if (!StowActions.Ready(out var player)) { return; } InventoryGui instance = InventoryGui.instance; Container val = (((Object)(object)instance != (Object)null) ? instance.m_currentContainer : null); if (!((Object)(object)val == (Object)null)) { List<Container> list = Ring(player, instance, val); if (list.Count < 2) { Messages.Center("$ok_stow_nocycle"); return; } int num = list.IndexOf(val); Container obj = list[(num + direction + list.Count) % list.Count]; instance.CloseContainer(); obj.Interact((Humanoid)(object)player, false, false); } } private static List<Container> Ring(Player player, InventoryGui gui, Container current) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(StowSettings.NearbyRange.Value, gui.m_autoCloseDistance); Vector3 origin = ((Component)player).transform.position; List<Container> list = ContainerScan.Nearby(origin, num, ContainerUse.Stow); foreach (Container item in ContainerScan.All()) { if (!list.Contains(item) && StowTargets.Distance(origin, item) <= num && Viewable(item)) { list.Add(item); } } if (!list.Contains(current)) { list.Add(current); } list.Sort((Container a, Container b) => Angle(origin, a).CompareTo(Angle(origin, b))); return list; } private static bool Viewable(Container container) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || CoreSettings.SharedChests.Value == SharedMode.Off || container.GetInventory() == null) { return false; } if (!ContainerScan.InUseByAnother(container) || !ContainerRules.IsEnabled(ContainerScan.PrefabName(container)) || !SwitchAllows(container)) { return false; } if (container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)) { return false; } if ((int)container.m_privacy == 0 && (Object)(object)container.m_piece == (Object)null) { return false; } return container.CheckAccess(localPlayer.GetPlayerID()); } private static bool SwitchAllows(Container container) { if (ContainerScan.IsShip(container)) { return CoreSettings.Ships.Value; } if (ContainerScan.IsCart(container)) { return CoreSettings.Carts.Value; } if (ContainerScan.IsPrivateChest(container)) { return CoreSettings.PlayerChests.Value; } return true; } private static float Angle(Vector3 origin, Container container) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)container).transform.position - origin; return Mathf.Atan2(val.z, val.x); } } [HarmonyPatch(typeof(Player), "Update")] public static class DumpKeyPatch { [HarmonyPostfix] public static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && StowSettings.Enabled.Value && !Keys.InventoryOpen && !Menu.IsVisible() && !Console.IsVisible() && !UnifiedPopup.IsVisible() && Keys.Pressed(StowSettings.DumpKey)) { StowActions.Dump(); } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] public static class FavouriteOverlay { [HarmonyPostfix] public static void Postfix(InventoryGrid __instance, Player player) { Refresh(__instance, (Object)(object)player != (Object)null); } public static void Refresh(InventoryGrid grid, bool playerGrid) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) bool flag = StowSettings.Enabled.Value && StowSettings.ShowFavourites.Value; Inventory inventory = grid.m_inventory; foreach (InventoryElement element in grid.m_elements) { SlotMarks slotMarks = ((Component)element).GetComponent<SlotMarks>(); if (!((Object)(object)slotMarks == (Object)null) || (flag && inventory != null)) { if ((Object)(object)slotMarks == (Object)null) { slotMarks = SlotMarks.Attach(element); } ItemData val = ((flag && inventory != null) ? inventory.GetItemAt(element.Position.x, element.Position.y) : null); bool favouriteItem = val != null && Favourites.IsFavouriteItem(val); bool favouriteSlot = flag && playerGrid && Favourites.IsFavouriteSlot(element.Position); bool junk = val != null && Favourites.IsJunk(val); slotMarks.Set(favouriteItem, favouriteSlot, junk); } } } } public static class Favourites { private const string ItemsKey = "favouriteItems"; private const string SlotsKey = "favouriteSlots"; private const string JunkKey = "junk"; private static Player cachedFor; private static HashSet<string> items; private static HashSet<string> slots; private static HashSet<string> junk; public static bool IsFavouriteItem(ItemData item) { if (item != null) { return Set(ref items, "favouriteItems").Contains(Id(item)); } return false; } public static bool IsJunk(ItemData item) { if (item != null) { return Set(ref junk, "junk").Contains(Id(item)); } return false; } public static bool IsFavouriteSlot(Vector2i pos) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) return Set(ref slots, "favouriteSlots").Contains(SlotId(pos)); } public static bool ToggleItem(ItemData item) { return Toggle(ref items, "favouriteItems", Id(item)); } public static bool ToggleSlot(Vector2i pos) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return Toggle(ref slots, "favouriteSlots", SlotId(pos)); } public static bool ToggleJunk(ItemData item) { return Toggle(ref junk, "junk", Id(item)); } public static void ToggleItemWithMessage(ItemData item) { Messages.Center(StowWords.Format(ToggleItem(item) ? "$ok_stow_favourite_on" : "$ok_stow_favourite_off", ItemNames.DisplayName(item))); } public static void ToggleSlotWithMessage(Vector2i pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) Messages.Center(StowWords.Format(ToggleSlot(pos) ? "$ok_stow_slot_on" : "$ok_stow_slot_off", pos.x + 1 + "," + (pos.y + 1))); } public static void ToggleJunkWithMessage(ItemData item) { Messages.Center(StowWords.Format(ToggleJunk(item) ? "$ok_stow_junk_on" : "$ok_stow_junk_off", ItemNames.DisplayName(item))); } private static string Id(ItemData item) { return ItemNames.PrefabName(item); } private static string SlotId(Vector2i pos) { return pos.x + ":" + pos.y; } private static bool Toggle(ref HashSet<string> set, string key, string id) { if (string.IsNullOrEmpty(id)) { return false; } HashSet<string> hashSet = Set(ref set, key); bool num = !hashSet.Remove(id); if (num) { hashSet.Add(id); } CharacterData.SetSet(key, hashSet); return num; } private static HashSet<string> Set(ref HashSet<string> set, string key) { if ((Object)(object)cachedFor != (Object)(object)Player.m_localPlayer) { items = (slots = (junk = null)); cachedFor = Player.m_localPlayer; } return set ?? (set = CharacterData.GetSet(key)); } } public static class Finder { private const float DefaultSeconds = 5f; public static void Find(ItemData item) { if (!StowActions.Ready(out var player) || item == null) { return; } string text = ItemNames.DisplayName(item); float seconds = LinkSeconds(); int num = 0; foreach (Container item2 in StowTargets.Nearby(player)) { int num2 = item2.GetInventory().CountItems(item.m_shared.m_name, -1, false); if (num2 > 0) { num++; LinkMarker.Create(player, item2, text + " x" + num2, seconds); } } Messages.Center((num > 0) ? StowWords.Format("$ok_stow_found", text, num) : StowWords.Format("$ok_stow_notfound", text)); } public static float LinkSeconds() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown ConfigFile val = (((Object)(object)Plugin.Instance != (Object)null) ? ((BaseUnityPlugin)Plugin.Instance).Config : null); ConfigDefinition val2 = new ConfigDefinition("1. Reach", "Link Seconds"); if (val == null || !val.ContainsKey(val2)) { return 5f; } try { return Convert.ToSingle(val[val2].BoxedValue); } catch (Exception) { return 5f; } } } [HarmonyPatch(typeof(Container), "CheckForChanges")] public static class GroundPickup { private static readonly Dictionary<Container, float> nextSweep = new Dictionary<Container, float>(); [HarmonyPostfix] public static void Postfix(Container __instance) { Tick(__instance); } public static void Tick(Container container) { if (StowSettings.Enabled.Value && StowSettings.GroundPickup.Value && !((Object)(object)container == (Object)null)) { ZNetView nview = container.m_nview; if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner() && !container.IsInUse() && StowRules.PicksUp(container) && Due(container) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null) && ContainerScan.IsUsable(container, ContainerUse.Stow) && Sweep(container) > 0) { ContainerScan.Save(container); } } } private static bool Due(Container container) { float time = Time.time; float num = Mathf.Max(1f, StowSettings.PickupInterval.Value); if (!nextSweep.TryGetValue(container, out var value)) { nextSweep[container] = time + num * ((float)(((Object)container).GetInstanceID() & 0xFF) / 256f); if (nextSweep.Count > 64) { Prune(); } return false; } if (time < value) { return false; } nextSweep[container] = time + num; return true; } private static void Prune() { List<Container> list = new List<Container>(); foreach (Container key in nextSweep.Keys) { if ((Object)(object)key == (Object)null) { list.Add(key); } } foreach (Container item in list) { nextSweep.Remove(item); } } private static int Sweep(Container container) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)container).transform.position; float value = StowSettings.PickupRange.Value; int num = 0; foreach (ItemDrop item in new List<ItemDrop>(ItemDrop.s_instances)) { if ((Object)(object)item != (Object)null && Eligible(container, item, position, value)) { num += Take(container, item); } } return num; } private static bool Eligible(Container container, ItemDrop drop, Vector3 origin, float range) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) ZNetView nview = drop.m_nview; if ((Object)(object)nview == (Object)null || !nview.IsValid() || drop.m_itemData == null || drop.m_itemData.m_shared == null || drop.IsPiece()) { return false; } if (Vector3.Distance(origin, ((Component)drop).transform.position) > range) { return false; } if (Age(nview) < (double)StowSettings.PickupDelay.Value || !Wanted(container, drop.m_itemData)) { return false; } if (CoreSettings.HonourWards.Value) { return PrivateArea.CheckAccess(((Component)drop).transform.position, 0f, false, false); } return true; } private static double Age(ZNetView view) { long num = view.GetZDO().GetLong(ZDOVars.s_spawnTime, 0L); if (num == 0L || (Object)(object)ZNet.instance == (Object)null) { return -1.0; } return (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds; } private static bool Wanted(Container container, ItemData item) { if (StowRules.Refuses(container, item)) { return false; } if (StowRules.Accepts(container, item)) { return true; } if (StowSettings.PickupOnlyHeldItems.Value) { return container.GetInventory().ContainsItemByName(item.m_shared.m_name); } return true; } private static int Take(Container container, ItemDrop drop) { ZNetView nview = drop.m_nview; if (!nview.IsOwner()) { nview.ClaimOwnership(); } if (!nview.IsOwner()) { return 0; } drop.Load(); ItemData val = drop.m_itemData.Clone(); int stack = val.m_stack; if (stack <= 0) { return 0; } if (container.GetInventory().AddItem(val)) { ZNetScene.instance.Destroy(((Component)drop).gameObject); return stack; } int num = stack - val.m_stack; if (num > 0) { drop.m_itemData.m_stack = val.m_stack; drop.Save(); } return num; } } public static class HoveredItem { public static bool Find(InventoryGui gui, out InventoryGrid grid, out Vector2i pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) grid = null; pos = new Vector2i(-1, -1); if ((Object)(object)gui == (Object)null) { return false; } if (TryGrid(gui.m_playerGrid, out pos)) { grid = gui.m_playerGrid; return true; } if ((Object)(object)gui.m_currentContainer != (Object)null && (Object)(object)gui.m_container != (Object)null && ((Component)gui.m_container).gameObject.activeSelf && TryGrid(gui.m_containerGrid, out pos)) { grid = gui.m_containerGrid; return true; } return false; } public static ItemData Item(InventoryGrid grid, Vector2i pos) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)grid != (Object)null) || grid.m_inventory == null) { return null; } return grid.m_inventory.GetItemAt(pos.x, pos.y); } private static bool TryGrid(InventoryGrid grid, out Vector2i pos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) pos = new Vector2i(-1, -1); if ((Object)(object)grid == (Object)null || grid.m_inventory == null || !((Component)grid).gameObject.activeInHierarchy) { return false; } if ((Object)(object)grid.m_uiGroup != (Object)null && grid.m_uiGroup.IsActive && (ZInput.IsExclusiveGamepadActive() || ZInput.IsTouchActive())) { pos = grid.m_selected; if (pos.x >= 0) { return pos.y >= 0; } return false; } InventoryElement hoveredElement = grid.GetHoveredElement(); if ((Object)(object)hoveredElement == (Object)null) { return false; } pos = grid.GetElementPos(hoveredElement); return pos.x >= 0; } } public sealed class LinkMarker : MonoBehaviour { private static readonly Color LinkColour = new Color(0.44f, 0.76f, 1f, 0.9f); private static Material lineMaterial; private LineRenderer line; private TextMeshPro label; private Transform target; private float endTime; public static void Create(Player player, Container container, string text, float seconds) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown GameObject val = new GameObject("OpenKeep_link"); LinkMarker linkMarker = val.AddComponent<LinkMarker>(); linkMarker.target = ((Component)container).transform; linkMarker.endTime = Time.time + Mathf.Max(0.5f, seconds); linkMarker.line = BuildLine(val); linkMarker.label = BuildLabel(val, text); linkMarker.Refresh(); } private void Update() { if (Time.time >= endTime || (Object)(object)target == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { Refresh(); } } private void Refresh() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)Player.m_localPlayer).transform.position + Vector3.up; Vector3 val2 = target.position + Vector3.up * 0.5f; line.SetPosition(0, val); line.SetPosition(1, val2); label.transform.position = target.position + Vector3.up * 1.6f; Camera main = Camera.main; if ((Object)(object)main != (Object)null) { label.transform.rotation = Quaternion.LookRotation(label.transform.position - ((Component)main).transform.position); } } private static LineRenderer BuildLine(GameObject go) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) LineRenderer obj = go.AddComponent<LineRenderer>(); obj.useWorldSpace = true; obj.positionCount = 2; obj.startWidth = 0.06f; obj.endWidth = 0.06f; ((Renderer)obj).material = LineMaterial(); obj.startColor = LinkColour; obj.endColor = LinkColour; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj).receiveShadows = false; return obj; } private static TextMeshPro BuildLabel(GameObject parent, string text) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("label"); val.transform.SetParent(parent.transform, false); TextMeshPro val2 = val.AddComponent<TextMeshPro>(); TMP_FontAsset val3 = LabelFont(); if ((Object)(object)val3 != (Object)null) { ((TMP_Text)val2).font = val3; } ((TMP_Text)val2).text = text; ((TMP_Text)val2).fontSize = 3.5f; ((Graphic)val2).color = LinkColour; ((TMP_Text)val2).alignment = (TextAlignmentOptions)514; ((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)val2).rectTransform.sizeDelta = new Vector2(8f, 1.5f); return val2; } private static TMP_FontAsset LabelFont() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_containerName != (Object)null && (Object)(object)instance.m_containerName.font != (Object)null) { return instance.m_containerName.font; } return TMP_Settings.defaultFontAsset; } private static Material LineMaterial() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_005c: Expected O, but got Unknown if ((Object)(object)lineMaterial != (Object)null) { return lineMaterial; } lineMaterial = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Particles/Standard Unlit") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Standard")) { color = LinkColour }; return lineMaterial; } } public static class MainGrid { private const int GameDefaultRows = 4; public static int FirstRow(Player player, Inventory inventory) { if (!((Object)(object)player != (Object)null) || inventory != ((Humanoid)player).GetInventory()) { return 0; } return 1; } public static int Rows(Player player, Inventory inventory) { int height = inventory.GetHeight(); if ((Object)(object)player == (Object)null || inventory != ((Humanoid)player).GetInventory()) { return height; } int value = StowSettings.MainInventoryRows.Value; return Math.Min(height, (value > 0) ? value : GameRows(player)); } private static int GameRows(Player player) { if (PackPanelGrid.TryRead(player, out var _, out var mainRows, out var _)) { return mainRows; } string s = default(string); if (player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result)) { return result; } return 4; } } public static class Movable { public static string Blocker(Player player, Inventory inventory, ItemData item) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (item == null || item.m_shared == null) { return ""; } if (item.m_equipped || ((Object)(object)player != (Object)null && ((Humanoid)player).IsItemEquiped(item))) { return "$ok_stow_equipped_kept"; } if (item.m_shared.m_questItem || StackMover.IsPending(item)) { return ""; } if ((Object)(object)player != (Object)null && inventory == ((Humanoid)player).GetInventory() && Favourites.IsFavouriteSlot(item.m_gridPos)) { return "$ok_stow_favourite_kept"; } if (Favourites.IsFavouriteItem(item)) { return "$ok_stow_favourite_kept"; } return null; } public static bool CanMove(Player player, Inventory inventory, ItemData item) { return Blocker(player, inventory, item) == null; } } [HarmonyPatch(typeof(InventoryGui), "Awake")] public static class PanelButtons { private const float Width = 78f; private const float Height = 26f; private const float Gap = 4f; private const float BelowEdge = -30f; private const string PackPanelStrip = "PackPanel_buttonstrip"; private const float InsideStrip = 2f; private const string Prefix = "OpenKeep_"; private static readonly List<RectTransform> Placed = new List<RectTransform>(); private static bool rowInside; private static float Offset => (StowSettings.ButtonRowOffset != null) ? StowSettings.ButtonRowOffset.Value : 0; private static float BottomOf(RectTransform rect) { return ((rowInside && (Object)(object)InventoryGui.instance != (Object)null && (Object)(object)((Transform)rect).parent == (Object)(object)InventoryGui.instance.m_player) ? 2f : (-30f)) + Offset; } public static void Follow(InventoryGui gui) { bool flag = StripShown(gui); if (flag != rowInside) { rowInside = flag; Reposition(); } } private static bool StripShown(InventoryGui gui) { if (!PackPanelLink.Present || (Object)(object)gui == (Object)null || (Object)(object)gui.m_player == (Object)null) { return false; } Transform val = ((Transform)gui.m_player).Find("PackPanel_buttonstrip"); if ((Object)(object)val != (Object)null) { return ((Component)val).gameObject.activeSelf; } return false; } [HarmonyPostfix] public static void Postfix(InventoryGui __instance) { Guard.Run("stow panel buttons", delegate { Create(__instance); }); } public static void Reposition() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Placed.RemoveAll((RectTransform rect) => (Object)(object)rect == (Object)null); foreach (RectTransform item in Placed) { item.anchoredPosition = new Vector2(item.anchoredPosition.x, BottomOf(item)); } } public static void Create(InventoryGui gui) { if (!((Object)(object)gui == (Object)null) && !((Object)(object)gui.m_takeAllButton == (Object)null) && !((Object)(object)gui.m_player == (Object)null) && !((Object)(object)gui.m_container == (Object)null)) { bool flag = !PackPanelLink.LaysOutInventory && TrashPlate.TryCreate(gui, delegate { TrashMode.CanClicked(gui); }); float num = -123f - (flag ? 0f : 15f); Add(gui, gui.m_player, "$ok_stow_quickstack", num, StowActions.QuickStack); num += 82f; Add(gui, gui.m_player, "$ok_stow_storeall", num, StowActions.StoreAll); num += 82f; Add(gui, gui.m_player, "$ok_stow_topup", num, TopUp.Run); num += 82f; Add(gui, gui.m_player, "$ok_stow_sort", num, delegate { Sorting.SortPlayer(Player.m_localPlayer, quiet: false); }); if (!flag) { AddTrash(gui, gui.m_player, num + 39f + 4f + 13f); } Add(gui, gui.m_container, "$ok_stow_sort", 0f, Sorting.SortOpenContainer); } } private static void Add(InventoryGui gui, RectTransform panel, string word, float centreX, Action action) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(((Component)gui.m_takeAllButton).gameObject, (Transform)(object)panel); ((Object)val).name = "OpenKeep_" + word.TrimStart(new char[1] { '$' }); val.SetActive(true); Place((RectTransform)val.transform, centreX, new Vector2(78f, 26f)); Button component = val.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener((UnityAction)delegate { Guard.Run(word, action); }); } SetLabel(val, word); } private static void Place(RectTransform rect, float centreX, Vector2 size) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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) rect.anchorMin = new Vector2(0.5f, 0f); rect.anchorMax = new Vector2(0.5f, 0f); rect.pivot = new Vector2(0.5f, 0f); rect.anchoredPosition = new Vector2(centreX, BottomOf(rect)); rect.sizeDelta = size; ((Transform)rect).localScale = Vector3.one; Placed.Add(rect); } private static void SetLabel(GameObject go, string word) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) TMP_Text componentInChildren = go.GetComponentInChildren<TMP_Text>(true); if (!((Object)(object)componentInChildren == (Object)null)) { componentInChildren.text = Language.Localize(word); componentInChildren.enableAutoSizing = true; componentInChildren.fontSizeMax = Mathf.Max(12f, Mathf.Min(componentInChildren.fontSize, 16f)); componentInChildren.fontSizeMin = 9f; componentInChildren.overflowMode = (TextOverflowModes)1; componentInChildren.margin = new Vector4(6f, 1f, 6f, 1f); componentInChildren.textWrappingMode = (TextWrappingModes)0; } } private static void AddTrash(InventoryGui gui, RectTransform panel, float centreX) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(((Component)gui.m_takeAllButton).gameObject, (Transform)(object)panel); ((Object)val).name = "OpenKeep_trashcan"; val.SetActive(true); Place((RectTransform)val.transform, centreX, new Vector2(26f, 26f)); TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.SetActive(false); } BinIcon(val.transform); Button component = val.GetComponent<Button>(); component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener((UnityAction)delegate { Guard.Run("trash can", delegate { TrashMode.CanClicked(gui); }); }); } private static Image BinIcon(Transform button) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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) GameObject val = new GameObject("icon", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(button, false); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = new Vector2(4f, 4f); val2.offsetMax = new Vector2(-4f, -4f); Image component = val.GetComponent<Image>(); component.sprite = StowSprites.Bin; component.preserveAspect = true; ((Graphic)component).raycastTarget = false; return component; } } public static class Routing { public static void Route(ItemData item) { if (StowActions.Ready(out var player) && !Refused(player, item)) { string text = ItemNames.DisplayName(item); Container val = FindTarget(player, item); if ((Object)(object)val == (Object)null) { Messages.Center(StowWords.Format("$ok_stow_noroute", text)); } else { Send(val, item, item.m_stack, StowWords.Format("$ok_stow_routed", text, StowTargets.Name(val))); } } } public static void StoreOne(ItemData item) { if (!StowActions.Ready(out var player) || Refused(player, item)) { return; } string text = ItemNames.DisplayName(item); Container openTarget = StowTargets.OpenTarget; if (!((Object)(object)openTarget == (Object)null) || !StowTargets.ViewingOnly()) { openTarget = openTarget ?? Holder(player, item); if ((Object)(object)openTarget == (Object)null || StowRules.Refuses(openTarget, item)) { Messages.Center(StowWords.Format("$ok_stow_noroute", text)); } else { Send(openTarget, item, 1, StowWords.Format("$ok_stow_storedone", text)); } } } private static void Send(Container target, ItemData item, int amount, string success) { bool shared = StowTargets.IsShared(target); StackMover.Reserve(item); ChestWriter.Put(target, item, amount, null, delegate(bool ok) { StackMover.Release(item); if (ok) { Messages.Center(success); } else if (!shared) { Messages.Center("$ok_stow_nothing"); } }); } private static bool Refused(Player player, ItemData item) { string text = Movable.Blocker(player, ((Humanoid)player).GetInventory(), item); if (text == null) { return false; } if (text.Length > 0) { Messages.Center(StowWords.Format(text, ItemNames.DisplayName(item))); } return true; } private static Container Holder(Player player, ItemData item) { foreach (Container item2 in StowTargets.Nearby(player)) { if (item2.GetInventory().ContainsItemByName(item.m_shared.m_name)) { return item2; } } return null; } private static Container FindTarget(Player player, ItemData item) { List<Container> list = StowTargets.Nearby(player); list.RemoveAll((Container container) => StowRules.Refuses(container, item)); Container val = list.Find((Container container) => container.GetInventory().ContainsItemByName(item.m_shared.m_name)); if ((Object)(object)val != (Object)null) { return val; } List<string> groups = StowRules.GroupsOf(item); return ((groups.Count > 0) ? list.Find((Container container) => HoldsGroup(container, groups)) : null) ?? list.Find((Container container) => StowRules.Accepts(container, item)); } private static bool HoldsGroup(Container container, List<string> groups) { foreach (ItemData allItem in container.GetInventory().GetAllItems()) { foreach (string group in groups) { if (StowRules.Groups.Matches(group, allItem)) { return true; } } } return false; } } public sealed class SlotMarks : MonoBehaviour { private const float MarkSize = 14f; private static readonly Color StarColour = new Color(1f, 0.85f, 0.25f, 0.95f); private static readonly Color CrossColour = new Color(1f, 0.35f, 0.3f, 0.95f); private static readonly Color BorderColour = new Color(0.45f, 0.75f, 1f, 0.9f); private Image star; private Image cross; private Image border; public static SlotMarks Attach(InventoryElement element) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) SlotMarks slotMarks = ((Component)element).gameObject.AddComponent<SlotMarks>(); slotMarks.border = slotMarks.Add("OpenKeep_border", StowSprites.Border, BorderColour, Vector2.zero, Vector2.one, Vector2.zero); slotMarks.border.type = (Type)1; slotMarks.star = slotMarks.Add("OpenKeep_star", StowSprites.Star, StarColour, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(14f, 14f)); slotMarks.cross = slotMarks.Add("OpenKeep_cross", StowSprites.Cross, CrossColour, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(14f, 14f)); slotMarks.Set(favouriteItem: false, favouriteSlot: false, junk: false); return slotMarks; } public void Set(bool favouriteItem, bool favouriteSlot, bool junk) { ((Behaviour)star).enabled = favouriteItem; ((Behaviour)border).enabled = favouriteSlot; ((Behaviour)cross).enabled = junk; } private Image Add(string name, Sprite sprite, Color colour, Vector2 anchorMin, Vector2 anchorMax, Vector2 size) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(((Component)this).transform, false); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = anchorMin; val2.anchorMax = anchorMax; val2.pivot = anchorMin; val2.anchoredPosition = new Vector2((anchorMin.x > 0.5f) ? (-2f) : 2f, -2f) * ((size == Vector2.zero) ? 0f : 1f); val2.sizeDelta = size; Image component = val.GetComponent<Image>(); component.sprite = sprite; ((Graphic)component).color = colour; ((Graphic)component).raycastTarget = false; return component; } } public static class Sorting { public static void SortPlayer(Player player, bool quiet) { if (!((Object)(object)player == (Object)null) && StowSettings.Enabled.Value) { Inventory inventory = ((Humanoid)player).GetInventory(); int num = Sort(inventory, (ItemData item) => Pinned(player, item), MainGrid.FirstRow(player, inventory), MainGrid.Rows(player, inventory), PackPanelGrid.BlockedCells(player, inventory)); if (!quiet) { Messages.Center(StowWords.Format("$ok_stow_sorted", num)); } } } public static void SortOpenContainer() { if (StowActions.Ready(out var _)) { SortContainer(StowTargets.Open, quiet: false); } } public static void SortContainer(Container container, bool quiet) { if ((Object)(object)container == (Object)null || !ContainerScan.IsUsable(container, ContainerUse.Stow)) { if (!quiet) { Messages.Center(WhyNot(container)); } } else if (ContainerScan.Claim(container)) { Inventory inventory = container.GetInventory(); int num = Sort(inventory, (ItemData item) => false, 0, inventory.GetHeight()); ContainerScan.Save(container); if (!quiet) { Messages.Center(StowWords.Format("$ok_stow_sorted", num)); } } } private static string WhyNot(Container container) { if ((Object)(object)container == (Object)null) { return "$ok_stow_nocontainer"; } if (StowTargets.IsShared(container)) { return "$ok_shared_unavailable"; } if (!SharedState.IsViewing(container)) { return "$ok_stow_nocontainer"; } return "$ok_shared_readonly"; } private static bool Pinned(Player player, ItemData item) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (item.m_equipped || ((Humanoid)player).IsItemEquiped(item) || Favourites.IsFavouriteSlot(item.m_gridPos) || StackMover.IsPending(item)) { return true; } if (!StowSettings.SortFavouriteItems.Value) { return Favourites.IsFavouriteItem(item); } return false; } public static int Sort(Inventory inventory, Func<ItemData, bool> pinned, int firstRow, int rows, IEnumerable<Vector2i> reserved = null) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) List<ItemData> allItems = inventory.GetAllItems(); List<ItemData> list = new List<ItemData>(); int width = inventory.GetWidth(); HashSet<int> hashSet = new HashSet<int>(); foreach (Vector2i item in (IEnumerable<Vector2i>)(((object)reserved) ?? ((object)new Vector2i[0]))) { hashSet.Add(item.y * width + item.x); } foreach (ItemData item2 in allItems) { if (pinned(item2) || item2.m_gridPos.y < firstRow || item2.m_gridPos.y >= rows) { hashSet.Add(item2.m_gridPos.y * width + item2.m_gridPos.x); } else { list.Add(item2); } } Merge(list, allItems); list.Sort(Compare); Place(inventory, list, hashSet, firstRow * width, rows * width); inventory.Changed(false, false); return list.Count; } private static void Merge(List<ItemData> loose, List<ItemData> all) { for (int i = 0; i < loose.Count; i++) { ItemData val = loose[i]; if (val.m_shared.m_maxStackSize <= 1) { continue; } for (int num = loose.Count - 1; num > i; num--) { int num2 = val.m_shared.m_maxStackSize - val.m_stack; if (num2 <= 0) { break; } ItemData val2 = loose[num]; if (Same(val, val2)) { int num3 = Math.Min(num2, val2.m_stack); val.m_stack += num3; val2.m_stack -= num3; if (val2.m_stack == 0 && all.Remove(val2)) { loose.RemoveAt(num); } } } } } private static void Place(Inventory inventory, List<ItemData> loose, HashSet<int> taken, int firstCell, int cells) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) int width = inventory.GetWidth(); int i = firstCell; foreach (ItemData item in loose) { for (; i < cells && taken.Contains(i); i++) { } if (i >= cells) { break; } item.m_gridPos = new Vector2i(i % width, i / width); i++; } } private static bool Same(ItemData a, ItemData b) { if (ItemNames.SameItem(a, b) && a.m_quality == b.m_quality) { return a.m_worldLevel == b.m_worldLevel; } return false; } private static int Compare(ItemData a, ItemData b) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected I4, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected I4, but got Unknown int num = 0; switch (StowSettings.SortOrder.Value) { case SortOrder.Category: num = ((int)a.m_shared.m_itemType).CompareTo((int)b.m_shared.m_itemType); break; case SortOrder.Weight: num = b.m_shared.m_weight.CompareTo(a.m_shared.m_weight); break; case SortOrder.Value: num = b.m_shared.m_value.CompareTo(a.m_shared.m_value); break; } if (num == 0) { num = string.Compare(ItemNames.DisplayName(a), ItemNames.DisplayName(b), StringComparison.OrdinalIgnoreCase); } if (num == 0) { num = b.m_quality.CompareTo(a.m_quality); } if (num == 0) { num = b.m_stack.CompareTo(a.m_stack); } return num; } } public enum SortOrder { Category, Name, Weight, Value } public static class StackMover { private static readonly HashSet<ItemData> pending = new HashSet<ItemData>(); public static bool IsPending(ItemData item) { if (item != null) { return pending.Contains(item); } return false; } internal static void Reserve(ItemData item) { if (item != null) { pending.Add(item); } } internal static void Release(ItemData item) { if (item != null) { pending.Remove(item); } } public static void Report(int stacks) { Messages.Center((stacks > 0) ? StowWords.Format("$ok_stow_moved", stacks) : "$ok_stow_nothing"); } public static void ReportAction(int stacks, bool waiting) { if (stacks > 0 || !waiting) { Report(stacks); } } } public static class StowActions { public static bool Ready(out Player player) { player = Player.m_localPlayer; if (!StowSettings.Enabled.Value) { Messages.Center("$ok_stow_off"); return false; } if ((Object)(object)player != (Object)null) { return !((Character)player).IsTeleporting(); } return false; } public static void QuickStack() { if (!Ready(out var player)) { return; } bool value = StowSettings.QuickStackNearby.Value; List<Container> list = (value ? StowTargets.Nearby(player) : StowTargets.OpenOnly()); if (list.Count == 0) { if (value) { Messages.Center("$ok_stow_nothing"); } else { StowTargets.SayNoOpen(); } } else { StackInto(player, list, onlyHeld: true); } } public static void Dump() { if (Ready(out var player)) { if (!StowSettings.QuickStackNearby.Value) { Messages.Center("$ok_stow_nearby_off"); } else { StackInto(player, StowTargets.Nearby(player), onlyHeld: true); } } } public static void StoreAll() { if (Ready(out var player)) { List<Container> list = StowTargets.OpenOnly(); if (list.Count == 0) { StowTargets.SayNoOpen(); } else { StackInto(player, list, onlyHeld: false); } } } private static void StackInto(Player player, List<Container> targets, bool onlyHeld) { int num = 0; bool waiting = false; foreach (Container target in targets) { ChestBatch chestBatch = new ChestBatch(target, "$ok_stow_moved_to"); foreach (ItemData item in Candidates(player, target, onlyHeld)) { chestBatch.Put(item, item.m_stack, 1); } chestBatch.Finish(); if (chestBatch.Waiting) { waiting = true; } else { num += chestBatch.Moved; } } StackMover.ReportAction(num, waiting); } private static List<ItemData> Candidates(Player player, Container container, bool onlyHeld) { Inventory inventory = ((Humanoid)player).GetInventory(); Inventory inventory2 = container.GetInventory(); int num = MainGrid.FirstRow(player, inventory); int num2 = MainGrid.Rows(player, inventory); List<ItemData> list = new List<ItemData>(); foreach (ItemData item in new List<ItemData>(inventory.GetAllItems())) { if (item.m_gridPos.y >= num && item.m_gridPos.y < num2 && Movable.CanMove(player, inventory, item) && !StowRules.Refuses(container, item) && (!onlyHeld || inventory2.ContainsItemByName(item.m_shared.m_name))) { list.Add(item); } } return list; } } [HarmonyPatch(typeof(InventoryGui), "Update")] public static class StowHotkeys { [HarmonyPostfix] public static void Postfix(InventoryGui __instance) { PanelButtons.Follow(__instance); Poll(__instance); } public static void Poll(InventoryGui gui) { TrashMode.Tick(gui); if (StowSettings.Enabled.Value && Keys.InventoryOpen && !((Object)(object)Player.m_localPlayer == (Object)null) && !UnifiedPopup.IsVisible() && (!((Object)(object)gui.m_splitDialog != (Object)null) || !gui.m_splitDialog.IsActive)) { PollActions(gui); PollHovered(gui); Cycling.Poll(gui); } } private static void PollActions(InventoryGui gui) { if (Keys.Pressed(StowSettings.QuickStackKey)) { StowActions.QuickStack(); } else if (Keys.Pressed(StowSettings.StoreAllKey)) { StowActions.StoreAll(); } else if (Keys.Pressed(StowSettings.TopUpKey)) { TopUp.Run(); } else if (Keys.Pressed(StowSettings.SortInventoryKey)) { Sorting.SortPlayer(Player.m_localPlayer, quiet: false); } else if (Keys.Pressed(StowSettings.SortContainerKey)) { Sorting.SortOpenContainer(); } else if (Keys.Pressed(StowSettings.DestroyJunkKey)) { Trash.DestroyJunk(gui); } else if (Keys.Pressed(StowSettings.TrashKey)) { Trash.TrashHovered(gui); } } private static void PollHovered(InventoryGui gui) { //IL_001b: 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) if (!HoveredItem.Find(gui, out var grid, out var pos)) { return; } bool flag = (Object)(object)grid == (Object)(object)gui.m_playerGrid; ItemData val = HoveredItem.Item(grid, pos); if (Keys.Pressed(StowSettings.FavouriteSlotKey)) { if (flag) { Favourites.ToggleSlotWithMessage(pos); } } else if (val != null) { if (Keys.Pressed(StowSettings.FavouriteItemKey)) { Favourites.ToggleItemWithMessage(val); } else if (Keys.Pressed(StowSettings.JunkKey)) { Favourites.ToggleJunkWithMessage(val); } else if (Keys.Pressed(StowSettings.FindKey)) { Finder.Find(val); } else if (flag && Keys.Pressed(StowSettings.StoreOneKey)) { Routing.StoreOne(val); } } } } public sealed class StowModel : YamlModel { public ItemGroups ItemGroups { get; } = new ItemGroups(); public Dictionary<string, StowRule> Containers { get; } = new Dictionary<string, StowRule>(StringComparer.OrdinalIgnoreCase); protected override void Read(YamlNode root) { ItemGroups.Read(root.Get("groups")); YamlNode yamlNode = root.Get("containers"); if (yamlNode.Kind == YamlNodeKind.Missing) { return; } foreach (KeyValuePair<string, YamlNode> entry in yamlNode.Entries) { Containers[entry.Key.Trim()] = StowRule.Read(entry.Value, ItemGroups); } } } public static class StowModule { public const string Resource = "OpenKeep.config.OpenKeep.Stow.yml"; public static YamlFileSet Files { get; private set; } public static void Initialize(SyncedConfiguration synced) { StowSettings.Bind(synced); Files = synced.AddYaml(new YamlFileSet("OpenKeep.Stow*.yml", "openkeep_stow", () => new StowModel(), Apply) { DefaultContent = SyncedConfiguration.EmbeddedResource(typeof(StowModule).Assembly, "OpenKeep.config.OpenKeep.Stow.yml"), EditorLabel = () => Language.Localize("$ok_stow_edit") }); StowWords.Register(); StowSettings.ButtonRowOffset.SettingChanged += Guard.Wrap("stow button row offset", (EventHandler)delegate { PanelButtons.Reposition(); }); } private static void Apply(YamlModel model) { StowModel stowModel = (StowModel)model; StowRules.Apply(stowModel); Plugin.Log.LogInfo((object)$"Stow rules applied: {stowModel.Containers.Count} container rules."); } } public sealed class StowRule { public static StowRule Default { get; } = new StowRule(pickup: false, ItemMatchSet.Empty, ItemMatchSet.Empty); public bool Pickup { get; } public ItemMatchSet Accept { get; } public ItemMatchSet Refuse { get; } private StowRule(bool pickup, ItemMatchSet accept, ItemMatchSet refuse) { Pickup = pickup; Accept = accept; Refuse = refuse; } public static StowRule Read(YamlNode node, ItemGroups groups) { if (node.Kind != YamlNodeKind.Map) { node.Error("a container entry needs a map with pickup, accept or refuse"); return Default; } bool result = false; node.Get("pickup").TryBool(out result); return new StowRule(result, ReadList(node.Get("accept"), groups), ReadList(node.Get("refuse"), groups)); } private static ItemMatchSet ReadList(YamlNode node, ItemGroups groups) { if (node.Kind == YamlNodeKind.Missing || !node.TryStringList(out List<string> items)) { return ItemMatchSet.Empty; } ItemMatchSet itemMatchSet = ItemMatchSet.Parse(items, groups); foreach (ItemMatcher matcher in itemMatchSet.Matchers) { if (matcher.Problem != null) { node.Warn("'" + matcher?.ToString() + "' is ignored: " + matcher.Problem); } } return itemMatchSet; } } public static class StowRules { private static StowModel current = new StowModel(); public static ItemGroups Groups => current.ItemGroups; public static void Apply(StowModel model) { current = model ?? new StowModel(); } public static StowRule For(Container container) { string key = ContainerScan.PrefabName(container); if (!current.Containers.TryGetValue(key, out var value)) { return StowRule.Default; } return value; } public static bool Refuses(Container container, ItemData item) { StowRule stowRule = For(container); if (!stowRule.Refuse.IsEmpty) { return stowRule.Refuse.Matches(item); } return false; } public static bool Accepts(Container container, ItemData item) { StowRule stowRule = For(container); if (!stowRule.Accept.IsEmpty && stowRule.Accept.Matches(item)) { return !Refuses(container, item); } return false; } public static bool PicksUp(Container container) { return For(container).Pickup; } public static List<string> GroupsOf(ItemData item) { List<string> list = new List<string>(); foreach (string name in current.ItemGroups.Names) { if (current.ItemGroups.Matches(name, item)) { list.Add(name); } } return list; } } public static class StowSettings { public const string Section = "2. Stow"; public static ConfigEntry<bool> Enabled { get; private set; } public static ConfigEntry<KeyboardShortcut> QuickStackKey { get; private set; } public static ConfigEntry<bool> QuickStackNearby { get; private set; } public static ConfigEntry<KeyboardShortcut> StoreAllKey { get; private set; } public static ConfigEntry<KeyboardShortcut> TopUpKey { get; private set; } public static ConfigEntry<KeyboardShortcut> SortInventoryKey { get; private set; } public static ConfigEntry<KeyboardShortcut> SortContainerKey { get; private set; } public static ConfigEntry<SortOrder> SortOrder { get; private set; } public static ConfigEntry<bool> SortFavouriteItems { get; private set; } public static ConfigEntry<int> MainInventoryRows { get; private set; } public static ConfigEntry<bool> AutoSortContainers { get; private set; } public static ConfigEntry<bool> AutoSortInventory { get; private set; } public static ConfigEntry<KeyboardShortcut> FavouriteItemKey { get; private set; } public static ConfigEntry<KeyboardShortcut> FavouriteSlotKey { get; private set; } public static ConfigEntry<KeyboardShortcut> JunkKey { get; private set; } public static ConfigEntry<KeyboardShortcut> TrashKey { get; private set; } public static ConfigEntry<KeyboardShortcut> DestroyJunkKey { get; private set; } public static ConfigEntry<bool> ConfirmTrash { get; private set; } public static ConfigEntry<bool> TrashUsesSalvage { get; private set; } public static ConfigEntry<KeyboardShortcut> RouteModifier { get; private set; } public static ConfigEntry<KeyboardShortcut> StoreOneKey { get; private set; } public static ConfigEntry<KeyboardShortcut> FindKey { get; private set; } public static ConfigEntry<KeyboardShortcut> DumpKey { get; private set; } public static ConfigEntry<KeyboardShortcut> CyclePreviousKey { get; private set; } public static ConfigEntry<KeyboardShortcut> CycleNextKey { get; private set; } public static ConfigEntry<bool> CycleWithWheel { get; private set; } public static ConfigEntry<float> NearbyRange { get; private set; } public static ConfigEntry<bool> ShowFavourites { get; private set; } public static ConfigEntry<bool> GroundPickup { get; private set; } public static ConfigEntry<float> PickupRange { get; private set; } public static ConfigEntry<float> PickupInterval { get; private set; } public static ConfigEntry<float> PickupDelay { get; private set; } public static ConfigEntry<bool> PickupOnlyHeldItems { get; private set; } public static ConfigEntry<int> ButtonRowOffset { get; private set; } public static void Bind(SyncedConfiguration synced) { BindMoves(synced); BindSorting(synced); BindFavourites(synced); BindTrash(synced); BindClicks(synced); BindCycling(synced); BindPickup(synced); } private static void BindMoves(SyncedConfiguration synced) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) Enabled = synced.Bind("2. Stow", "Enabled", true, "Master switch of the Stow module: panel buttons, hotkeys, sorting, trashing, routing, chest cycling and ground pickup.", true, null); QuickStackKey = synced.Bind<KeyboardShortcut>("2. Stow", "Quick Stack Key", new KeyboardShortcut((KeyCode)113, Array.Empty<KeyCode>()), "Inventory open: every non-favourite stack whose item already exists in the open container (or, with no container open, in any nearby container) moves there.", synced: false, null, Array.Empty<object>()); QuickStackNearby = synced.Bind("2. Stow", "Quick Stack Nearby", true, "Quick stack also reaches every nearby container, not only the open one. Off also disables the Dump key.", true, null); StoreAllKey = synced.Bind<KeyboardShortcut>("2. Stow", "Store All Key", RenamedKeys.Carry<KeyboardShortcut>(synced.Config, "2. Stow", "Stow All Key", "Store All Key", new KeyboardShortcut((KeyCode)103, Array.Empty<KeyCode>())), "Inventory open with a container: every non-favourite item moves into the open container as far as it fits.", synced: false, null, Array.Empty<object>()); TopUpKey = synced.Bind<KeyboardShortcut>("2. Stow", "Top Up Key", RenamedKeys.Carry<KeyboardShortcut>(synced.Config, "2. Stow", "Restock Key", "Top Up Key", new KeyboardShortcut((KeyCode)114, Array.Empty<KeyCode>())), "Inventory open: every stack in the inventory that is not full is topped up from the open container or nearby containers. Favourite items included.", synced: false, null, Array.Empty<object>()); NearbyRange = synced.Bind("2. Stow", "Nearby Range", 20f, "Metres from the player for quick stack, top up, dump, route, find and cycle.", true, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(1f, 100f)); ButtonRowOffset = synced.Bind("2. Stow", "Button Row Offset", 0, "Moves the Stow button row up (positive) or down (negative) by this many pixels from its default place under the container panel.", false, null); } private static void BindSorting(SyncedConfiguration synced) { //IL_0012: 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) SortInventoryKey = synced.Bind<KeyboardShortcut>("2. Stow", "Sort Inventory Key", new KeyboardShortcut((KeyCode)116, Array.Empty<KeyCode>()), "Inventory open: sorts the player inventory by Sort Order. The hotbar, favourite slots, equipped items and the rows other mods add below the game's (Main Inventory Rows) stay where they are.", synced: false, null, Array.Empty<object>()); SortContainerKey = synced.Bind<KeyboardShortcut>("2. Stow", "Sort Container Key", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), "Inventory open with a container: sorts the open container by Sort Order.", synced: false, null, Array.Empty<object>()); SortOrder = synced.Bind("2. Stow", "Sort Order", OpenKeep.Stow.SortOrder.Category, "Category (item type, then name), Name, Weight (heaviest first) or Value (most valuable first). Stacks of the same item merge while sorting.", false, null); SortFavouriteItems = synced.Bind("2. Stow", "Sort Favourite Items", true, "Off: the sort leaves favourite items where they are. Turn off when another mod keeps items in extra slots the sort would pull out - favourite those items and they stay put.", false, null); MainInventoryRows = synced.Bind("2. Stow", "Main Inventory Rows", 0, "Rows of the player inventory, hotbar included, that quick stack, store all, dump and sort work on; the hotbar itself is always left alone. 0: the rows the game gives you (4, more once bought from the trader). Mods that add equipment, food or ammo slots keep them in rows below, which these actions leave alone; top up still fills the stacks there. Set a number when a mod adds ordinary inventory rows; 20 covers every row.", false, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(0, 20)); AutoSortContainers = synced.Bind("2. Stow", "Auto Sort Containers", false, "A container is sorted when it is opened.", false, null); AutoSortInventory = synced.Bind("2. Stow", "Auto Sort Inventory", false, "The player inventory is sorted when the panel opens.", false, null); } private static void BindFavourites(SyncedConfiguration synced) { //IL_0012: 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) FavouriteItemKey = synced.Bind<KeyboardShortcut>("2. Stow", "Favourite Item Key", new KeyboardShortcut((KeyCode)102, Array.Empty<KeyCode>()), "Hovering an item: the item name becomes a favourite (never quick stacked, stored, dumped, trashed or salvaged). Press again to remove.", synced: false, null, Array.Empty<object>()); FavouriteSlotKey = synced.Bind<KeyboardShortcut>("2. Stow", "Favourite Slot Key", new KeyboardShortcut((KeyCode)102, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Hovering a slot of the player inventory: the slot becomes a favourite (its content never moves, never sorted). Press again to remove.", synced: false, null, Array.Empty<object>()); ShowFavourites = synced.Bind("2. Stow", "Show Favourites", true, "Favourite items get a small star in the corner of the slot, favourite slots a coloured border, junk a small cross.", false, null); } private static void BindTrash(SyncedConfiguration synced) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) JunkKey = synced.Bind<KeyboardShortcut>("2. Stow", "Junk Key", RenamedKeys.Carry<KeyboardShortcut>(synced.Config, "2. Stow", "Trash Flag Key", "Junk Key", new KeyboardShortcut((KeyCode)106, Array.Empty<KeyCode>())), "Hovering an item: the item name is marked as junk; Destroy Junk destroys every junk stack. Press again to unmark it.", synced: false, null, Array.Empty<object>()); TrashKey = synced.Bind<KeyboardShortcut>("2. Stow", "Trash Key", new KeyboardShortcut((KeyCode)127, Array.Empty<KeyCode>()), "Hovering an item: the stack is trashed after confirmation.", synced: false, null, Array.Empty<object>()); DestroyJunkKey = synced.Bind<KeyboardShortcut>("2. Stow", "Destroy Junk Key", RenamedKeys.Carry<KeyboardShortcut>(synced.Config, "2. Stow", "Trash Flagged Key", "Destroy Junk Key", new KeyboardShortcut((KeyCode)127, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 })), "Destroys every junk stack in the inventory (after the popup when Confirm Trash is on).", synced: false, null, Array.Empty<object>()); ConfirmTrash = synced.Bind("2. Stow", "Confirm Trash", false, "The game's popup asks before anything is destroyed; gamepad confirm and cancel work. Off by default: trashing is immediate.", false, null); TrashUsesSalvage = synced.Bind("2. Stow", "Trash Uses Salvage", false, "Trashing a whole stack from the inventory salvages it instead (section 3) when the item can be salvaged.", false, null); } private static void BindClicks(SyncedConfiguration synced) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) RouteModifier = synced.Bind<KeyboardShortcut>("2. Stow", "Route Modifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "Held with a left click on an inventory item: the stack is sent to the nearest nearby container that already holds the item, an item of its group, or accepts it in OpenKeep.Stow.yml.", synced: false, null, Array.Empty<object>()); StoreOneKey = synced.Bind<KeyboardShortcut>("2. Stow", "Store One Key", new KeyboardShortcut((KeyCode)118, Array.Empty<KeyCode>()), "On a hovered inventory item: one item of the stack goes to the open container, or to the nearest container holding it.", synced: false, null, Array.Empty<object>()); FindKey = synced.Bind<KeyboardShortcut>("2. Stow", "Find Key", new KeyboardShortcut((KeyCode)122, Array.Empty<KeyCode>()), "Hovering an item: every nearby container holding it is marked for Link Seconds (the Reach setting) with a line from the player and a floating count.", synced: false, null, Array.Empty<object>()); DumpKey = synced.Bind<KeyboardShortcut>("2. Stow", "Dump Key", new KeyboardShortcut((KeyCode)100, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Outside the inventory: quick stack to every nearby container.", synced: false, null, Array.Empty<object>()); } private static void BindCycling(SyncedConfiguration synced) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) CyclePreviousKey = synced.Bind<KeyboardShortcut>("2. Stow", "Cycle Previous Key", new KeyboardShortcut((KeyCode)276, Array.Empty<KeyCode>()), "With a container open: closes it and opens the previous nearby container, ordered by angle around the player. Only containers the game would keep open (within its auto close distance) take part.", synced: false, null, Array.Empty<object>()); CycleNextKey = synced.Bind<KeyboardShortcut>("2. Stow", "Cycle Next Key", new KeyboardShortcut((KeyCode)275, Array.Empty<KeyCode>()), "With a container open: closes it and opens the next nearby container.", synced: false, null, Array.Empty<object>()); CycleWithWheel = synced.Bind("2. Stow", "Cycle With Wheel", true, "The mouse wheel over the container grid cycles too.", false, null); } private static void BindPickup(SyncedConfiguration synced) { GroundPickup = synced.Bind("2. Stow", "Ground Pickup", false, "Containers whose prefab has pickup: true in OpenKeep.Stow.yml pull dropped items from the ground by rule.", true, null); PickupRange = synced.Bind("2. Stow", "Pickup Range", 2f, "Metres around the container.", true, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(1f, 50f)); PickupInterval = synced.Bind("2. Stow", "Pickup Interval", 5f, "Seconds between sweeps of one container.", true, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(1f, 120f)); PickupDelay = synced.Bind("2. Stow", "Pickup Delay", 30f, "Seconds an item must lie on the ground before a container takes it, measured from the item's spawn time, so players can pick up their own drops.", true, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 3600f)); PickupOnlyHeldItems = synced.Bind("2. Stow", "Pickup Only Held Items", true, "A container only takes items it already holds; the YAML accept list adds more. Off: it takes everything its refuse list allows.", true, null); } } public static class StowSprites { private const int MarkSize = 16; private const string TrashResource = "OpenKeep.assets.trash.png"; private static Sprite star; private static Sprite cross; private static Sprite border; private static Sprite bin; public static Sprite Star { get { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)star != (Object)null)) { return star = Make(16, StarPixel, Vector4.zero); } return star; } } public static Sprite Cross { get { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)cross != (Object)null)) { return cross = Make(16, CrossPixel, Vector4.zero); } return cross; } } public static Sprite Border { get { //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)border != (Object)null)) { return border = Make(16, BorderPixel, new Vector4(3f, 3f, 3f, 3f)); } return border; } } public static Sprite Bin { get { if (!((Object)(object)bin != (Object)null)) { return bin = Load("OpenKeep.assets.trash.png"); } return bin; } } private static Sprite Make(int size, Func<int, int, int, bool> inside, Vector4 slices) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { val.SetPixel(j, i, inside(j, i, size) ? Color.white : Color.clear); } } val.Apply(); Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, slices); ((Object)obj).name = "OpenKeep_sprite"; return obj; } private static Sprite Load(string resource) { Sprite val = EmbeddedSprite.Load(typeof(StowSprites).Assembly, resource, "OpenKeep_sprite"); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("could not read the embedded image " + resource)); } else { Plugin.Log.LogInfo((object)$"{resource}: {((Texture)val.texture).width}x{((Texture)val.texture).height}, {((Texture)val.texture).mipmapCount} mip levels"); } return val; } private static bool StarPixel(int x, int y, int size) { float num = (float)size / 2f; float num2 = (float)x + 0.5f - num; float num3 = (float)y + 0.5f - num; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3) / num; float num5 = (Mathf.Atan2(num3, num2) / ((float)Math.PI * 2f) + 0.25f) * 5f; float num6 = 1f - Mathf.Abs(num5 - Mathf.Floor(num5) - 0.5f) * 2f; float num7 = 0.42f + 0.56000006f * (1f - num6); return num4 <= num7; } private static bool CrossPixel(int x, int y, int size) { if ((float)x < 2f || (float)y < 2f || (float)x >= (float)size - 2f || (float)y >= (float)size - 2f) { return false; } if (!((float)Mathf.Abs(x - y) <= 1.6f)) { return (float)Mathf.Abs(x + y - (size - 1)) <= 1.6f; } return true; } private static bool BorderPixel(int x, int y, int size) { if (x >= 2 && y >= 2 && x < size - 2) { return y >= size - 2; } return true; } } public static class StowTargets { public static Container Open { get { if (!((Object)(object)InventoryGui.instance != (Object)null)) { return null; } return InventoryGui.instance.m_currentContainer; } } public static Container OpenTarget { get { Container open = Open; if (!((Object)(object)open != (Object)null) || !IsTarget(open)) { return null; } return open; } } public static bool IsTarget(Container container) { try { return ContainerScan.IsUsable(container, ContainerUse.Stow) || ContainerScan.IsShared(container); } catch (Exception ex) { Plugin.Log.LogDebug((object)("OpenKeep: container skipped, " + ex.GetType().Name + ": " + ex.Message)); return false; } } public static bool IsShared(Container container) { return ChestWriter.IsShared(container); } public static List<Container> Nearby(Player player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)player).transform.position; float value = StowSettings.NearbyRange.Value; List<KeyValuePair<float, Container>> list = new List<KeyValuePair<float, Container>>(); foreach (Container item in ContainerScan.All()) { float num = Distance(position, item); if (num <= value && IsTarget(item)) { list.Add(new KeyValuePair<float, Container>(num, item)); } } list.Sort((KeyValuePair<float, Container> a, KeyValuePair<float, Container> b) => a.Key.CompareTo(b.Key)); List<Container> list2 = list.ConvertAll((KeyValuePair<float, Container> pair) => pair.Value); Container open = Open; if ((Object)(object)open != (Object)null && list2.Remove(open)) { list2.Insert(0, open); } return list2; } public static List<Container> OpenOnly() { List<Container> list = new List<Container>(); Container openTarget = OpenTarget; if ((Object)(object)openTarget != (Object)null) { list.Add(openTarget); } return list; } public static bool ViewingOnly() { Container open = Open; if ((Object)(object)open == (Object)null || !SharedState.IsViewing(open) || SharedState.FullMode) { return false; } Messages.Center("$ok_shared_readonly"); return true; } public static void SayNoOpen() { if (!ViewingOnly()) { Messages.Center("$ok_stow_nocontainer"); } } public static float Distance(Vector3 origin, Container container) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) try { return Vector3.Distance(origin, ((Component)container).transform.position); } catch (Exception) { return float.PositiveInfinity; } } public static string Name(Container container) { Inventory val = (((Object)(object)container != (Object)null) ? container.GetInventory() : null); if (val == null) { return ""; } return Language.Localize(val.GetName()); } } public static class StowWords { public const string QuickStack = "$ok_stow_quickstack"; public const string StoreAll = "$ok_stow_storeall"; public const string TopUp = "$ok_stow_topup"; public const string Sort = "$ok_stow_sort"; public const string Trash = "$ok_stow_trash"; public const string Edit = "$ok_stow_edit"; public const string Off = "$ok_stow_off"; public const string Moved = "$ok_stow_moved"; public const string MovedTo = "$ok_stow_moved_to"; public const string Nothing = "$ok_stow_nothing"; public const string NoContainer = "$ok_stow_nocontainer"; public const string NearbyOff = "$ok_stow_nearby_off"; public const string NoRoute = "$ok_stow_noroute"; public const string Routed = "$ok_stow_routed"; public const string StoredOne = "$ok_stow_storedone"; public const string ToppedUp = "$ok_stow_toppedup"; public const string ToppedUpFrom = "$ok_stow_toppedup_from"; public const string Sorted = "$ok_stow_sorted"; public const string FavouriteOn = "$ok_stow_favourite_on"; public const string FavouriteOff = "$ok_stow_favourite_off"; public const string SlotOn = "$ok_stow_slot_on"; public const string SlotOff = "$ok_stow_slot_off"; public const string JunkOn = "$ok_stow_junk_on"; public const string JunkOff = "$ok_stow_junk_off"; public const string FavouriteKept = "$ok_stow_favourite_kept"; public const string EquippedKept = "$ok_stow_equipped_kept"; public const string TrashAsk = "$ok_stow_trash_ask"; public const string DestroyJunkAsk = "$ok_stow_destroy_junk_ask"; public const string Trashed = "$ok_stow_trashed"; public const string NoJunk = "$ok_stow_nojunk"; public const string DragHint = "$ok_stow_drag_hint"; public const string Found = "$ok_stow_found"; public const string NotFound = "$ok_stow_notfound"; public const string NoCycle = "$ok_stow_nocycle"; public const string Salvaged = "$ok_stow_salvaged"; public const string TrashModeOn = "$ok_stow_trash_mode"; public static void Register() { Language.Add("ok_stow_quickstack", "Quick stack"); Language.Add("ok_stow_storeall", "Store all"); Language.Add("ok_stow_topup", "Top up"); Language.Add("ok_stow_sort", "Sort"); Language.Add("ok_stow_trash", "Trash"); Language.Add("ok_stow_edit", "Edit stow rules"); Language.Add("ok_stow_off", "OpenKeep stow is disabled"); Language.Add("ok_stow_moved", "Moved {0} stacks"); Language.Add("ok_stow_moved_to", "Moved {0} stacks to {1}"); Language.Add("ok_stow_nothing", "Nothing to move"); Language.Add("ok_stow_nocontainer", "No container is open"); Language.Add("ok_stow_nearby_off", "Quick stacking to nearby containers is disabled"); Language.Add("ok_stow_noroute", "No nearby container takes {0}"); Language.Add("ok_stow_routed", "Sent {0} to {1}"); Language.Add("ok_stow_storedone", "Stored one {0}"); Language.Add("ok_stow_toppedup", "Topped up {0} items"); Language.Add("ok_stow_toppedup_from", "Topped up {0} items from {1}"); Language.Add("ok_stow_sorted", "Sorted {0} stacks"); RegisterMarks(); RegisterTrash(); } private static void RegisterMarks() { Language.Add("ok_stow_favourite_on", "{0} is now a favourite"); Language.Add("ok_stow_favourite_off", "{0} is no longer a favourite"); Language.Add("ok_stow_slot_on", "Slot {0} is now a favourite"); Language.Add("ok_stow_slot_off", "Slot {0} is no longer a favourite"); Language.Add("ok_stow_junk_on", "{0} is marked as junk"); Language.Add("ok_stow_junk_off", "{0} is no longer marked as junk"); Language.Add("ok_stow_favourite_kept", "{0} is a favourite and stays"); Language.Add("ok_stow_equipped_kept", "{0} is equipped and stays"); Language.Add("ok_stow_found", "{0} in {1} nearby containers"); Language.Add("ok_stow_notfound", "No nearby container holds {0}"); Language.Add("ok_stow_nocycle", "No other container within reach"); } private static void RegisterTrash() { Language.Add("ok_stow_trash_ask", "Destroy {0}?"); Language.Add("ok_stow_destroy_junk_ask", "Destroy {0} junk stacks?"); Language.Add("ok_stow_trashed", "Destroyed {0}"); Language.Add("ok_stow_nojunk", "Nothing in the inventory is marked as junk"); Language.Add("ok_stow_drag_hint", "Drag a stack onto the trash can to destroy it, or Shift + click the can to click stacks away"); Language.Add("ok_stow_salvaged", "Salvaged {0}"); Language.Add("ok_stow_trash_mode", "Trash mode: click a stack to destroy it, let go of Shift to stop"); } public static string Format(string word, params object[] args) { string text = Language.Localize(word); try { return string.Format(text, args); } catch (FormatException) { return text; } } } public static class TopUp { public static void Run() { if (!StowActions.Ready(out var player)) { return; } Dictionary<string, int> room = Room(((Humanoid)player).GetInventory()); int num = 0; bool flag = false; foreach (Container item in StowTargets.Nearby(player)) { ChestBatch chestBatch = new ChestBatch(item, "$ok_stow_toppedup_from"); Fill(item, room, chestBatch); chestBatch.Finish(); if (chestBatch.Waiting) { flag = true; } else { num += chestBatch.Moved; } } if (num > 0 || !flag) { Messages.Center((num > 0) ? StowWords.Format("$ok_stow_toppedup", num) : "$ok_stow_nothing"); } } private static Dictionary<string, int> Room(Inventory inventory) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (ItemData allItem in inventory.GetAllItems()) { if (Partial(allItem)) { string key = Key(allItem); dictionary.TryGetValue(key, out var value); dictionary[key] = value + allItem.m_shared.m_maxStackSize - allItem.m_stack; } } return dictionary; } private static bool Partial(ItemData item) { if (item.m_shared.m_maxStackSize > 1 && item.m_stack < item.m_shared.m_maxStackSize) { return !item.m_shared.m_questItem; } return false; } private static string Key(ItemData item) { return item.m_shared.m_name + "|" + item.m_quality + "|" + item.m_worldLevel; } private static void Fill(Container container, Dictionary<string, int> room, ChestBatch batch) { if (!Wants(container.GetInventory(), room) || (!batch.Shared && !ContainerScan.Claim(container))) { return; } foreach (ItemData item in new List<ItemData>(container.GetInventory().GetAllItems())) { string key = Key(item); if (room.TryGetValue(key, out var value) && value > 0) { int num = Math.Min(value, item.m_stack); room[key] = value - num; batch.Take(item, num, num); } } } private static bool Wants(Inventory source, Dictionary<string, int> room) { foreach (ItemData allItem in source.GetAllItems()) { if (room.TryGetValue(Key(allItem), out var value) && value > 0) { return true; } } return false; } } public static class Trash { [CompilerGenerated] private static class <>O { public static PopupButtonCallback <0>__Pop; } public static void TrashHovered(InventoryGui gui) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!StowActions.Ready(out var player) || !HoveredItem.Find(gui, out var grid, out var pos)) { return; } ItemData item = HoveredItem.Item(grid, pos); Inventory inventory = grid.m_inventory; if (item != null && !Refused(gui, player, inventory, item)) { int amount = item.m_stack; Confirm(StowWords.Format("$ok_stow_trash_ask", Label(ItemNames.DisplayName(item), amount)), delegate { Destroy(gui, inventory, item, amount); }); } } public static void TrashDragged(InventoryGui gui) { if (!StowActions.Ready(out var player)) { return; } if ((Object)(object)gui.m_dragGo == (Object)null || gui.m_dragItem == null || gui.m_dragInventory == null) { Messages.Center("$ok_stow_drag_hint"); return; } ItemData item = gui.m_dragItem; Inventory inventory = gui.m_dragInventory; int amount = Math.Min(gui.m_dragAmount, item.m_stack); if (!Refused(gui, player, inventory, item)) { Confirm(StowWords.Format("$ok_stow_trash_ask", Label(ItemNames.DisplayName(item), amount)), delegate { gui.SetupDragItem((ItemData)null, (Inventory)null, 1); Destroy(gui, inventory, item, amount); }); } } public static void TrashClicked(InventoryGui gui, Inventory inventory, ItemData item) { if (StowActions.Ready(out var player) && item != null && !Refused(gui, player, inventory, item)) { Destroy(gui, inventory, item, item.m_stack); } } public static void DestroyJunk(InventoryGui gui) { if (!StowActions.Ready(out var player)) { return; } Inventory inventory = ((Humanoid)player).GetInventory(); List<ItemData> junk = inventory.GetAllItems().FindAll((ItemData item) => Favourites.IsJunk(item) && Movable.CanMove(player, inventory, item)); if (junk.Count == 0) { Messages.Center("$ok_stow_nojunk"); return; } Confirm(StowWords.Format("$ok_stow_destroy_junk_ask", junk.Count), delegate { gui.SetupDragItem((ItemData)null, (Inventory)null, 1); foreach (ItemData item in junk) { Destroy(gui, inventory, item, item.m_stack); } }); } private static bool Refused(InventoryGui gui, Player player, Inventory inventory, ItemData item) { Container val = ContainerOf(gui, inventory); if ((Object)(object)val != (Object)null && !StowTargets.IsTarget(val)) { if (SharedState.IsViewing(val)) { Messages.Center("$ok_shared_readonly"); } return true; } string text = Movable.Blocker(player, inventory, item); if (text == null) { return false; } if (text.Length > 0) { Messages.Center(StowWords.Format(text, ItemNames.DisplayName(item))); } return true; } private static string Label(string name, int amount) { if (amount <= 1) { return name; } return name + " x" + amount; } private static void Confirm(string text, Action action) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown if (!StowSettings.ConfirmTrash.Value || !UnifiedPopup.IsAvailable()) { action(); return; } string text2 = Language.Localize("$ok_stow_trash"); PopupButtonCallback val = delegate { UnifiedPopup.Pop(); action(); }; object obj = <>O.<0>__Pop; if (obj == null) { PopupButtonCallback val2 = UnifiedPopup.Pop; <>O.<0>__Pop = val2; obj = (object)val2; } UnifiedPopup.Push((PopupBase)new YesNoPopup(text2, text, val, (PopupButtonCallback)obj, false, false)); } private static void Destroy(InventoryGui gui, Inventory inventory, ItemData item, int amount) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || inventory == null || !inventory.ContainsItem(item)) { return; } Container val = ContainerOf(gui, inventory); if ((Object)(object)val != (Object)null && StowTargets.IsShared(val)) { TakeAndDestroy(localPlayer, val, item, amount); } else { if ((Object)(object)val != (Object)null && !ContainerScan.Claim(val)) { return; } string text = Label(ItemNames.DisplayName(item), amount); if ((Object)(object)val == (Object)null && amount >= item.m_stack && StowSettings.TrashUsesSalvage.Value && SalvageActions.CanSalvage(item)) { if (SalvageActions.Salvage(localPlayer, item)) { Messages.Center(StowWords.Format("$ok_stow_salvaged", text)); }