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 WiresStackify v0.1.4
WiresStackify.dll
Decompiled a day 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.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("WiresStackify")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+131b950bb0584d98bfd3f18de07030645be872b5")] [assembly: AssemblyProduct("WiresStackify")] [assembly: AssemblyTitle("WiresStackify")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 WiresStackify { internal enum StackAction { None, Sort, SortByWeight, QuickStack, Restock, QuickStackAndRestock, Everything } internal static class Actions { internal sealed class PanelMiddleClick : MonoBehaviour, IPointerDownHandler, IEventSystemHandler { public void OnPointerDown(PointerEventData e) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) if ((int)e.button == 2) { Clicked(((Component)this).gameObject, e.position); } } } [HarmonyPatch(typeof(InventoryGui), "Awake")] private static class PanelClickSetup { private static void Postfix(InventoryGui __instance) { if ((Object)(object)__instance.m_dropButton != (Object)null) { Add(((Component)__instance.m_dropButton).gameObject); } if ((Object)(object)__instance.m_player != (Object)null) { Add(((Component)__instance.m_player).gameObject); } if ((Object)(object)__instance.m_container != (Object)null) { Add(((Component)__instance.m_container).gameObject); } } private static void Add(GameObject go) { if ((Object)(object)go.GetComponent<PanelMiddleClick>() == (Object)null) { go.AddComponent<PanelMiddleClick>(); } } } [HarmonyPatch(typeof(UIInputHandler), "OnPointerDown")] private static class SlotMiddleClick { private static void Postfix(UIInputHandler __instance, PointerEventData eventData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((int)eventData.button == 2 && (Object)(object)((Component)__instance).GetComponent<PanelMiddleClick>() == (Object)null) { Clicked(((Component)__instance).gameObject, eventData.position); } } } internal const float ResultDelay = 0.1f; private static GameObject _rustle; internal static void Do(StackAction action, bool chest) { Player localPlayer = Player.m_localPlayer; if (action == StackAction.None || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting()) { return; } Rustle(); bool flag = false; try { switch (action) { case StackAction.Sort: case StackAction.SortByWeight: { bool flag2 = action == StackAction.SortByWeight; flag = Sorting.Run(chest, flag2 ? Sorting.Mode.Weight : Sorting.Mode.Type); if (flag) { ButtonFeel.Wiggle(chest, flag2 ? (-1f) : 1f); if (flag2) { WeightShake.Shake(chest); } } break; } case StackAction.QuickStack: flag = QuickStack.Run(localPlayer, chest) > 0; if (flag) { Later(((Humanoid)localPlayer).m_pickupEffects); } break; case StackAction.Restock: flag = Restock.Run(localPlayer, chest) > 0; if (flag) { Later(((Humanoid)localPlayer).m_dropEffects); } break; case StackAction.QuickStackAndRestock: { int num4 = QuickStack.Run(localPlayer, chest); int num5 = Restock.Run(localPlayer, chest); flag = num4 > 0 || num5 > 0; if (flag) { Later((num4 > 0) ? ((Humanoid)localPlayer).m_pickupEffects : ((Humanoid)localPlayer).m_dropEffects); } break; } case StackAction.Everything: { StackifyEffects.Used.Clear(); int num = QuickStack.Run(localPlayer, chest); int num2 = Restock.Run(localPlayer, chest); List<Container> chests = new List<Container>(StackifyEffects.Used); StackifyEffects.Used.Clear(); int num3 = Sorting.RunAll(chests, Sorting.Mode.Type); flag = num > 0 || num2 > 0 || num3 > 0; if (num > 0 || num2 > 0) { Later((num > 0) ? ((Humanoid)localPlayer).m_pickupEffects : ((Humanoid)localPlayer).m_dropEffects); } if (num3 > 0) { ButtonFeel.Wiggle(chest, 1f); } break; } } } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Stackify action failed: " + ex)); } if (!flag) { ButtonFeel.Squeeze(chest); } StackifyButtons.RefreshHover(); } internal static void DropOn(bool chest, ItemData item, Inventory from) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || item == null) { return; } Rustle(); int num = 0; try { if (chest) { Container chest2 = (((Object)(object)InventoryGui.instance != (Object)null) ? StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance) : null); num = Restock.RunOnly(localPlayer, chest2, item); } else if (from == ((Humanoid)localPlayer).GetInventory()) { num = QuickStack.Run(localPlayer, onlyThisChest: false, null, item); } } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Stackify drop failed: " + ex)); } if (num > 0) { StackifyPlugin.DropDragItem(); Later(chest ? ((Humanoid)localPlayer).m_dropEffects : ((Humanoid)localPlayer).m_pickupEffects); } else { ButtonFeel.Squeeze(chest); } StackifyButtons.RefreshHover(); } internal static void Rustle() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)_rustle == (Object)null && (Object)(object)instance != (Object)null && instance.m_closeInventoryEffects != null) { EffectData[] effectPrefabs = instance.m_closeInventoryEffects.m_effectPrefabs; foreach (EffectData val in effectPrefabs) { if (val != null && val.m_enabled && (Object)(object)val.m_prefab != (Object)null && (Object)(object)val.m_prefab.GetComponentInChildren<ZSFX>(true) != (Object)null) { _rustle = val.m_prefab; break; } } } if ((Object)(object)_rustle != (Object)null) { StackifyEffects.PlayUi(_rustle, 1.25f); } } internal static void Later(EffectList sound) { ((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(After(0.1f, delegate { //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) StackifyEffects.SpawnLocal(sound, StackifyEffects.Ear(), Quaternion.identity); })); } internal static IEnumerator After(float seconds, Action then) { yield return (object)new WaitForSecondsRealtime(seconds); then(); } internal static StackAction ForButton(int button, bool shift) { return button switch { 0 => (shift ? StackifyPlugin.ShiftLeftClick : StackifyPlugin.LeftClick).Value, 1 => (shift ? StackifyPlugin.ShiftRightClick : StackifyPlugin.RightClick).Value, 2 => (shift ? StackifyPlugin.ShiftMiddleClick : StackifyPlugin.MiddleClick).Value, _ => StackAction.None, }; } internal static bool Shift() { if (!Input.GetKey((KeyCode)304)) { return Input.GetKey((KeyCode)303); } return true; } internal static string Describe(StackAction a) { return a switch { StackAction.Sort => "sort by type", StackAction.SortByWeight => "sort by weight", StackAction.QuickStack => "quick stack", StackAction.Restock => "restock", StackAction.QuickStackAndRestock => "quick stack, restock", StackAction.Everything => "quick stack, restock, sort all used", _ => null, }; } private static void Clicked(GameObject source, Vector2 mouse) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || !InventoryGui.IsVisible() || (Object)(object)source == (Object)null) { return; } StackAction value = (Shift() ? StackifyPlugin.PanelShiftMiddleClick : StackifyPlugin.PanelMiddleClick).Value; if (value == StackAction.None || (Object)(object)StackifyPlugin.DragGo.Invoke(instance) != (Object)null) { return; } RectTransform player = instance.m_player; RectTransform container = instance.m_container; if ((Object)(object)player == (Object)null) { return; } bool flag = (Object)(object)StackifyPlugin.CurrentContainer.Invoke(instance) != (Object)null && (Object)(object)container != (Object)null && ((Component)container).gameObject.activeInHierarchy; Transform transform = source.transform; bool flag2 = (Object)(object)instance.m_dropButton != (Object)null && (Object)(object)transform == (Object)(object)((Component)instance.m_dropButton).transform; int num; if (flag && transform.IsChildOf((Transform)(object)container)) { num = 2; } else if (transform.IsChildOf((Transform)(object)player)) { num = 1; } else { if (!flag2) { return; } num = ((!flag) ? 1 : ((mouse.y >= (Edge(player, top: false) + Edge(container, top: true)) * 0.5f) ? 1 : 2)); } Do(value, num == 2); } private static float Edge(RectTransform r, bool top) { //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_0037: 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) Vector3[] array = (Vector3[])(object)new Vector3[4]; r.GetWorldCorners(array); Camera val = Cam(r); float num = (top ? float.MinValue : float.MaxValue); Vector3[] array2 = array; foreach (Vector3 val2 in array2) { float y = RectTransformUtility.WorldToScreenPoint(val, val2).y; num = (top ? Mathf.Max(num, y) : Mathf.Min(num, y)); } return num; } private static bool Over(RectTransform r, Vector2 screen) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (((Component)r).gameObject.activeInHierarchy) { return RectTransformUtility.RectangleContainsScreenPoint(r, screen, Cam(r)); } return false; } private static Camera Cam(RectTransform r) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) Canvas componentInParent = ((Component)r).GetComponentInParent<Canvas>(); if (!((Object)(object)componentInParent != (Object)null) || (int)componentInParent.renderMode == 0) { return null; } return componentInParent.rootCanvas.worldCamera; } } internal sealed class Favorites { [HarmonyPatch(typeof(InventoryGrid), "OnLeftDown")] private static class LeftPatch { private static bool Prefix(InventoryGrid __instance, UIInputHandler __0) { return Click(__instance, __0, left: true); } } [HarmonyPatch(typeof(InventoryGrid), "OnRightDown")] private static class RightPatch { private static bool Prefix(InventoryGrid __instance, UIInputHandler __0) { return Click(__instance, __0, left: false); } } [HarmonyPatch(typeof(Inventory), "Changed")] private static class InventoryChangedPatch { private static void Postfix(Inventory __instance) { if ((Object)(object)Player.m_localPlayer != (Object)null && __instance == ((Humanoid)Player.m_localPlayer).GetInventory()) { _version++; } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] private static class BorderPatch { private static void Postfix(InventoryGrid __instance, Player player) { if ((Object)(object)player == (Object)null || (Object)(object)InventoryGui.instance == (Object)null || (Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid) { return; } Inventory val = GridInventory.Invoke(__instance); if (val != ((Humanoid)player).GetInventory()) { return; } List<InventoryElement> list = GridElements.Invoke(__instance); if (_drawnVersion != _version || _drawnElements != list || _drawnCount != list.Count) { if (_drawnElements != list) { Frames.Clear(); } _drawnVersion = _version; _drawnElements = list; _drawnCount = list.Count; Draw(val, list, For(player)); } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] private static class TooltipPatch { private static void Postfix(ItemData item, bool crafting, ref string __result) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (!crafting && StackifyPlugin.FavoriteTooltip.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && item != null && For(Player.m_localPlayer).IsItemFavorited(item.m_shared)) { __result = __result + "\n<color=#" + ColorUtility.ToHtmlStringRGB(StackifyPlugin.ColorItem.Value) + ">Favorited: won't be quick stacked</color>"; } } } private static readonly Dictionary<long, Favorites> ByPlayer = new Dictionary<long, Favorites>(); private static int _version; private readonly string _path; private readonly HashSet<Vector2i> _slots = new HashSet<Vector2i>(); private readonly HashSet<string> _items = new HashSet<string>(); private static readonly Func<InventoryGrid, GameObject, Vector2i> ButtonPos = AccessTools.MethodDelegate<Func<InventoryGrid, GameObject, Vector2i>>(AccessTools.Method(typeof(InventoryGrid), "GetButtonPos", (Type[])null, (Type[])null), (object)null, true); internal static readonly FieldRef<InventoryGrid, Inventory> GridInventory = AccessTools.FieldRefAccess<InventoryGrid, Inventory>("m_inventory"); internal static readonly FieldRef<InventoryGrid, List<InventoryElement>> GridElements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements"); private static GameObject _click; private static Sprite _border; private static int _drawnVersion = -1; private static List<InventoryElement> _drawnElements; private static int _drawnCount; private const string SlotFrame = "WireStackifySlotFrame"; private const string ItemFrame = "WireStackifyItemFrame"; private static readonly Dictionary<InventoryElement, Image[]> Frames = new Dictionary<InventoryElement, Image[]>(); private const string StackRing = "WireStackifyStackRing"; private const string RestockRing = "WireStackifyRestockRing"; private static readonly List<Image> Previewing = new List<Image>(); private static readonly FieldRef<GuiBar, Color> BarColor = AccessTools.FieldRefAccess<GuiBar, Color>("m_originalColor"); private static readonly Color Blue = new Color(0.376f, 0.66f, 0.897f, 1f); internal static Favorites For(Player p) { long playerID = p.GetPlayerID(); if (!ByPlayer.TryGetValue(playerID, out var value)) { value = (ByPlayer[playerID] = new Favorites(playerID)); } return value; } internal static void MarkDirty() { _version++; } private Favorites(long id) { _path = Path.Combine(Paths.ConfigPath, "WiresStackify_favorites_" + id + ".txt"); if (File.Exists(_path)) { Load(); } else if (ImportQuickStackStore(id)) { Save(); } } internal bool IsFavorited(ItemData item) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (!_items.Contains(item.m_shared.m_name)) { return _slots.Contains(item.m_gridPos); } return true; } internal bool IsItemFavorited(SharedData s) { return _items.Contains(s.m_name); } internal bool IsSlotFavorited(Vector2i pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _slots.Contains(pos); } internal void ToggleSlot(Vector2i pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!_slots.Remove(pos)) { _slots.Add(pos); } Save(); } internal void ToggleItem(SharedData s) { if (!_items.Remove(s.m_name)) { _items.Add(s.m_name); } Save(); } private void Load() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) try { string[] array = File.ReadAllLines(_path); foreach (string text in array) { if (text.StartsWith("slot ")) { string[] array2 = text.Split(new char[1] { ' ' }); if (array2.Length == 3 && int.TryParse(array2[1], out var result) && int.TryParse(array2[2], out var result2)) { _slots.Add(new Vector2i(result, result2)); } } else if (text.StartsWith("item ")) { _items.Add(text.Substring(5)); } } } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Couldn't read favorites: " + ex.Message)); } MarkDirty(); } private void Save() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) try { StringBuilder stringBuilder = new StringBuilder(); foreach (Vector2i slot in _slots) { stringBuilder.Append("slot ").Append(slot.x).Append(' ') .Append(slot.y) .Append('\n'); } foreach (string item in _items) { stringBuilder.Append("item ").Append(item).Append('\n'); } File.WriteAllText(_path, stringBuilder.ToString()); } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Couldn't save favorites: " + ex.Message)); } MarkDirty(); } private bool ImportQuickStackStore(long id) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) string path = Path.Combine(Paths.ConfigPath, "QuickStackStore_player_" + id + ".dat"); if (!File.Exists(path)) { return false; } try { using (Stream serializationStream = File.OpenRead(path)) { BinaryFormatter binaryFormatter = new BinaryFormatter(); if (binaryFormatter.Deserialize(serializationStream) is List<Tuple<int, int>> list) { foreach (Tuple<int, int> item in list) { _slots.Add(new Vector2i(item.Item1, item.Item2)); } } if (binaryFormatter.Deserialize(serializationStream) is List<string> list2) { foreach (string item2 in list2) { _items.Add(item2); } } } StackifyPlugin.Log.LogInfo((object)("Took over Quick Stack Store favorites: " + _slots.Count + " slots, " + _items.Count + " items.")); return _slots.Count > 0 || _items.Count > 0; } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Couldn't read Quick Stack Store favorites: " + ex.Message)); return false; } } private static bool Favoriting(InventoryGrid grid) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)InventoryGui.instance != (Object)null && (Object)(object)grid == (Object)(object)InventoryGui.instance.m_playerGrid && (Object)(object)Player.m_localPlayer != (Object)null && !((Character)Player.m_localPlayer).IsTeleporting() && (Object)(object)StackifyPlugin.DragGo.Invoke(InventoryGui.instance) == (Object)null) { if (!StackifyPlugin.Held(StackifyPlugin.FavoriteKey1.Value)) { return StackifyPlugin.Held(StackifyPlugin.FavoriteKey2.Value); } return true; } return false; } private static bool Click(InventoryGrid grid, UIInputHandler handler, bool left) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)handler == (Object)null || !Favoriting(grid)) { return true; } Vector2i val = ButtonPos(grid, ((Component)handler).gameObject); if (val == new Vector2i(-1, -1)) { return true; } Favorites favorites = For(Player.m_localPlayer); bool flag; if (!left) { favorites.ToggleSlot(val); flag = favorites.IsSlotFavorited(val); } else { ItemData itemAt = GridInventory.Invoke(grid).GetItemAt(val.x, val.y); if (itemAt == null) { return true; } favorites.ToggleItem(itemAt.m_shared); flag = favorites.IsItemFavorited(itemAt.m_shared); } ToggleSound(flag); if (flag) { List<InventoryElement> list = GridElements.Invoke(grid); int num = val.y * GridInventory.Invoke(grid).GetWidth() + val.x; if (list != null && num >= 0 && num < list.Count) { ((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(PopFrame(list[num], left ? "WireStackifyItemFrame" : "WireStackifySlotFrame", left ? 3f : 0f)); } } return false; } private static void ToggleSound(bool on) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if ((Object)(object)_click == (Object)null && (Object)(object)instance != (Object)null && (Object)(object)instance.m_takeAllButton != (Object)null) { ButtonSfx component = ((Component)instance.m_takeAllButton).GetComponent<ButtonSfx>(); if ((Object)(object)component != (Object)null) { _click = component.m_sfxPrefab; } } if ((Object)(object)_click != (Object)null) { StackifyEffects.PlayNow(_click, StackifyEffects.Ear(), Quaternion.identity, null, on ? 0.82f : 1.18f); } } private static IEnumerator PopFrame(InventoryElement e, string name, float inset) { yield return null; Image img = Frame(e, name, inset); if ((Object)(object)img == (Object)null) { yield break; } RectTransform r = ((Graphic)img).rectTransform; Color full = ((Graphic)img).color; float x = 0.35f; float v = 0f; for (float t = 0f; t < 0.45f; t += Time.unscaledDeltaTime) { if ((Object)(object)r == (Object)null || (Object)(object)img == (Object)null) { yield break; } float num = Mathf.Min(Time.unscaledDeltaTime, 0.05f); v += ((0f - x) * 420f - v * 20f) * num; x += v * num; float num2 = 1f + x; ((Transform)r).localScale = new Vector3(num2, num2, 1f); Color color = ((Graphic)img).color; color.a = full.a * Mathf.Clamp01(t / 0.08f); ((Graphic)img).color = color; if (t > 0.12f && Mathf.Abs(x) < 0.002f && Mathf.Abs(v) < 0.02f) { break; } yield return null; } if ((Object)(object)r != (Object)null) { ((Transform)r).localScale = Vector3.one; } if ((Object)(object)img != (Object)null) { Color color2 = ((Graphic)img).color; color2.a = full.a; ((Graphic)img).color = color2; } } private static void Draw(Inventory inv, List<InventoryElement> elements, Favorites fav) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) int width = inv.GetWidth(); int height = inv.GetHeight(); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int num = i * width + j; if (num >= elements.Count) { break; } Show(Frame(elements[num], "WireStackifySlotFrame", 0f), fav.IsSlotFavorited(new Vector2i(j, i)), StackifyPlugin.ColorSlot.Value); Show(Frame(elements[num], "WireStackifyItemFrame", 3f), on: false, StackifyPlugin.ColorItem.Value); } } foreach (ItemData allItem in inv.GetAllItems()) { if (fav.IsItemFavorited(allItem.m_shared)) { int num2 = allItem.m_gridPos.y * width + allItem.m_gridPos.x; if (num2 >= 0 && num2 < elements.Count) { Show(Frame(elements[num2], "WireStackifyItemFrame", 3f), on: true, StackifyPlugin.ColorItem.Value); } } } } private static void Show(Image img, bool on, Color color) { //IL_000b: 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_0019: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)img == (Object)null)) { if (((Graphic)img).color != color) { ((Graphic)img).color = color; } if (((Behaviour)img).enabled != on) { ((Behaviour)img).enabled = on; } } } private static Image Frame(InventoryElement e, string name, float inset) { if ((Object)(object)e == (Object)null || (Object)(object)e.m_queued == (Object)null) { return null; } int num = name switch { "WireStackifyStackRing" => 2, "WireStackifyItemFrame" => 1, "WireStackifySlotFrame" => 0, _ => 3, }; if (!Frames.TryGetValue(e, out var value)) { value = (Frames[e] = (Image[])(object)new Image[4]); } if ((Object)(object)value[num] != (Object)null) { return value[num]; } Transform val = ((Component)e.m_queued).transform.Find(name); if ((Object)(object)val != (Object)null) { return value[num] = ((Component)val).GetComponent<Image>(); } value[num] = MakeFrame(e, name, inset); return value[num]; } private static Image MakeFrame(InventoryElement e, string name, float inset) { //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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_005c: 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_00bd: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(((Component)e.m_queued).transform, false); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = new Vector2(inset, inset); val2.offsetMax = new Vector2(0f - inset, 0f - inset); Image component = val.GetComponent<Image>(); Image val3 = (((Object)(object)e.m_selected != (Object)null) ? e.m_selected.GetComponentInChildren<Image>(true) : null); if ((Object)(object)val3 != (Object)null && (Object)(object)val3.sprite != (Object)null) { component.sprite = val3.sprite; component.type = val3.type; component.pixelsPerUnitMultiplier = val3.pixelsPerUnitMultiplier; component.fillCenter = false; } else { component.sprite = BorderSprite(); } ((Graphic)component).raycastTarget = false; ((Behaviour)component).enabled = false; return component; } private static Sprite BorderSprite() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_border != (Object)null) { return _border; } float num = 3f; float num2 = 8f; Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); ((Texture)val).wrapMode = (TextureWrapMode)1; Color32[] array = (Color32[])(object)new Color32[16384]; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num3 = (float)j + 0.5f - 64f; float num4 = (float)i + 0.5f - 64f; float num5 = 64f; float num6 = Mathf.Abs(num3) - num5 + num2; float num7 = Mathf.Abs(num4) - num5 + num2; Vector2 val2 = new Vector2(Mathf.Max(num6, 0f), Mathf.Max(num7, 0f)); float num8 = ((Vector2)(ref val2)).magnitude + Mathf.Min(Mathf.Max(num6, num7), 0f) - num2; float num9 = Mathf.Clamp01(0.5f - num8) * Mathf.Clamp01(num8 + num + 0.5f); array[i * 128 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(num9 * 255f)); } } val.SetPixels32(array); val.Apply(); _border = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 100f); return _border; } private static Color Yellow() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_staminaBar2Fast != (Object)null) { Color val = BarColor.Invoke(Hud.instance.m_staminaBar2Fast); if (val.a > 0f) { val.a = 1f; return val; } } } catch (Exception) { } return new Color(1f, 0.848f, 0f, 1f); } internal static string BlueHex() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return ColorUtility.ToHtmlStringRGB(Blue); } internal static string YellowHex() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return ColorUtility.ToHtmlStringRGB(Yellow()); } internal static void ShowPreview(List<ItemData> stack, List<ItemData> restock) { //IL_007d: 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) ClearPreview(); InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_playerGrid == (Object)null || (Object)(object)localPlayer == (Object)null) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (GridInventory.Invoke(instance.m_playerGrid) != inventory) { return; } List<InventoryElement> list = GridElements.Invoke(instance.m_playerGrid); if (list != null) { int width = inventory.GetWidth(); if (stack != null) { Mark(stack, list, width, "WireStackifyStackRing", 0f, Yellow()); } if (restock != null) { Mark(restock, list, width, "WireStackifyRestockRing", 3f, Blue); } } } private static void Mark(List<ItemData> items, List<InventoryElement> elements, int w, string ring, float inset, Color c) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) foreach (ItemData item in items) { int num = item.m_gridPos.y * w + item.m_gridPos.x; if (num < 0 || num >= elements.Count) { continue; } Image val = Frame(elements[num], ring, inset); if (!((Object)(object)val == (Object)null)) { if (((Graphic)val).color != c) { ((Graphic)val).color = c; } ((Component)val).transform.SetAsLastSibling(); ((Behaviour)val).enabled = true; Previewing.Add(val); } } } internal static void ClearPreview() { foreach (Image item in Previewing) { if ((Object)(object)item != (Object)null) { ((Behaviour)item).enabled = false; } } Previewing.Clear(); } } internal static class NearbyChests { [HarmonyPatch(typeof(Container), "Awake")] private static class AwakePatch { private static void Postfix(Container __instance) { if ((Object)(object)NView.Invoke(__instance) != (Object)null) { All.Add(__instance); } } } private static readonly List<Container> All = new List<Container>(); internal static readonly FieldRef<Container, ZNetView> NView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); private static readonly FieldRef<Container, Piece> PieceOf = AccessTools.FieldRefAccess<Container, Piece>("m_piece"); private static readonly FieldRef<Container, bool> InUseFlag = AccessTools.FieldRefAccess<Container, bool>("m_inUse"); private static readonly FieldRef<bool> PublicServer = AccessTools.StaticFieldRefAccess<bool>(AccessTools.Field(typeof(ZNet), "m_publicServer")); private static readonly Func<Container, long, bool> CheckAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null), (object)null, true); private static readonly int InUseKey = StringExtensionMethods.GetStableHashCode("InUse"); private static readonly Predicate<Container> IsGone = (Container c) => (Object)(object)c == (Object)null; internal static List<Container> InRange(Vector3 point, float range) { //IL_002f: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) All.RemoveAll(IsGone); List<Container> list = new List<Container>(); float num = range * range; foreach (Container item in All) { Vector3 val = point - ((Component)item).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude >= num)) { ZNetView val2 = NView.Invoke(item); if ((Object)(object)val2 != (Object)null && val2.HasOwner()) { list.Add(item); } } } return list; } internal static List<Container> ForPouch(Player player, bool onlyThisChest, Container current, float range) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); if ((Object)(object)current != (Object)null) { list.Add(current); } if (onlyThisChest || range <= 0f || !AreaAllowed()) { return list; } bool singleplayer = IsTrueSingleplayer(); long playerID = player.GetPlayerID(); foreach (Container item in InRange(((Component)player).transform.position, range)) { if ((Object)(object)item != (Object)(object)current && CanUse(item, playerID, singleplayer)) { list.Add(item); } } return list; } internal static bool IsTrueSingleplayer() { if (!ZNet.IsOpenServer() && !PublicServer.Invoke() && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && !ZNet.instance.IsDedicated()) { return ZNet.instance.GetConnectedPeers().Count == 0; } return false; } internal static bool AreaAllowed() { if (!IsTrueSingleplayer() && !StackifyPlugin.HasMuc) { return StackifyPlugin.MultiplayerWithoutMuc.Value; } return true; } internal static bool CanUse(Container c, long playerId, bool singleplayer) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) Player component = ((Component)NView.Invoke(c)).GetComponent<Player>(); if ((Object)(object)component != (Object)null && (Object)(object)component != (Object)(object)Player.m_localPlayer) { return false; } if (!CheckAccess(c, playerId)) { return false; } if (c.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)c).transform.position, 0f, true, false)) { return false; } Piece val = PieceOf.Invoke(c); if ((Object)(object)val != (Object)null) { if (!val.IsPlacedByPlayer() && !StackifyPlugin.NonPlayerBuilt.Value) { return false; } } else if (c.m_name != "piece_chest_drawer" && !StackifyPlugin.NonPhysicalContainers.Value) { return false; } if (StackifyPlugin.HasMuc) { return true; } if (!singleplayer && (Object)(object)((Component)((Component)c).transform.root).GetComponentInChildren<Ship>() != (Object)null) { return false; } return !InUse(c); } private static bool InUse(Container c) { ZDO zDO = NView.Invoke(c).GetZDO(); if ((zDO == null || zDO.GetInt(InUseKey, 0) != 1) && !c.IsInUse()) { if ((Object)(object)c.m_wagon != (Object)null) { return c.m_wagon.InUse(); } return false; } return true; } internal static void Claim(Container c, bool inUse) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) ZNetView val = NView.Invoke(c); if (inUse) { val.ClaimOwnership(); } InUseFlag.Invoke(c) = inUse; if (StackifyPlugin.QuietChests.Value) { val.GetZDO().Set(InUseKey, inUse ? 1 : 0, false); } else { c.SetInUse(inUse); } ZDOMan.instance.ForceSendZDO(ZNet.GetUID(), val.GetZDO().m_uid); } } internal static class PickupSlots { [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] private static class AddItemPatch { private static void Prefix(ItemData item, out ItemData __state) { __state = _adding; _adding = item; } private static void Finalizer(ItemData __state) { _adding = __state; } } [HarmonyPatch(typeof(Inventory), "FindEmptySlot")] private static class FindEmptySlotPatch { private static void Postfix(Inventory __instance, bool topFirst, ref Vector2i __result) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_009f: Unknown result type (might be due to invalid IL or missing references) if (__result.x < 0) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || __instance != ((Humanoid)localPlayer).GetInventory()) { return; } Favorites favorites = Favorites.For(localPlayer); if (!favorites.IsSlotFavorited(__result) || (_adding != null && favorites.IsItemFavorited(_adding.m_shared))) { return; } int width = __instance.GetWidth(); int num = StackifyPlugin.MainRows(__instance, localPlayer); Vector2i val = default(Vector2i); for (int i = 0; i < num; i++) { int num2 = (topFirst ? i : (num - 1 - i)); for (int j = 0; j < width; j++) { ((Vector2i)(ref val))..ctor(j, num2); if (__instance.GetItemAt(j, num2) == null && !favorites.IsSlotFavorited(val)) { __result = val; return; } } } } } private static ItemData _adding; } internal static class QuickStack { [HarmonyPatch(typeof(Container), "RPC_StackResponse")] private static class PlaceStacksPatch { private static bool Prefix(Container __instance, bool granted) { if (!StackifyPlugin.HoldToStack.Value) { return true; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } if (granted) { Run(Player.m_localPlayer, onlyThisChest: true, __instance); } else { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_inuse", 0, (Sprite)null, false); } return false; } } private static readonly HashSet<string> Names = new HashSet<string>(); private static bool ShouldStack(ItemData item, Favorites fav, bool hotbar, int rows) { if (item.m_shared.m_maxStackSize > 1 && (item.m_gridPos.y > 0 || hotbar) && item.m_gridPos.y < rows) { return !fav.IsFavorited(item); } return false; } internal static List<ItemData> Candidates(Player player, ItemData only = null) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) Favorites favorites = Favorites.For(player); Inventory inventory = ((Humanoid)player).GetInventory(); bool value = StackifyPlugin.QuickStackHotbar.Value; int num = StackifyPlugin.MainRows(inventory, player); List<ItemData> list = new List<ItemData>(); foreach (ItemData allItem in inventory.GetAllItems()) { if (only == null) { if (ShouldStack(allItem, favorites, value, num)) { list.Add(allItem); } } else if (allItem == only || (allItem.m_shared.m_name == only.m_shared.m_name && allItem.m_gridPos.y < num && (allItem.m_gridPos.y > 0 || value) && !favorites.IsSlotFavorited(allItem.m_gridPos))) { list.Add(allItem); } } return list; } internal static List<ItemData> Preview(Player player, bool onlyThisChest, out int chests, ItemData only = null) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Invalid comparison between Unknown and I4 //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Invalid comparison between Unknown and I4 chests = 0; List<ItemData> list = new List<ItemData>(); if ((Object)(object)InventoryGui.instance == (Object)null) { return list; } Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance); if (onlyThisChest && (Object)(object)val == (Object)null) { return list; } if (only != null && !((Humanoid)player).GetInventory().ContainsItem(only)) { return list; } List<ItemData> list2 = Candidates(player, only); if (list2.Count == 0) { return list; } HashSet<Container> hashSet = new HashSet<Container>(); foreach (Container item in NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.QuickStackRange.Value)) { Inventory inventory = item.GetInventory(); Names.Clear(); bool flag = false; foreach (ItemData allItem in inventory.GetAllItems()) { Names.Add(allItem.m_shared.m_name); if ((int)allItem.m_shared.m_itemType == 13) { flag = true; } } for (int num = list2.Count - 1; num >= 0; num--) { ItemData val2 = list2[num]; if ((Names.Contains(val2.m_shared.m_name) || (flag && StackifyPlugin.TrophiesTogether.Value && (int)val2.m_shared.m_itemType == 13)) && inventory.CanAddItem(val2, -1)) { list.Add(val2); list2.RemoveAt(num); hashSet.Add(item); } } } chests = hashSet.Count; return list; } internal static int Run(Player player, bool onlyThisChest, Container chestOverride = null, ItemData only = null) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 if (((Character)player).IsTeleporting() || (Object)(object)InventoryGui.instance == (Object)null || (Object)(object)InventoryGui.instance.m_container == (Object)null) { return 0; } if (only == null) { StackifyPlugin.DropDragItem(); } Inventory inventory = ((Humanoid)player).GetInventory(); List<ItemData> list = Candidates(player, only); if (list.Count == 0) { return 0; } list.Sort((ItemData a, ItemData b) => -StackifyPlugin.CompareSlotOrder(a.m_gridPos, b.m_gridPos)); List<ItemData> list2 = null; if (StackifyPlugin.TrophiesTogether.Value) { list2 = new List<ItemData>(); for (int num = list.Count - 1; num >= 0; num--) { if ((int)list[num].m_shared.m_itemType == 13) { list2.Insert(0, list[num]); list.RemoveAt(num); } } } int num2 = 0; Container val = (((Object)(object)chestOverride != (Object)null) ? chestOverride : StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance)); List<StackifyEffects.Hit> list3 = new List<StackifyEffects.Hit>(); foreach (Container item in NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.QuickStackRange.Value)) { int num3; if ((Object)(object)item == (Object)(object)val || StackifyPlugin.HasMuc) { num3 = IntoChest(list2, list, inventory, item.GetInventory(), changed: false); } else { NearbyChests.Claim(item, inUse: true); num3 = IntoChest(list2, list, inventory, item.GetInventory(), changed: false); NearbyChests.Claim(item, inUse: false); } if (num3 > 0) { num2 += num3; list3.Add(new StackifyEffects.Hit { Chest = item, Count = num3 }); } } if (num2 > 0) { StackifyPlugin.Changed(inventory); } if (num2 > 0) { StackifyButtons.Feedback(StackifyEffects.Kind.Stack, num2, onlyThisChest); } StackifyEffects.Play(StackifyEffects.Kind.Stack, list3, val, player, onlyThisChest); return num2; } private static int IntoChest(List<ItemData> trophies, List<ItemData> items, Inventory inv, Inventory chest, bool changed) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 int num = 0; List<ItemData> allItems = chest.GetAllItems(); if (trophies != null && trophies.Count > 0) { bool flag = false; foreach (ItemData item in allItems) { if ((int)item.m_shared.m_itemType == 13) { flag = true; break; } } if (flag) { for (int num2 = trophies.Count - 1; num2 >= 0; num2--) { if (chest.AddItem(trophies[num2])) { inv.RemoveItem(trophies[num2]); trophies.RemoveAt(num2); num++; } } } } if (items.Count > 0 && allItems.Count > 0) { Names.Clear(); foreach (ItemData item2 in allItems) { Names.Add(item2.m_shared.m_name); } for (int num3 = items.Count - 1; num3 >= 0; num3--) { ItemData val = items[num3]; if (Names.Contains(val.m_shared.m_name) && chest.AddItem(val)) { inv.RemoveItem(val); items.RemoveAt(num3); num++; } } } if (changed) { StackifyPlugin.Changed(inv); } return num; } } internal static class Restock { private sealed class Want { public ItemData Item; public int Have; public int Max; } private static int MaxFor(SharedData s) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 int maxStackSize = s.m_maxStackSize; int num = 0; if ((int)s.m_itemType == 9) { num = StackifyPlugin.RestockLimitAmmo.Value; } else if ((int)s.m_itemType == 2) { num = StackifyPlugin.RestockLimitConsumables.Value; } if (num <= 0) { num = StackifyPlugin.RestockLimitGeneral.Value; } if (num <= 0) { return maxStackSize; } return Math.Min(maxStackSize, num); } private static bool ShouldRestock(ItemData item, Favorites fav, bool hotbar) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_005b: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 int num = MaxFor(item.m_shared); ItemType itemType = item.m_shared.m_itemType; if (num > 1 && num > item.m_stack && (item.m_customData == null || item.m_customData.Count == 0) && (item.m_gridPos.y > 0 || hotbar) && (!StackifyPlugin.RestockOnlyAmmoAndFood.Value || (int)itemType == 9 || (int)itemType == 2)) { if (StackifyPlugin.RestockOnlyFavorites.Value) { return fav.IsFavorited(item); } return true; } return false; } private static List<Want> WantsFor(Player player, ItemData kind) { List<Want> list = new List<Want>(); foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (allItem.m_shared.m_name == kind.m_shared.m_name && allItem.m_quality == kind.m_quality && allItem.m_shared.m_maxStackSize > 1 && allItem.m_stack < allItem.m_shared.m_maxStackSize && (allItem.m_customData == null || allItem.m_customData.Count == 0)) { list.Add(new Want { Item = allItem, Have = allItem.m_stack, Max = allItem.m_shared.m_maxStackSize }); } } return list; } private static float Room(Player player) { return Math.Max(0f, player.GetMaxCarryWeight() - ((Humanoid)player).GetInventory().GetTotalWeight()); } private static int Fits(Want want, int take, float room) { float weight = want.Item.GetWeight(1); if (weight <= 0f) { return take; } return Math.Min(take, (int)Math.Floor(room / weight + 0.0001f)); } private static List<Want> NormalWants(Player player) { Favorites fav = Favorites.For(player); bool value = StackifyPlugin.RestockHotbar.Value; List<Want> list = new List<Want>(); foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (ShouldRestock(allItem, fav, value)) { list.Add(new Want { Item = allItem, Have = allItem.m_stack, Max = MaxFor(allItem.m_shared) }); } } list.Sort((Want a, Want b) => -StackifyPlugin.CompareSlotOrder(a.Item.m_gridPos, b.Item.m_gridPos)); return list; } internal static List<ItemData> PreviewOnly(Player player, Container chest, ItemData kind, out float weight) { weight = 0f; if ((Object)(object)player == (Object)null || (Object)(object)chest == (Object)null || kind == null) { return new List<ItemData>(); } List<Want> list = WantsFor(player, kind); list.Sort((Want a, Want b) => -StackifyPlugin.CompareSlotOrder(a.Item.m_gridPos, b.Item.m_gridPos)); int containers; return Simulate(list, new List<Container> { chest }, Room(player), out containers, out weight); } internal static int RunOnly(Player player, Container chest, ItemData kind) { if ((Object)(object)player == (Object)null || (Object)(object)chest == (Object)null || kind == null || ((Character)player).IsTeleporting()) { return 0; } Inventory inventory = ((Humanoid)player).GetInventory(); List<Want> list = WantsFor(player, kind); if (list.Count == 0) { return 0; } list.Sort((Want a, Want b) => -StackifyPlugin.CompareSlotOrder(a.Item.m_gridPos, b.Item.m_gridPos)); HashSet<Vector2i> hashSet = new HashSet<Vector2i>(); float room = Room(player); FromChest(list, inventory, chest.GetInventory(), hashSet, ref room, out var took); if (hashSet.Count > 0) { StackifyPlugin.Changed(inventory); } List<StackifyEffects.Hit> list2 = new List<StackifyEffects.Hit>(); if (took) { list2.Add(new StackifyEffects.Hit { Chest = chest, Count = hashSet.Count }); } if (hashSet.Count > 0) { StackifyButtons.Feedback(StackifyEffects.Kind.Restock, hashSet.Count, chest: true); } StackifyEffects.Play(StackifyEffects.Kind.Restock, list2, chest, player, chestButton: true); return hashSet.Count; } internal static int Run(Player player, bool onlyThisChest) { if (((Character)player).IsTeleporting() || (Object)(object)InventoryGui.instance == (Object)null || (Object)(object)InventoryGui.instance.m_container == (Object)null) { return 0; } StackifyPlugin.DropDragItem(); Inventory inventory = ((Humanoid)player).GetInventory(); List<Want> list = NormalWants(player); if (list.Count == 0) { return 0; } float room = Room(player); HashSet<Vector2i> hashSet = new HashSet<Vector2i>(); Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance); List<StackifyEffects.Hit> list2 = new List<StackifyEffects.Hit>(); foreach (Container item in NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.RestockRange.Value)) { if (list.Count == 0 || room <= 0f) { break; } int count = hashSet.Count; bool took; if ((Object)(object)item == (Object)(object)val || StackifyPlugin.HasMuc) { FromChest(list, inventory, item.GetInventory(), hashSet, ref room, out took); } else { NearbyChests.Claim(item, inUse: true); FromChest(list, inventory, item.GetInventory(), hashSet, ref room, out took); NearbyChests.Claim(item, inUse: false); } if (took) { list2.Add(new StackifyEffects.Hit { Chest = item, Count = hashSet.Count - count }); } } if (hashSet.Count > 0) { StackifyPlugin.Changed(inventory); } if (hashSet.Count > 0) { StackifyButtons.Feedback(StackifyEffects.Kind.Restock, hashSet.Count, onlyThisChest); } StackifyEffects.Play(StackifyEffects.Kind.Restock, list2, val, player, onlyThisChest); return hashSet.Count; } private static void FromChest(List<Want> wants, Inventory inv, Inventory chest, HashSet<Vector2i> touched, ref float room, out bool took) { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) took = false; List<ItemData> allItems = chest.GetAllItems(); for (int num = wants.Count - 1; num >= 0; num--) { Want want = wants[num]; for (int num2 = allItems.Count - 1; num2 >= 0; num2--) { if (num2 < allItems.Count) { ItemData val = allItems[num2]; if ((val.m_customData == null || val.m_customData.Count <= 0) && !(val.m_shared.m_name != want.Item.m_shared.m_name) && val.m_quality == want.Item.m_quality) { int num3 = Fits(want, Math.Min(want.Max - want.Have, val.m_stack), room); if (num3 <= 0) { break; } want.Have += num3; room -= want.Item.GetWeight(num3); took = true; touched.Add(want.Item.m_gridPos); inv.MoveItemToThis(chest, val, num3, want.Item.m_gridPos.x, want.Item.m_gridPos.y); if (want.Have >= want.Max) { wants.RemoveAt(num); break; } } } } } } internal static List<ItemData> Preview(Player player, bool onlyThisChest, out int containers, out float weight) { containers = 0; weight = 0f; if ((Object)(object)InventoryGui.instance == (Object)null) { return new List<ItemData>(); } Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance); if (onlyThisChest && (Object)(object)val == (Object)null) { return new List<ItemData>(); } List<Container> chests = NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.RestockRange.Value); return Simulate(NormalWants(player), chests, Room(player), out containers, out weight); } private static List<ItemData> Simulate(List<Want> wants, List<Container> chests, float room, out int containers, out float weight) { containers = 0; weight = 0f; List<ItemData> list = new List<ItemData>(); if (wants.Count == 0) { return list; } foreach (Container chest in chests) { if (wants.Count == 0 || room <= 0f) { break; } Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { if (allItem.m_customData == null || allItem.m_customData.Count <= 0) { string key = allItem.m_shared.m_name + "|" + allItem.m_quality; dictionary.TryGetValue(key, out var value); dictionary[key] = value + allItem.m_stack; } } bool flag = false; for (int num = wants.Count - 1; num >= 0; num--) { Want want = wants[num]; string key2 = want.Item.m_shared.m_name + "|" + want.Item.m_quality; if (dictionary.TryGetValue(key2, out var value2) && value2 > 0) { int num2 = Fits(want, Math.Min(want.Max - want.Have, value2), room); if (num2 > 0) { dictionary[key2] = value2 - num2; want.Have += num2; float weight2 = want.Item.GetWeight(num2); room -= weight2; weight += weight2; flag = true; if (!list.Contains(want.Item)) { list.Add(want.Item); } if (want.Have >= want.Max) { wants.RemoveAt(num); } } } } if (flag) { containers++; } } return list; } } internal static class Sorting { internal enum Mode { Type, Weight } [HarmonyPatch(typeof(Container), "Awake")] private static class RpcPatch { private static void Postfix(Container __instance) { ZNetView val = NearbyChests.NView.Invoke(__instance); if ((Object)(object)val == (Object)null || val.GetZDO() == null) { return; } Container c = __instance; val.Register<int>("WireStackify_RequestSort3", (Action<long, int>)delegate(long sender, int mode) { ZNetView val2 = NearbyChests.NView.Invoke(c); if ((Object)(object)val2 != (Object)null && val2.IsOwner()) { Sort(c.GetInventory(), null, c.GetInventory().GetHeight(), (Mode)mode); } }); } } private const string RpcName = "WireStackify_RequestSort3"; private static readonly int[] TypeToCategory = new int[24] { 0, 2, 4, 7, 7, 8, 10, 10, 0, 6, 0, 10, 10, 1, 7, 7, 0, 10, 9, 7, 7, 3, 7, 5 }; private static readonly FieldRef<InventoryGui, InventoryGrid> ContainerGrid = AccessTools.FieldRefAccess<InventoryGui, InventoryGrid>("m_containerGrid"); private static GameObject _moveSound; private static bool _moveSearched; internal static bool Run(bool chest, Mode mode) { InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting()) { return false; } try { if (!chest) { return SortInventory(instance, localPlayer, mode); } Container val = StackifyPlugin.CurrentContainer.Invoke(instance); return (Object)(object)val != (Object)null && SortChest(instance, val, mode); } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Sorting failed: " + ex)); return false; } } internal static int RunAll(IEnumerable<Container> chests, Mode mode) { InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting()) { return 0; } int num = 0; try { StackifyPlugin.DropDragItem(); Inventory inventory = ((Humanoid)localPlayer).GetInventory(); List<ItemData> list = Sort(inventory, Favorites.For(localPlayer), StackifyPlugin.MainRows(inventory, localPlayer), mode); num += list.Count; if (list.Count > 0) { ((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Ripple(instance.m_playerGrid, list)); } Container val = StackifyPlugin.CurrentContainer.Invoke(instance); foreach (Container chest in chests) { if ((Object)(object)chest == (Object)null) { continue; } ZNetView val2 = NearbyChests.NView.Invoke(chest); if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { continue; } if (StackifyPlugin.HasMuc || val2.IsOwner()) { List<ItemData> list2 = Sort(chest.GetInventory(), null, chest.GetInventory().GetHeight(), mode); num += list2.Count; if (list2.Count > 0 && (Object)(object)chest == (Object)(object)val) { ((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Ripple(ContainerGrid.Invoke(instance), list2)); } } else { val2.InvokeRPC("WireStackify_RequestSort3", new object[1] { (int)mode }); } } } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Sorting failed: " + ex)); } if (num > 0) { Feedback(null, null); } return num; } private static bool SortInventory(InventoryGui gui, Player player, Mode mode) { StackifyPlugin.DropDragItem(); Inventory inventory = ((Humanoid)player).GetInventory(); List<ItemData> list = Sort(inventory, Favorites.For(player), StackifyPlugin.MainRows(inventory, player), mode); Feedback(gui.m_playerGrid, list); return list.Count > 0; } private static bool SortChest(InventoryGui gui, Container chest, Mode mode) { StackifyPlugin.DropDragItem(); ZNetView val = NearbyChests.NView.Invoke(chest); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (StackifyPlugin.HasMuc || val.IsOwner()) { List<ItemData> list = Sort(chest.GetInventory(), null, chest.GetInventory().GetHeight(), mode); Feedback(ContainerGrid.Invoke(gui), list); return list.Count > 0; } val.InvokeRPC("WireStackify_RequestSort3", new object[1] { (int)mode }); Feedback(null, null); return true; } private static List<ItemData> Sort(Inventory inv, Favorites favorites, int rows, Mode mode) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) bool flag = favorites == null || StackifyPlugin.SortHotbar.Value; List<ItemData> list = new List<ItemData>(); HashSet<Vector2i> hashSet = new HashSet<Vector2i>(); foreach (ItemData allItem in inv.GetAllItems()) { if (allItem.m_gridPos.y < rows && (favorites == null || (!favorites.IsItemFavorited(allItem.m_shared) && (allItem.m_gridPos.y > 0 || flag) && !favorites.IsSlotFavorited(allItem.m_gridPos)))) { list.Add(allItem); } else { hashSet.Add(allItem.m_gridPos); } } Dictionary<ItemData, Vector2i> dictionary = new Dictionary<ItemData, Vector2i>(); foreach (ItemData item in list) { dictionary[item] = item.m_gridPos; } List<ItemData> list2 = new List<ItemData>(); if (StackifyPlugin.SortMergeStacks.Value) { MergeStacks(list, inv, list2); } if (mode == Mode.Weight) { list.Sort(WeightOrder); } else { list.Sort(TypeOrder); } List<Vector2i> list3 = Slots(inv, rows, flag, favorites, hashSet); for (int i = 0; i < list.Count && i < list3.Count; i++) { list[i].m_gridPos = list3[i]; } List<ItemData> list4 = new List<ItemData>(); foreach (ItemData item2 in list) { if (dictionary[item2] != item2.m_gridPos) { list4.Add(item2); } } list4.AddRange(list2); if (list4.Count > 0) { StackifyPlugin.Changed(inv); } return list4; } private static List<Vector2i> Slots(Inventory inv, int h, bool hotbar, Favorites favorites, HashSet<Vector2i> kept) { //IL_0023: 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_0060: 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) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) int width = inv.GetWidth(); int num = ((!hotbar) ? 1 : 0); List<Vector2i> list = new List<Vector2i>(); for (int num2 = h - 1; num2 >= num; num2--) { for (int i = 0; i < width; i++) { list.Add(new Vector2i(i, num2)); } } List<Vector2i> list2 = new List<Vector2i>(list.Count); foreach (Vector2i item in list) { if (!kept.Contains(item) && (favorites == null || !favorites.IsSlotFavorited(item))) { list2.Add(item); } } return list2; } private static int TypeGroup(ItemData item) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected I4, but got Unknown int num = (int)item.m_shared.m_itemType; if (num >= 0 && num < TypeToCategory.Length) { return TypeToCategory[num]; } return num; } private static int TypeOrder(ItemData a, ItemData b) { int num = TypeGroup(a).CompareTo(TypeGroup(b)); if (num == 0) { num = string.CompareOrdinal(a.m_shared.m_name, b.m_shared.m_name); } if (num == 0) { num = -a.m_quality.CompareTo(b.m_quality); } if (num == 0) { num = -a.m_stack.CompareTo(b.m_stack); } return num; } private static int WeightOrder(ItemData a, ItemData b) { int num = -a.GetWeight(-1).CompareTo(b.GetWeight(-1)); if (num == 0) { return TypeOrder(a, b); } return num; } private static void MergeStacks(List<ItemData> items, Inventory inv, List<ItemData> merged) { Dictionary<string, List<ItemData>> dictionary = new Dictionary<string, List<ItemData>>(); foreach (ItemData item in items) { if (item.m_stack < item.m_shared.m_maxStackSize && (item.m_customData == null || item.m_customData.Count <= 0)) { string key = item.m_shared.m_name + "|" + item.m_quality; if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<ItemData>()); } value.Add(item); } } foreach (List<ItemData> value2 in dictionary.Values) { if (value2.Count <= 1) { continue; } int num = 0; foreach (ItemData item2 in value2) { num += item2.m_stack; } int maxStackSize = value2[0].m_shared.m_maxStackSize; foreach (ItemData item3 in value2) { if (num <= 0) { item3.m_stack = 0; inv.RemoveItem(item3); items.Remove(item3); merged.Add(item3); } else { item3.m_stack = Math.Min(maxStackSize, num); num -= item3.m_stack; } } } } private static void Feedback(InventoryGrid grid, List<ItemData> moved) { InventoryGui instance = InventoryGui.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && (moved == null || moved.Count != 0)) { GameObject move = MoveSound(instance); ((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Actions.After(0.1f, delegate { StackifyEffects.PlayUi(move); })); if (moved != null) { ((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Ripple(grid, moved)); } } } private static GameObject MoveSound(InventoryGui gui) { if ((Object)(object)_moveSound != (Object)null || _moveSearched) { return _moveSound; } _moveSearched = true; if (gui.m_moveItemEffects != null) { EffectData[] effectPrefabs = gui.m_moveItemEffects.m_effectPrefabs; foreach (EffectData val in effectPrefabs) { if (val != null && (Object)(object)val.m_prefab != (Object)null && ((Object)val.m_prefab).name == "sfx_gui_moveitem") { return _moveSound = val.m_prefab; } } } ZSFX[] array = Resources.FindObjectsOfTypeAll<ZSFX>(); foreach (ZSFX val2 in array) { if ((Object)(object)val2 != (Object)null && ((Object)((Component)val2).gameObject).name == "sfx_gui_moveitem" && (Object)(object)((Component)val2).transform.parent == (Object)null) { return _moveSound = ((Component)val2).gameObject; } } StackifyPlugin.Log.LogWarning((object)"Couldn't find the game's item move sound."); return null; } private static IEnumerator Ripple(InventoryGrid grid, List<ItemData> moved) { int n = moved.Count; if (n == 0) { yield break; } float num = Mathf.Min(0.03f, 0.5f / (float)n); float[] at = new float[n]; for (int i = 1; i < n; i++) { at[i] = at[i - 1] + num * Random.Range(0.6f, 1.4f); } List<RectTransform> icons = new List<RectTransform>(n); List<InventoryElement> list = (((Object)(object)grid != (Object)null) ? Favorites.GridElements.Invoke(grid) : null); Inventory val = (((Object)(object)grid != (Object)null) ? Favorites.GridInventory.Invoke(grid) : null); int num2 = ((val != null) ? val.GetWidth() : 0); foreach (ItemData item2 in moved) { RectTransform item = null; if (list != null && val != null && item2.m_stack > 0) { int num3 = item2.m_gridPos.y * num2 + item2.m_gridPos.x; if (num3 >= 0 && num3 < list.Count && (Object)(object)list[num3] != (Object)null && (Object)(object)list[num3].m_icon != (Object)null) { item = ((Graphic)list[num3].m_icon).rectTransform; } } icons.Add(item); } for (float t = 0f; t < at[n - 1] + 0.22f; t += Time.unscaledDeltaTime) { for (int j = 0; j < n; j++) { if (!((Object)(object)icons[j] == (Object)null)) { float num4 = Mathf.Clamp01((t - at[j]) / 0.22f); float num5 = ((num4 <= 0f) ? 0.82f : (1f + Mathf.Sin(num4 * (float)Math.PI) * 0.12f * (1f - num4) - (1f - num4) * (1f - num4) * 0.18f)); ((Transform)icons[j]).localScale = new Vector3(num5, num5, 1f); } } yield return null; } foreach (RectTransform item3 in icons) { if ((Object)(object)item3 != (Object)null) { ((Transform)item3).localScale = Vector3.one; } } } } internal static class StackifyButtons { private sealed class PendingIcon { public Image Image; public Color Color; public bool Chest; } internal sealed class ClickHandler : MonoBehaviour, IPointerDownHandler, IEventSystemHandler { public bool Chest; public void OnPointerDown(PointerEventData e) { //IL_0041: 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_004f: Invalid comparison between Unknown and I4 //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 InventoryGui instance = InventoryGui.instance; if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)instance == (Object)null)) { ItemData val = Holding(instance); if (val != null) { Actions.DropOn(Chest, val, DragInventory.Invoke(instance)); } else { Actions.Do(Actions.ForButton(((int)e.button != 0) ? (((int)e.button == 1) ? 1 : (((int)e.button == 2) ? 2 : (-1))) : 0, Actions.Shift()), Chest); } } } } [HarmonyPatch(typeof(InventoryGui), "SetupDragItem")] private static class DragPatch { private static void Postfix(InventoryGui __instance) { UpdateOpen(__instance); RefreshHover(); } } [HarmonyPatch(typeof(InventoryGui), "Show")] private static class ShowPatch { private static void Postfix(InventoryGui __instance) { SetIcons(); UpdateCounts(); UpdateOpen(__instance); } } [HarmonyPatch(typeof(Inventory), "Changed")] private static class CountPatch { private static void Postfix(Inventory __instance) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)InventoryGui.instance == (Object)null)) { Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance); if (__instance == ((Humanoid)localPlayer).GetInventory() || ((Object)(object)val != (Object)null && __instance == val.GetInventory())) { UpdateCounts(); } } } } [HarmonyPatch(typeof(InventoryGui), "Awake")] private static class AwakePatch { private static void Postfix(InventoryGui __instance) { try { Build(__instance); } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Couldn't add the Stackify buttons: " + ex)); } } } internal sealed class TipRefresh : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { public bool Chest; public void OnPointerEnter(PointerEventData e) { Enter(Chest); } public void OnPointerExit(PointerEventData e) { Exit(Chest); } private void OnDisable() { Exit(Chest); } } private const string Name = "WireStackify"; private const string Topic = "Stackify"; private const string ChestTopic = "Stackify (Container)"; private static readonly List<PendingIcon> Pending = new List<PendingIcon>(); private static readonly List<KeyValuePair<Image, bool>> Icons = new List<KeyValuePair<Image, bool>>(); private static bool _openInv; private static bool _openChest; private static Sprite _pouch; private static Sprite _open; private static Sprite _closed; private static bool _openTried; private static bool _closedTried; private static bool _flashInv; private static bool _flashChest; private static int _flashToken; private static readonly List<KeyValuePair<UITooltip, bool>> Tips = new List<KeyValuePair<UITooltip, bool>>(); private static RectTransform _tooltipAnchor; private static readonly FieldRef<InventoryGui, InventoryGrid> ContainerGrid = AccessTools.FieldRefAccess<InventoryGui, InventoryGrid>("m_containerGrid"); internal static readonly FieldRef<InventoryGui, ItemData> DragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem"); private static readonly FieldRef<InventoryGui, Inventory> DragInventory = AccessTools.FieldRefAccess<InventoryGui, Inventory>("m_dragInventory"); private static bool _hovering; private static bool _hoverChest; private static string _previewChest = ""; private static string _previewInv = ""; private const float FlashTime = 0.7f; private static TMP_Text _invCount; private static TMP_Text _chestCount; private static readonly StackAction[] TipOrder = new StackAction[6] { StackAction.QuickStack, StackAction.Restock, StackAction.QuickStackAndRestock, StackAction.Sort, StackAction.SortByWeight, StackAction.Everything }; private static ItemData Holding(InventoryGui gui) { if ((Object)(object)gui == (Object)null || !StackifyPlugin.DropOnPouch.Value || (Object)(object)StackifyPlugin.DragGo.Invoke(gui) == (Object)null) { return null; } return DragItem.Invoke(gui); } internal static void Feedback(StackifyEffects.Kind kind, int count, bool chest) { if (count > 0) { ButtonFeel.Result(kind, count, chest); Flash(chest); } } internal static void Enter(bool chest) { _hovering = true; _hoverChest = chest; ButtonFeel.Hover(chest, on: true); RefreshHover(); } internal static void Exit(bool chest) { if (_hovering && _hoverChest == chest) { _hovering = false; ButtonFeel.Hover(chest, on: false); Favorites.ClearPreview(); } } internal static void RefreshHover() { if (!_hovering) { return; } Player localPlayer = Player.m_localPlayer; string text = ""; if ((Object)(object)localPlayer != (Object)null && StackifyPlugin.HoverPreview.Value) { try { ItemData val = Holding(InventoryGui.instance); int chests = 0; bool flag = val != null && _hoverChest; List<ItemData> list = (flag ? null : QuickStack.Preview(localPlayer, _hoverChest, out chests, val)); int containers = 0; float weight = 0f; List<ItemData> list2 = ((val == null) ? Restock.Preview(localPlayer, _hoverChest, out containers, out weight) : (flag ? Restock.PreviewOnly(localPlayer, StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance), val, out weight) : null)); float num = 0f; if (list != null) { foreach (ItemData item in list) { num += item.GetWeight(-1); } } Favorites.ShowPreview(list, list2); if (flag && list2.Count > 0) { containers = 1; } string text2 = Favorites.YellowHex(); string text3 = Favorites.BlueHex(); text = "\n"; if (list != null) { text = text + "\n" + ((list.Count == 0) ? "Quick stack: nothing" : ("Quick stack: <color=#" + text2 + ">" + Stacks(list.Count) + "</color> into " + Containers(chests) + Weight(0f - num, text2))); } if (list2 != null) { text = text + "\n" + ((list2.Count == 0) ? "Restock: nothing" : ("Restock: <color=#" + text3 + ">" + Stacks(list2.Count) + "</color> from " + Containers(containers) + Weight(weight, text3))); } } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Stackify preview failed: " + ex)); } } else { Favorites.ClearPreview(); } if (_hoverChest) { _previewChest = text; } else { _previewInv = text; } UpdateTips(_hoverChest ? 1 : 0); } private static string Stacks(int n) { if (n != 1) { return n + " stacks"; } return "1 stack"; } private static string Weight(float w, string hex) { if (Mathf.Abs(w) < 0.05f) { return ""; } return "\n<color=#" + hex + ">" + ((w > 0f) ? "+" : "-") + Mathf.Abs(w).ToString("0.#", CultureInfo.InvariantCulture) + "</color> weight"; } private static string Containers(int n) { return "<color=orange>" + n + "</color>" + ((n == 1) ? " container" : " containers"); } private static void UpdateOpen(InventoryGui gui) { bool flag = false; bool flag2 = false; Player localPlayer = Player.m_localPlayer; ItemData val = Holding(gui); if (val != null && (Object)(object)localPlayer != (Object)null) { try { flag = QuickStack.Preview(localPlayer, onlyThisChest: false, out var _, val).Count > 0; flag2 = Restock.PreviewOnly(localPlayer, StackifyPlugin.CurrentContainer.Invoke(gui), val, out var _).Count > 0; } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Stackify open pouch: " + ex.Message)); } } if (flag != _openInv) { _openInv = flag; Refresh(chest: false); } if (flag2 != _openChest) { _openChest = flag2; Refresh(chest: true); } } internal static void Flash(bool chest) { if (chest) { _flashChest = true; } else { _flashInv = true; } int token = ++_flashToken; Refresh(chest); ((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Actions.After(0.7f, delegate { if (token == _flashToken) { _flashInv = (_flashChest = false); Refresh(chest: false); Refresh(chest: true); } })); } private static void Refresh(bool chest) { if ((Object)(object)_pouch == (Object)null) { return; } bool flag = ((!chest) ? (_openInv || _flashInv) : (_openChest || _flashChest)); Sprite val = (flag ? OpenPouch() : Closed()); if ((Object)(object)val == (Object)null) { val = Closed(); } for (int num = Icons.Count - 1; num >= 0; num--) { Image key = Icons[num].Key; if ((Object)(object)key == (Object)null) { Icons.RemoveAt(num); } else if (Icons[num].Value == chest && !((Object)(object)key.sprite == (Object)(object)val)) { key.sprite = val; ButtonFeel.Pop(chest, flag); } } } private static Sprite Closed() { if ((Object)(object)_closed != (Object)null || _closedTried || (Object)(object)_pouch == (Object)null) { if (!((Object)(object)_closed != (Object)null)) { return _pouch; } return _closed; } _closedTried = true; _closed = LoadSprite("pouch_closed"); if (!((Object)(object)_closed != (Object)null)) { return _pouch; } return _closed; } private static Sprite OpenPouch() { if ((Object)(object)_open != (Object)null || _openTried || (Object)(object)_pouch == (Object)null) { return _open; } _openTried = true; _open = LoadSprite("pouch_open"); return _open; } private static Sprite LoadSprite(string name) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WiresStackify.Assets." + name + ".png"); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); MethodInfo method = typeof(ImageConversion).GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }); if (method == null || !(bool)method.Invoke(null, new object[2] { val, array })) { return null; } ((Texture)val).wrapMode = (TextureWrapMode)1; if ((Object)(object)_pouch.texture != (Object)null) { ((Texture)val).filterMode = ((Texture)_pouch.texture).filterMode; } Rect rect = _pouch.rect; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(_pouch.pivot.x / ((Rect)(ref rect)).width, _pouch.pivot.y / ((Rect)(ref rect)).height); Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), val2, _pouch.pixelsPerUnit * (float)((Texture)val).width / ((Rect)(ref rect)).width); ((Object)obj).name = "WireStackify_" + name; return obj; } catch (Exception ex) { StackifyPlugin.Log.LogWarning((object)("Couldn't load " + name + ": " + ex.Message)); return null; } } private static void CursorHand(GameObject go) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!(assembly.GetName().Name != "WiresNativeCursorSupport")) { Type type = assembly.GetType("WiresNativeCursorSupport.NativeCursorApi"); MethodInfo methodInfo = ((type != null) ? type.GetMethod("SetHand", BindingFlags.Static | BindingFlags.Public) : null); if (methodInfo != null) { methodInfo.Invoke(null, new object[1] { go }); } break; } } } catch (Exception ex) { StackifyPlugin.Log.LogDebug((object)("Native Cursor Support hand: " + ex.Message)); } } internal static void UpdateCounts() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } if ((Object)(object)_invCount != (Object)null) { Inventory inventory = ((Humanoid)localPlayer).GetInventory(); int num = StackifyPlugin.MainRows(inventory, localPlayer); int num2 = 0; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_gridPos.y < num) { num2++; } } SetCount(_invCount, num2); } if ((Object)(object)_chestCount != (Object)null && (Object)(object)InventoryGui.instance != (Object)null) { Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance); if ((Object)(object)val != (Object)null) { SetCount(_chestCount, val.GetInventory().GetAllItems().Count); } } } private static void SetCount(TMP_Text t, int n) { string text = n.ToString(); if (t.text != text) { t.text = text; } } private static void SetIcons() { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //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_005b: 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) if (Pending.Count == 0) { return; } if ((Object)(object)_pouch == (Object)null && (Object)(object)Minimap.instance != (Object)null && Minimap.instance.m_locationIcons != null) { foreach (LocationSpriteData locationIcon in Minimap.instance.m_locationIcons) { if ((Object)(object)locationIcon.m_icon != (Object)null && ((Object)locationIcon.m_icon).name == "mapicon_trader") { _pouch = locationIcon.m_icon; break; } } } for (int num = Pending.Count - 1; num >= 0; num--) { PendingIcon pendingIcon = Pending[num]; Sprite val = Closed(); if ((Object)(object)pendingIcon.Image == (Object)null) { Pending.RemoveAt(num); } else if (!((Object)(object)val == (Object)null)) { pendingIcon.Image.sprite = val; Icons.Add(new KeyValuePair<Image, bool>(pendingIcon.Image, pendingIcon.Chest)); ((Graphic)pendingIcon.Image).color = pendingIcon.Color; RectTransform rectTransform = ((Graphic)pendingIcon.Image).rectTransform; rectTransform.sizeDelta *= 1.1875f; ButtonFeel componentInParent = ((Component)pendingIcon.Image).GetComponentInParent<ButtonFeel>(); if ((Object)(object)componentInParent != (Object)null) { componentInParent.IconReady(); } Pending.RemoveAt(num); } } } private static void Build(InventoryGui gui) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)(((Object)(object)gui.m_armor != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); RectTransform val2 = (RectTransform)(((Object)(object)gui.m_weight != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); RectTransform val3 = (RectTransform)(((Object)(object)gui.m_containerWeight != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { InventoryGrid val4 = ContainerGrid.Invoke(gui); _tooltipAnchor = (((Object)(object)val4 != (Object)null) ? val4.m_tooltipAnchor : null); UITooltip template = (((Object)(object)val4 != (Object)null && (Object)(object)val4.m_elementPrefab != (Object)null) ? val4.m_elementPrefab.GetComponent<UITooltip>() : null); WeightShake.Add(val2, chest: false); if ((Object)(object)val3 != (Object)null) { WeightShake.Add(val3, chest: true); } RectTransform val5 = Clone(val, gui.m_armor, chest: false, template); ((Transform)val5).localPosition = (((Transform)val).localPosition + ((Transform)val2).localPosition) * 0.5f; if ((Object)(object)val3 != (Object)null) { ((Transform)Clone(val3, gui.m_containerWeight, chest: true, template)).localPosition = ((Transform)val3).localPosition + (((Transform)val5).localPosition - ((Transform)val2).localPosition); } UpdateTips(); ((BaseUnityPlugin)StackifyPlugin.Instance).Config.SettingChanged += delegate { UpdateTips(); }; SetIcons(); } } private static RectTransform Clone(RectTransform block, TMP_Text valueText, bool chest, UITooltip template) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(((Component)block).gameObject, ((Transform)block).parent, false); ((Object)val).name = "WireStackify" + (chest ? "Chest" : "Inventory"); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetSiblingIndex(((Transform)block).GetSiblingIndex() + 1); string text = RelativePath(valueText.transform, (Transform)(object)block); TMP_Text val3 = null; TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val4 in componentsInChildren) { if (RelativePath(val4.transform, (Transform)(object)val2) == text) { val4.text = ""; val3 = val4; if (chest) { _chestCount = val4; } else { _invCount = val4; } } ((Graphic)val4).raycastTarget = false; } Image val5 = null; Image[] componentsInChildren2 = val.GetComponentsInChildren<Image>(true); foreach (Image val6 in componentsInChildren2) { if (((Object)val6).name.IndexOf("icon", StringComparison.OrdinalIgnoreCase) >= 0) { val6.sprite = null; Pending.Add(new PendingIcon { Image = val6, Color = ((Graphic)val6).color, Chest = chest }); ((Graphic)val6).color = new Color(1f, 1f, 1f, 0f); val6.preserveAspect = true; ((Graphic)val6).raycastTarget = false; val5 = val6; } else { ((Graphic)val6).raycastTarget = true; } } GameObject val7 = new GameObject("HitArea", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val8 = (RectTransform)val7.transform; ((Transform)val8).SetParent((Transform)(object)val2, false); ((Transform)val8).SetAsLastSibling(); val8.anchorMin = Vector2.zero; val8.anchorMax = Vector2.one; Vector2 offsetMin = (val8.offsetMax = Vector2.zero); val8.offsetMin = offsetMin; Image component = val7.GetComponent<Image>(); ((Graphic)component).color = new Color(0f, 0f, 0f, 0f); ((Graphic)component).raycastTarget = true; UITooltip[] componentsInChildren3 = val.GetComponentsInChildren<UITooltip>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } val.AddComponent<TipRefresh>().Chest = chest; UITooltip val9 = val.AddComponent<UITooltip>(); if ((Object)(object)template != (Object)null) { FieldInfo[] fields = typeof(UITooltip).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsInitOnly) { fieldInfo.SetValue(val9, fieldInfo.GetValue(template)); } } } val9.m_gamepadFocusObject = null; Tips.Add(new KeyValuePair<UITooltip, bool>(val9, chest)); ButtonFeel buttonFeel = val.AddComponent<ButtonFeel>(); val.AddComponent<FeelReset>().Feel = buttonFeel; buttonFeel.Setup(((Object)(object)val5 != (Object)null) ? ((Graphic)val5).rectTransform : null, ((Object)(object)val3 != (Object)null) ? val3.rectTransform : null, val5, chest); val.AddComponent<ClickHandler>().Chest = chest; CursorHand(val); return val2; } private static string NearbyLine() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return ""; } if (!NearbyChests.AreaAllowed()) { return "\nNearby containers: only with Multi User Chest in multiplayer"; } float num = Mathf.Max(StackifyPlugin.QuickStackRange.Value, StackifyPlugin.RestockRange.Value); if (num <= 0f) { return ""; } bool singleplayer = NearbyChests.IsTrueSingleplayer(); long playerID = localPlayer.GetPlayerID(); int num2 = 0; foreach (Container item in NearbyChests.InRange(((Component)localPlayer).transform.position, num)) { if (NearbyChests.CanUse(item, playerID, singleplayer)) { num2++; } } return "\nContainers in range: <color=orange>" + num2 + "</color>"; } private static void UpdateTips(int which = -1) { //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<string, StackAction>> list = Bindings(); foreach (KeyValuePair<UITooltip, bool> tip in Tips) { if ((Object)(object)tip.Key == (Object)null || (which >= 0 && tip.Value != (which == 1))) { continue; } bool value = tip.Value; StringBuilder stringBuilder = new StringBuilder(); StackAction[] tipOrder = TipOrder; foreach (StackAction stackAction in tipOrder) { string text = null; foreach (KeyValuePair<string, StackAction> item in list) { if (item.Value == stackAction) { text = ((text == null) ? item.Key : (text + " or " + item.Key)); } } if (text != null) { stringBuilder.Append("\n<color=orange>").Append(text).Append("</color>: ") .Append(Actions.Describe(stackAction)); } } if (StackifyPlugin.DropOnPouch.Value) { stringBuilder.Append(value ? "\n<color=orange>Click while holding an item</color>: restock held item type" : "\n<color=orange>Click while holding an item</color>: quick stack held item type"); } stringBuilder.Append("\n").Append(value ? "\nOnly works in this container." : NearbyLine()); stringBuilder.Append(value ? _previewChest : _previewInv); tip.Key.Set(value ? "Stackify (Container)" : "Stackify", stringBuilder.ToString().TrimStart(new char[1] { '\n' }), _tooltipAnchor, default(Vector2)); } } private static List<KeyValuePair<string, StackAction>> Bindings() { List<KeyValuePair<string, StackAction>> list = new List<KeyValuePair<string, StackAction>> { new KeyValuePair<string, StackAction>("Left click", StackifyPlugin.LeftClick.Value), new KeyValuePair<string, StackAction>("Right click", StackifyPlugin.RightClick.Value), new KeyValuePair<string, StackAction>("Middle click", StackifyPlugin.MiddleClick.Value) }; StackAction value = StackifyPlugin.ShiftLeftClick.Value; StackAction value2 = StackifyPlugin.ShiftRightClick.Value; StackAction value3 = StackifyPlugin.ShiftMiddleClick.Value; if (value == value2 && value2 == value3) { list.Add(new KeyValuePair<string, StackAction>("Shift + click", value)); } else { list.Add(new KeyValuePair<string, StackAction>("Shift + left click", value)); list.Add(new KeyValuePair<string, StackAction>("Shift + right click", value2)); list.Add(new KeyValuePair<string, StackAction>("Shift + middle click", value3)); } return list; } private static string RelativePath(Transform t, Transform root) { string text = ""; while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)root) { text = ((Object)t).name + "/" + text; t = t.parent; } return text; } } internal sealed class ButtonFeel : MonoBehaviour { private struct Spring { public float X; public float V; public bool Settled { get { if (Mathf.Abs(X) < 0.002f) { return Mathf.Abs(V) < 0.02f; } return false; } } public void Step(float dt, float stiffness, float damping) { V += ((0f - X) * stiffness - V * damping) * dt; X += V * dt; } } private static readonly List<ButtonFeel> All = new List<ButtonFeel>(); private RectTransform _icon; private RectTransform _label; private Image _iconImage; private TMP_Text _labelText; private bool _chest; private Vector3 _iconPos; private Vector3 _iconScale; private Color _iconColor; private Color _labelColor; private bool _hasBase; private bool _iconColorKnown; private Spring _grow; private Spring _hop; private Spring