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 StorageTerminal v1.0.1
plugins/StorageTerminal.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem.UI; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = "")] [assembly: AssemblyCompany("Tremendouz")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Tremendouz")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("Storage Terminal")] [assembly: AssemblyTitle("StorageTerminal")] [assembly: AssemblyVersion("1.0.1.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 StorageTerminal { internal static class Access { public static readonly FieldRef<Container, Inventory> ContainerInventory = AccessTools.FieldRefAccess<Container, Inventory>("m_inventory"); public static readonly FieldRef<Inventory, List<ItemData>> Items = AccessTools.FieldRefAccess<Inventory, List<ItemData>>("m_inventory"); public static readonly FieldRef<InventoryGui, Container> CurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); public static readonly FieldRef<InventoryGui, ItemData> DragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem"); public static readonly FieldRef<InventoryGui, InventoryGrid> ContainerGrid = AccessTools.FieldRefAccess<InventoryGui, InventoryGrid>("m_containerGrid"); private static readonly Func<Container, long, bool> checkAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null), (object)null, true); private static readonly Func<Inventory, ItemData, int, int, int, bool, bool> addItemAt = AccessTools.MethodDelegate<Func<Inventory, ItemData, int, int, int, bool, bool>>(AccessTools.Method(typeof(Inventory), "AddItem", new Type[5] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) }, (Type[])null), (object)null, true); private static readonly Func<Inventory, bool, Vector2i> findEmptySlot = AccessTools.MethodDelegate<Func<Inventory, bool, Vector2i>>(AccessTools.Method(typeof(Inventory), "FindEmptySlot", new Type[1] { typeof(bool) }, (Type[])null), (object)null, true); private static readonly Action<Inventory, bool, bool> changed = AccessTools.MethodDelegate<Action<Inventory, bool, bool>>(AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null), (object)null, true); private static readonly Func<InventoryGrid, int, int, int, InventoryElement> getElement = AccessTools.MethodDelegate<Func<InventoryGrid, int, int, int, InventoryElement>>(AccessTools.Method(typeof(InventoryGrid), "GetElement", new Type[3] { typeof(int), typeof(int), typeof(int) }, (Type[])null), (object)null, true); public static bool CheckAccess(Container c, long playerId) { return checkAccess(c, playerId); } public static InventoryElement GetElement(InventoryGrid grid, Vector2i pos, int width) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return getElement(grid, pos.x, pos.y, width); } public static bool AddItemAt(Inventory inv, ItemData item, int amount, Vector2i pos) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) return addItemAt(inv, item, amount, pos.x, pos.y, arg6: false); } public static Vector2i FindEmptySlot(Inventory inv) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return findEmptySlot(inv, arg2: false); } public static void Changed(Inventory inv) { changed(inv, arg2: true, arg3: false); } } internal static class ChestBulk { private static bool _running; public static void TryRun() { if (_running || !Plugin.EnableAllChests.Value || (Object)(object)ZNetScene.instance == (Object)null || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } _running = true; try { Run(out var enabled, out var skipped); Plugin.Log.LogInfo((object)$"EnableAllChests: enabled insertion/withdraw on {enabled} player-built chests, skipped {skipped} world chests."); ((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$st_enabled_all", new string[1] { enabled.ToString() }), 0, (Sprite)null, false); } finally { Plugin.EnableAllChests.Value = false; _running = false; } } private static void Run(out int enabled, out int skipped) { enabled = 0; skipped = 0; List<ZDO> list = new List<ZDO>(); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<Piece>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<TerminalMarker>())) { continue; } Container component = prefab.GetComponent<Container>(); if (!Object.op_Implicit((Object)(object)component) || Object.op_Implicit((Object)(object)component.m_wagon)) { continue; } list.Clear(); int num = 0; while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(((Object)prefab).name, list, ref num)) { } foreach (ZDO item in list) { if (item.GetLong(ZDOVars.s_creator, 0L) == 0L) { skipped++; continue; } item.Set("storageterminal_withdraw", true); item.Set("storageterminal_insert", true); enabled++; } } } } internal static class FilterPanel { private const int Columns = 4; private const float RowHeight = 30f; private const float Padding = 12f; private static GameObject _root; private static Toggle _all; private static readonly Dictionary<ItemFilter, Toggle> _toggles = new Dictionary<ItemFilter, Toggle>(); private static bool _updating; public static bool IsOpen { get { if (Object.op_Implicit((Object)(object)_root)) { return _root.activeSelf; } return false; } } public static void Toggle() { if (Object.op_Implicit((Object)(object)_root)) { _root.SetActive(!_root.activeSelf); } } public static void Hide() { if (Object.op_Implicit((Object)(object)_root) && _root.activeSelf) { _root.SetActive(false); } } public static void Create(Transform parent, float width, float top) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) _toggles.Clear(); float num = (float)((ItemFilter.All.Count + 1 + 4 - 1) / 4) * 30f + 24f; _root = GUIManager.Instance.CreateWoodpanel(parent, Vector2.zero, Vector2.zero, Vector2.zero, width, num, false); ((Object)_root).name = "StorageTerminal_Filters"; RectTransform val = (RectTransform)_root.transform; val.pivot = new Vector2(0f, 1f); val.anchoredPosition = new Vector2(0f, top); float columnWidth = (width - 24f) / 4f; _all = AddCell(0, "All", columnWidth, num); ((UnityEvent<bool>)(object)_all.onValueChanged).AddListener((UnityAction<bool>)OnAllChanged); int num2 = 1; foreach (ItemFilter item in ItemFilter.All) { Toggle val2 = AddCell(num2++, item.Label, columnWidth, num); ItemFilter captured = item; ((UnityEvent<bool>)(object)val2.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v) { OnFilterChanged(captured, v); }); _toggles[item] = val2; } _root.SetActive(false); } public static void Sync(List<ItemFilter> selected) { if (!Object.op_Implicit((Object)(object)_root)) { return; } _updating = true; _all.isOn = selected.Count == 0; foreach (KeyValuePair<ItemFilter, Toggle> toggle in _toggles) { toggle.Value.isOn = selected.Contains(toggle.Key); } _updating = false; } private static Toggle AddCell(int index, string label, float columnWidth, float panelHeight) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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) GUIManager instance = GUIManager.Instance; int num = index % 4; int num2 = index / 4; float num3 = 12f + (float)num * columnWidth; float num4 = panelHeight - 12f - (float)num2 * 30f - 15f; GameObject obj = instance.CreateToggle(_root.transform, 24f, 24f); RectTransform val = (RectTransform)obj.transform; Vector2 anchorMin = (val.anchorMax = Vector2.zero); val.anchorMin = anchorMin; val.anchoredPosition = new Vector2(num3 + 12f, num4); Text component = instance.CreateText(label, _root.transform, Vector2.zero, Vector2.zero, new Vector2(num3 + 30f + (columnWidth - 34f) / 2f, num4), instance.AveriaSerifBold, 14, instance.ValheimBeige, true, Color.black, columnWidth - 34f, 30f, false).GetComponent<Text>(); component.alignment = (TextAnchor)3; component.horizontalOverflow = (HorizontalWrapMode)1; return obj.GetComponent<Toggle>(); } private static void OnAllChanged(bool on) { if (_updating) { return; } _updating = true; if (on) { foreach (Toggle value in _toggles.Values) { value.isOn = false; } } else if (!_toggles.Values.Any((Toggle t) => t.isOn)) { _all.isOn = true; } _updating = false; Apply(); } private static void OnFilterChanged(ItemFilter filter, bool on) { if (!_updating) { _updating = true; if (on) { _all.isOn = false; } else if (!_toggles.Values.Any((Toggle t) => t.isOn)) { _all.isOn = true; } _updating = false; Apply(); } } private static void Apply() { List<ItemFilter> filters = (_all.isOn ? new List<ItemFilter>() : (from kv in _toggles where kv.Value.isOn select kv.Key).ToList()); FilterSettings.Save(filters); TerminalSession.Current?.SetFilters(filters); } } internal static class FilterSettings { public static List<ItemFilter> Load() { HashSet<string> ids = new HashSet<string>(from s in (Plugin.Filters.Value ?? "").Split(',') select s.Trim()); return ItemFilter.All.Where((ItemFilter f) => ids.Contains(f.Id)).ToList(); } public static void Save(IEnumerable<ItemFilter> filters) { Plugin.Filters.Value = string.Join(",", filters.Select((ItemFilter f) => f.Id)); } } internal static class ItemCategory { public const int Weapons = 10; public const int Ammo = 20; public const int Armor = 30; public const int Tools = 40; public const int Food = 50; public const int Fish = 55; public const int Trophies = 90; public const int MaterialBase = 100; public const int Wood = 100; public const int Hides = 101; public const int Ores = 102; public const int Metals = 103; public const int Stone = 104; public const int Valuables = 105; public const int Plants = 106; public const int CreatureDrops = 107; public const int OtherMaterials = 108; public static int Get(ItemData item) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected I4, but got Unknown ItemType itemType = item.m_shared.m_itemType; switch (itemType - 2) { case 1: case 2: case 3: case 12: case 13: case 20: return 10; case 7: case 21: return 20; case 4: case 5: case 9: case 10: case 15: case 16: case 22: return 30; case 17: return 40; case 0: return 50; case 19: return 55; case 11: return 90; default: return MaterialGroup(item); } } private static int MaterialGroup(ItemData item) { string id = ((Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : "") + " " + item.m_shared.m_name).ToLowerInvariant(); if (Has(id, "wood", "roundlog", "bark")) { return 100; } if (Has(id, "leather", "hide", "pelt", "scale", "chitin", "carapace")) { return 101; } if (Has(id, "ore", "scrap")) { return 102; } if (item.m_shared.m_value > 0) { return 105; } if (IsMetal(id)) { return 103; } if (Has(id, "stone", "flint", "obsidian", "grausten", "marble", "crystal", "coal", "tar", "resin")) { return 104; } if (Has(id, "seed", "flax", "barley", "linen", "thistle", "dandelion", "mushroom", "carrot", "turnip", "onion", "berr", "sap", "fiddlehead", "jotunpuff", "magecap", "vineberry")) { return 106; } if (Has(id, "feather", "bone", "tooth", "fang", "claw", "horn", "antler", "eye", "heart", "entrails", "ichor", "bile", "ooze", "guck", "wisp", "core", "head")) { return 107; } return 108; } private static bool IsMetal(string id) { if (!Has(id, "copper", "bronze", "iron", "silver", "blackmetal", "flametal", "nails")) { return id.StartsWith("tin "); } return true; } private static bool Has(string id, params string[] parts) { foreach (string value in parts) { if (id.Contains(value)) { return true; } } return false; } } internal sealed class ItemFilter { public readonly string Id; public readonly string Label; private readonly int _min; private readonly int _max; public static readonly IReadOnlyList<ItemFilter> All = new ItemFilter[17] { new ItemFilter("materials", "Materials (all)", 100, int.MaxValue), new ItemFilter("wood", "Wood", 100), new ItemFilter("stone", "Stone & minerals", 104), new ItemFilter("ores", "Ores", 102), new ItemFilter("metals", "Metals", 103), new ItemFilter("hides", "Hides & leather", 101), new ItemFilter("plants", "Plants & seeds", 106), new ItemFilter("drops", "Creature drops", 107), new ItemFilter("valuables", "Valuables", 105), new ItemFilter("food", "Food & potions", 50), new ItemFilter("ammo", "Ammo", 20), new ItemFilter("weapons", "Weapons", 10), new ItemFilter("armor", "Armor", 30), new ItemFilter("tools", "Tools", 40), new ItemFilter("fish", "Fish", 55), new ItemFilter("trophies", "Trophies", 90), new ItemFilter("othermaterials", "Other materials", 108) }; private ItemFilter(string id, string label, int category) : this(id, label, category, category) { } private ItemFilter(string id, string label, int min, int max) { Id = id; Label = label; _min = min; _max = max; } public bool Matches(int category) { if (category >= _min) { return category <= _max; } return false; } } internal static class LinkedChests { private static readonly List<Piece> pieces = new List<Piece>(); public static List<Container> Find(Vector3 center, Func<Container, bool> flag) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); if ((Object)(object)Game.instance == (Object)null) { return list; } long playerID = Game.instance.GetPlayerProfile().GetPlayerID(); pieces.Clear(); Piece.GetAllPiecesInRadius(center, Plugin.Range.Value, pieces); foreach (Piece piece in pieces) { Container val = (Object.op_Implicit((Object)(object)piece) ? ((Component)piece).GetComponent<Container>() : null); if (IsLinkable(val) && Access.CheckAccess(val, playerID) && flag(val)) { list.Add(val); } } pieces.Clear(); list.Sort(delegate(Container a, Container b) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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) Vector3 val2 = ((Component)a).transform.position - center; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; val2 = ((Component)b).transform.position - center; return sqrMagnitude.CompareTo(((Vector3)(ref val2)).sqrMagnitude); }); return list; } public static bool IsLinkable(Container c) { if (!Object.op_Implicit((Object)(object)c) || Object.op_Implicit((Object)(object)c.m_wagon) || TerminalPiece.IsTerminal(c)) { return false; } if (Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent<Ship>())) { return false; } ZNetView component = ((Component)c).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { return Access.ContainerInventory.Invoke(c) != null; } return false; } } internal static class LinkFlags { public const string TakeKey = "storageterminal_withdraw"; public const string InsertKey = "storageterminal_insert"; public static bool CanTake(Container c) { return Get(c, "storageterminal_withdraw"); } public static bool CanInsert(Container c) { return Get(c, "storageterminal_insert"); } public static void SetTake(Container c, bool value) { Set(c, "storageterminal_withdraw", value); } public static void SetInsert(Container c, bool value) { Set(c, "storageterminal_insert", value); } private static bool Get(Container c, string key) { ZNetView val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<ZNetView>() : null); if (Object.op_Implicit((Object)(object)val) && val.IsValid()) { return val.GetZDO().GetBool(key, false); } return false; } private static void Set(Container c, string key, bool value) { ZNetView val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<ZNetView>() : null); if (Object.op_Implicit((Object)(object)val) && val.IsValid()) { if (!val.IsOwner()) { val.ClaimOwnership(); } val.GetZDO().Set(key, value); } } } [HarmonyPatch(typeof(InventoryGui), "Show")] internal static class InventoryGuiShowPatch { private static void Prefix(Container container) { try { TerminalSession current = TerminalSession.Current; if (current != null && (Object)(object)current.Terminal != (Object)(object)container) { current.Close(); } if (Object.op_Implicit((Object)(object)container) && TerminalPiece.IsTerminal(container) && TerminalSession.Current == null) { TerminalSession.Open(container); TerminalUi.OnTerminalOpened(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Opening the terminal failed: {arg}"); } } } [HarmonyPatch(typeof(InventoryGui), "CloseContainer")] internal static class InventoryGuiCloseContainerPatch { private static void Prefix() { TerminalSession.Current?.Close(); TerminalUi.ReleaseInput(); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] internal static class InventoryGuiHidePatch { private static void Prefix() { TerminalSession.Current?.Close(); TerminalUi.ReleaseInput(); } } [HarmonyPatch(typeof(InventoryGui), "Update")] internal static class InventoryGuiUpdatePatch { private static bool _errorLogged; private static void Postfix(InventoryGui __instance) { try { TerminalSession.Current?.Tick(__instance); TerminalUi.Update(__instance); } catch (Exception arg) { if (!_errorLogged) { Plugin.Log.LogError((object)$"InventoryGui.Update: {arg}"); } _errorLogged = true; } } } [HarmonyPatch(typeof(InventoryGrid), "DropItem")] internal static class InventoryGridDropItemPatch { private static bool Prefix(InventoryGrid __instance, Inventory fromInventory, ItemData item, int amount, Vector2i pos, ref bool __result) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) TerminalSession current = TerminalSession.Current; if (current == null) { return true; } Inventory inventory = __instance.GetInventory(); bool flag = TerminalSession.IsView(inventory); bool flag2 = TerminalSession.IsView(fromInventory); if (!flag && !flag2) { return true; } if (flag && flag2) { __result = false; } else if (flag) { __result = current.StoreFrom(fromInventory, item, amount) > 0; } else { __result = current.TakeTo(item, amount, inventory, pos) > 0; } return false; } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData) })] internal static class InventoryQuickMovePatch { private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item) { TerminalSession current = TerminalSession.Current; if (current == null || item == null) { return true; } bool flag = TerminalSession.IsView(__instance); bool flag2 = TerminalSession.IsView(fromInventory); if (flag == flag2) { return !flag; } if (flag) { current.StoreFrom(fromInventory, item, item.m_stack); } else { current.TakeTo(item, item.m_stack, __instance, null); } return false; } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int) })] internal static class InventoryMoveToPosPatch { private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item, int amount, int x, int y, ref bool __result) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) TerminalSession current = TerminalSession.Current; if (current == null || item == null) { return true; } bool flag = TerminalSession.IsView(__instance); bool flag2 = TerminalSession.IsView(fromInventory); if (!flag && !flag2) { return true; } if (flag && flag2) { __result = false; } else if (flag) { __result = current.StoreFrom(fromInventory, item, amount) > 0; } else { __result = current.TakeTo(item, amount, __instance, (Vector2i?)new Vector2i(x, y)) > 0; } return false; } } [HarmonyPatch(typeof(Inventory), "StackAll")] internal static class InventoryStackAllPatch { private static bool Prefix(Inventory __instance, Inventory fromInventory, ref int __result) { if (!TerminalSession.IsView(__instance)) { return true; } __result = TerminalSession.Current.StackAllFrom(fromInventory); return false; } } [HarmonyPatch(typeof(InventoryGui), "SetupDragItem")] internal static class InventoryGuiSetupDragPatch { private static void Prefix(ItemData item, Inventory inventory, ref int amount) { if (item != null && TerminalSession.IsView(inventory)) { amount = Math.Min(amount, Math.Max(1, item.m_shared.m_maxStackSize)); } } } [HarmonyPatch(typeof(Humanoid), "DropItem")] internal static class HumanoidDropItemPatch { private static void Prefix(Inventory inventory, ItemData item, ref int amount) { if (item != null && TerminalSession.IsView(inventory)) { amount = Math.Min(amount, Math.Max(1, item.m_shared.m_maxStackSize)); } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class InventoryGridUpdateGuiPatch { private static void Postfix(InventoryGrid __instance) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = __instance.GetInventory(); if (!TerminalSession.IsView(inventory)) { return; } int width = inventory.GetWidth(); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_shared.m_maxStackSize > 1) { InventoryElement element = Access.GetElement(__instance, allItem.m_gridPos, width); if ((Object)(object)element != (Object)null && Object.op_Implicit((Object)(object)element.m_amount)) { element.m_amount.text = Format(allItem.m_stack); } } } } private static string Format(int n) { if (n >= 10000) { if (n >= 1000000) { return n / 1000000 + "M"; } return n / 1000 + "k"; } return n.ToString(); } } [HarmonyPatch(typeof(Container), "Save")] internal static class ContainerSavePatch { private static bool Prefix(Container __instance) { return !TerminalPiece.IsTerminal(__instance); } } [HarmonyPatch(typeof(Container), "Load")] internal static class ContainerLoadPatch { private static bool Prefix(Container __instance) { return !TerminalPiece.IsTerminal(__instance); } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ContainerHoverPatch { private static void Postfix(Container __instance, ref string __result) { if (TerminalPiece.IsTerminal(__instance) && Localization.instance != null) { __result = __result.Replace(Localization.instance.Localize(" ( $piece_container_empty )"), ""); } } } [HarmonyPatch(typeof(Piece), "SetCreator")] internal static class PieceSetCreatorPatch { private static void Postfix(Piece __instance) { Container component = ((Component)__instance).GetComponent<Container>(); if (LinkedChests.IsLinkable(component)) { if (Plugin.DefaultTake.Value) { LinkFlags.SetTake(component, value: true); } if (Plugin.DefaultInsert.Value) { LinkFlags.SetInsert(component, value: true); } } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerOnSpawnedPatch { private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { ChestBulk.TryRun(); } } } [BepInPlugin("tremendouz.storageterminal", "Storage Terminal by Tremendouz", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal sealed class Plugin : BaseUnityPlugin { public const string Guid = "tremendouz.storageterminal"; public const string ModName = "Storage Terminal by Tremendouz"; public const string Version = "1.0.1"; internal static ManualLogSource Log; internal static ConfigEntry<float> Range; internal static ConfigEntry<string> Recipe; internal static ConfigEntry<bool> DefaultTake; internal static ConfigEntry<bool> DefaultInsert; internal static ConfigEntry<bool> EnableAllChests; internal static ConfigEntry<SortMode> Sort; internal static ConfigEntry<string> Filters; internal static ConfigEntry<bool> IgnoreWeight; private Harmony _harmony; private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 20f, new ConfigDescription("Terminal range in meters — chests within this radius are linked.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 100f), Array.Empty<object>())); Recipe = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Recipe", "FineWood:10,Iron:2", "Terminal build cost: Prefab:Amount, comma separated. Takes effect after a game restart."); DefaultTake = ((BaseUnityPlugin)this).Config.Bind<bool>("Chests", "DefaultTake", false, "Newly built chests have terminal withdraw enabled."); DefaultInsert = ((BaseUnityPlugin)this).Config.Bind<bool>("Chests", "DefaultInsert", false, "Newly built chests have terminal insertion enabled."); EnableAllChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Chests", "EnableAllChests", false, "Action: set to true to enable insertion and withdraw on every player-built chest in the current world. Resets itself to false afterwards. If no world is loaded, it runs after you enter one."); EnableAllChests.SettingChanged += delegate { ChestBulk.TryRun(); }; Sort = ((BaseUnityPlugin)this).Config.Bind<SortMode>("UI", "Sort", SortMode.Name, "Last selected sort order in the terminal."); Filters = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "Filters", "", "Last selected terminal filters (comma separated ids, empty = All)."); IgnoreWeight = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "IgnoreWeight", false, "Recipe panel: Take also moves materials beyond the carry weight limit (checkbox in the panel)."); Texts.Register(); TerminalPiece.Register(Recipe.Value); _harmony = new Harmony("tremendouz.storageterminal"); _harmony.PatchAll(typeof(Plugin).Assembly); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class RecipePanel { private sealed class Craftable { public string Name; public string Search; public string Where; public int Output; public Requirement[] Resources; } private sealed class Tile { public Requirement Requirement; public Text Amount; } [CompilerGenerated] private static class <>O { public static UnityAction<string> <0>__FillList; public static UnityAction <1>__TakeMaterials; } private const float Width = 720f; private const float Height = 460f; private const float Column = 330f; private const int MaxRows = 150; private const float RowHeight = 28f; private const float RowSpacing = 2f; private const float TileWidth = 78f; private const float TileHeight = 86f; private const float TileSpacing = 6f; private const int TilesPerRow = 4; private const int TileRowsVisible = 3; private static GameObject _root; private static InputField _search; private static InputField _amount; private static Toggle _ignoreWeight; private static RectTransform _list; private static ScrollRect _listScroll; private static RectTransform _tiles; private static ScrollRect _tilesScroll; private static Text _title; private static readonly List<Tile> _tileViews = new List<Tile>(); private static List<Craftable> _all = new List<Craftable>(); private static Craftable _selected; public static bool IsFocused { get { if (!Object.op_Implicit((Object)(object)_search) || !_search.isFocused) { if (Object.op_Implicit((Object)(object)_amount)) { return _amount.isFocused; } return false; } return true; } } public static void Destroy() { if (Object.op_Implicit((Object)(object)_root)) { Object.Destroy((Object)(object)_root); } _root = null; _selected = null; _tileViews.Clear(); ScrollStep.Unregister(_listScroll); ScrollStep.Unregister(_tilesScroll); _listScroll = null; _tilesScroll = null; } public static void SetActive(bool active) { if (Object.op_Implicit((Object)(object)_root) && _root.activeSelf != active) { _root.SetActive(active); } } public static void OnTerminalOpened() { if (Object.op_Implicit((Object)(object)_root)) { _all = Collect(); _search.SetTextWithoutNotify(""); _amount.SetTextWithoutNotify("1"); _ignoreWeight.SetIsOnWithoutNotify(Plugin.IgnoreWeight.Value); FillList(""); Select(null); } } public static void Create(Transform fallbackParent) { try { Build(fallbackParent); } catch { Destroy(); throw; } } private static void Build(Transform fallbackParent) { //IL_002c: 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) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: 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_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Expected O, but got Unknown //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04f5: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Expected O, but got Unknown GUIManager instance = GUIManager.Instance; Transform val = (Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront) ? GUIManager.CustomGUIFront.transform : fallbackParent); _root = instance.CreateWoodpanel(val, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), Vector2.zero, 720f, 460f, false); ((Object)_root).name = "StorageTerminal_Recipes"; RectTransform val2 = (RectTransform)_root.transform; val2.pivot = new Vector2(0.5f, 1f); val2.anchoredPosition = new Vector2(0f, -10f); _root.SetActive(false); Transform transform = _root.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 1f); Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(0.5f, 0f); float num = -180f; float num2 = 180f; float num3 = num2 - 165f; instance.CreateText(Localization.instance.Localize("$st_recipes"), transform, val3, val3, new Vector2(0f, -22f), instance.AveriaSerifBold, 20, instance.ValheimOrange, true, Color.black, 300f, 30f, false).GetComponent<Text>().alignment = (TextAnchor)4; _search = instance.CreateInputField(transform, val3, val3, new Vector2(num, -55f), (ContentType)0, Localization.instance.Localize("$st_recipe_search"), 16, 330f, 30f).GetComponent<InputField>(); ((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)FillList); GameObject obj = instance.CreateScrollView(transform, false, true, 8f, 5f, instance.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.35f), 330f, 360f); RectTransform val5 = (RectTransform)obj.transform; Vector2 anchorMin = (val5.anchorMax = val3); val5.anchorMin = anchorMin; val5.pivot = new Vector2(0.5f, 1f); val5.anchoredPosition = new Vector2(num, -78f); ScrollRect componentInChildren = obj.GetComponentInChildren<ScrollRect>(true); if (!Object.op_Implicit((Object)(object)componentInChildren) || !Object.op_Implicit((Object)(object)componentInChildren.content)) { throw new InvalidOperationException("ScrollView without ScrollRect.content"); } _listScroll = componentInChildren; ScrollStep.Register(componentInChildren, 30f); _list = componentInChildren.content; VerticalLayoutGroup val7 = ((Component)_list).GetComponent<VerticalLayoutGroup>(); if (!Object.op_Implicit((Object)(object)val7)) { val7 = ((Component)_list).gameObject.AddComponent<VerticalLayoutGroup>(); } ((HorizontalOrVerticalLayoutGroup)val7).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val7).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val7).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val7).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val7).spacing = 2f; ((LayoutGroup)val7).padding = new RectOffset(4, 14, 4, 4); ContentSizeFitter val8 = ((Component)_list).GetComponent<ContentSizeFitter>(); if (!Object.op_Implicit((Object)(object)val8)) { val8 = ((Component)_list).gameObject.AddComponent<ContentSizeFitter>(); } val8.verticalFit = (FitMode)2; _title = instance.CreateText("", transform, val3, val3, new Vector2(num2, -55f), instance.AveriaSerifBold, 17, instance.ValheimOrange, true, Color.black, 330f, 30f, false).GetComponent<Text>(); _title.alignment = (TextAnchor)3; BuildTilesArea(transform, num2); GameObject obj2 = instance.CreateToggle(transform, 26f, 26f); RectTransform val9 = (RectTransform)obj2.transform; anchorMin = (val9.anchorMax = val4); val9.anchorMin = anchorMin; val9.anchoredPosition = new Vector2(num3 + 13f, 72f); _ignoreWeight = obj2.GetComponent<Toggle>(); ((UnityEvent<bool>)(object)_ignoreWeight.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v) { Plugin.IgnoreWeight.Value = v; }); instance.CreateText(Localization.instance.Localize("$st_ignore_weight"), transform, val4, val4, new Vector2(num3 + 140f, 72f), instance.AveriaSerifBold, 15, instance.ValheimOrange, true, Color.black, 220f, 28f, false); instance.CreateText(Localization.instance.Localize("$st_amount"), transform, val4, val4, new Vector2(num3 + 40f, 32f), instance.AveriaSerifBold, 16, instance.ValheimOrange, true, Color.black, 80f, 30f, false); _amount = instance.CreateInputField(transform, val4, val4, new Vector2(num3 + 115f, 32f), (ContentType)2, "1", 16, 70f, 30f).GetComponent<InputField>(); _amount.text = "1"; ((UnityEvent<string>)(object)_amount.onValueChanged).AddListener((UnityAction<string>)delegate { UpdateAmounts(); }); ButtonClickedEvent onClick = instance.CreateButton(Localization.instance.Localize("$st_take_button"), transform, val4, val4, new Vector2(num2 + 165f - 65f, 32f), 130f, 34f).GetComponent<Button>().onClick; object obj3 = <>O.<1>__TakeMaterials; if (obj3 == null) { UnityAction val11 = TakeMaterials; <>O.<1>__TakeMaterials = val11; obj3 = (object)val11; } ((UnityEvent)onClick).AddListener((UnityAction)obj3); } private static void BuildTilesArea(Transform parent, float centerX) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 1f); GameObject val2 = new GameObject("TilesViewport", new Type[3] { typeof(RectTransform), typeof(RectMask2D), typeof(Image) }); RectTransform val3 = (RectTransform)val2.transform; ((Transform)val3).SetParent(parent, false); Vector2 anchorMin = (val3.anchorMax = val); val3.anchorMin = anchorMin; val3.pivot = new Vector2(0.5f, 1f); val3.sizeDelta = new Vector2(330f, 270f); val3.anchoredPosition = new Vector2(centerX, -78f); ((Graphic)val2.GetComponent<Image>()).color = Color.clear; GameObject val5 = new GameObject("Tiles", new Type[1] { typeof(RectTransform) }); _tiles = (RectTransform)val5.transform; ((Transform)_tiles).SetParent((Transform)(object)val3, false); _tiles.anchorMin = new Vector2(0f, 1f); _tiles.anchorMax = new Vector2(1f, 1f); _tiles.pivot = new Vector2(0.5f, 1f); _tiles.sizeDelta = Vector2.zero; GridLayoutGroup obj = val5.AddComponent<GridLayoutGroup>(); obj.cellSize = new Vector2(78f, 86f); obj.spacing = new Vector2(6f, 6f); obj.constraint = (Constraint)1; obj.constraintCount = 4; val5.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2; _tilesScroll = val2.AddComponent<ScrollRect>(); _tilesScroll.horizontal = false; _tilesScroll.vertical = true; _tilesScroll.movementType = (MovementType)2; _tilesScroll.viewport = val3; _tilesScroll.content = _tiles; ScrollStep.Register(_tilesScroll, 92f); } private static List<Craftable> Collect() { List<Craftable> list = new List<Craftable>(); Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || (Object)(object)ObjectDB.instance == (Object)null) { return list; } HashSet<string> hashSet = new HashSet<string>(); foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (Object.op_Implicit((Object)(object)recipe) && recipe.m_enabled && Object.op_Implicit((Object)(object)recipe.m_item) && recipe.m_resources != null && recipe.m_resources.Length != 0) { SharedData shared = recipe.m_item.m_itemData.m_shared; if (localPlayer.IsRecipeKnown(shared.m_name) && hashSet.Add("R" + shared.m_name)) { list.Add(Make(shared.m_name, StationTag(recipe.m_craftingStation), recipe.m_amount, recipe.m_resources)); } } } foreach (GameObject item in ObjectDB.instance.m_items) { ItemDrop val = (Object.op_Implicit((Object)(object)item) ? item.GetComponent<ItemDrop>() : null); PieceTable val2 = (Object.op_Implicit((Object)(object)val) ? val.m_itemData.m_shared.m_buildPieces : null); if (!Object.op_Implicit((Object)(object)val2)) { continue; } foreach (GameObject piece in val2.m_pieces) { Piece val3 = (Object.op_Implicit((Object)(object)piece) ? piece.GetComponent<Piece>() : null); if (Object.op_Implicit((Object)(object)val3) && val3.m_enabled && val3.m_resources != null && val3.m_resources.Length != 0 && localPlayer.IsRecipeKnown(val3.m_name) && hashSet.Add("P" + val3.m_name)) { list.Add(Make(val3.m_name, "build", 1, val3.m_resources)); } } } list.Sort((Craftable a, Craftable b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase)); Plugin.Log.LogDebug((object)$"Recipes: {list.Count} known."); return list; } private static string StationTag(CraftingStation station) { if (!Object.op_Implicit((Object)(object)station)) { return "craft"; } return station.m_name switch { "$piece_workbench" => "workbench", "$piece_forge" => "forge", "$piece_cauldron" => "cauldron", "$piece_stonecutter" => "stonecutter", "$piece_artisanstation" => "artisan", "$piece_blackforge" => "black forge", "$piece_magetable" => "galdr", "$piece_preptable" => "prep table", "$piece_meadcauldron" => "mead ketill", _ => Localization.instance.Localize(station.m_name).ToLowerInvariant(), }; } private static Craftable Make(string token, string where, int output, Requirement[] resources) { string text = Localization.instance.Localize(token); return new Craftable { Name = text, Search = TerminalSession.Normalize(text), Where = where, Output = Math.Max(1, output), Resources = resources.Where((Requirement r) => r != null && Object.op_Implicit((Object)(object)r.m_resItem)).ToArray() }; } private static void FillList(string filter) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_list)) { return; } foreach (Transform item in (Transform)_list) { Object.Destroy((Object)(object)((Component)item).gameObject); } string needle = TerminalSession.Normalize(filter ?? ""); foreach (Craftable item2 in _all.Where((Craftable c) => needle.Length == 0 || c.Search.Contains(needle)).Take(150)) { string text = ((item2.Output > 1) ? $"{item2.Name} ×{item2.Output}" : item2.Name) + " <color=#a0a0a0>(" + item2.Where + ")</color>"; GameObject obj = GUIManager.Instance.CreateButton(text, (Transform)(object)_list, Vector2.zero, Vector2.zero, Vector2.zero, 300f, 28f); Text componentInChildren = obj.GetComponentInChildren<Text>(); if (Object.op_Implicit((Object)(object)componentInChildren)) { componentInChildren.supportRichText = true; componentInChildren.fontSize = 15; componentInChildren.alignment = (TextAnchor)3; RectTransform rectTransform = ((Graphic)componentInChildren).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = new Vector2(10f, 0f); rectTransform.offsetMax = new Vector2(-6f, 0f); } LayoutElement obj2 = obj.AddComponent<LayoutElement>(); obj2.preferredHeight = 28f; obj2.minHeight = 28f; Craftable captured = item2; ((UnityEvent)obj.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { Select(captured); }); } } private static void Select(Craftable craftable) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) _selected = craftable; foreach (Transform item in (Transform)_tiles) { Object.Destroy((Object)(object)((Component)item).gameObject); } _tileViews.Clear(); if (craftable == null) { _title.text = Localization.instance.Localize("$st_select_recipe"); return; } _title.text = ((craftable.Output > 1) ? $"{craftable.Name} ×{craftable.Output}" : craftable.Name); Requirement[] resources = craftable.Resources; foreach (Requirement req in resources) { _tileViews.Add(CreateTile(req)); } if (Object.op_Implicit((Object)(object)_tilesScroll)) { _tilesScroll.verticalNormalizedPosition = 1f; } UpdateAmounts(); } private static Tile CreateTile(Requirement req) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) GUIManager instance = GUIManager.Instance; GameObject val = new GameObject("Tile", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent((Transform)(object)_tiles, false); ((Graphic)val.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f); GameObject val2 = new GameObject("Icon", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val3 = (RectTransform)val2.transform; ((Transform)val3).SetParent(val.transform, false); Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(0.5f, 1f); val3.anchorMax = val4; val3.anchorMin = val4; val3.pivot = new Vector2(0.5f, 1f); val3.sizeDelta = new Vector2(40f, 40f); val3.anchoredPosition = new Vector2(0f, -4f); Image component = val2.GetComponent<Image>(); component.sprite = req.m_resItem.m_itemData.GetIcon(); component.preserveAspect = true; Text component2 = instance.CreateText(Localization.instance.Localize(req.m_resItem.m_itemData.m_shared.m_name), val.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 30f), instance.AveriaSerif, 11, instance.ValheimBeige, true, Color.black, 74f, 16f, false).GetComponent<Text>(); component2.alignment = (TextAnchor)4; component2.horizontalOverflow = (HorizontalWrapMode)0; component2.resizeTextForBestFit = true; component2.resizeTextMinSize = 8; component2.resizeTextMaxSize = 11; Text component3 = instance.CreateText("", val.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 12f), instance.AveriaSerifBold, 13, instance.ValheimBeige, true, Color.black, 74f, 18f, false).GetComponent<Text>(); component3.alignment = (TextAnchor)4; component3.supportRichText = true; return new Tile { Requirement = req, Amount = component3 }; } private static void UpdateAmounts() { if (_selected == null) { return; } TerminalSession current = TerminalSession.Current; Inventory val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null); int crafts = Crafts(); foreach (Tile tileView in _tileViews) { string name = tileView.Requirement.m_resItem.m_itemData.m_shared.m_name; int num = Need(tileView.Requirement, crafts); int num2 = current?.CountAvailable(name) ?? 0; int num3 = ((val != null) ? val.CountItems(name, -1, true) : 0); bool flag = num2 + num3 >= num; tileView.Amount.text = (flag ? $"{num}/{num2}" : $"<color=#ff6060>{num}/{num2}</color>"); } } private static int Crafts() { if (!int.TryParse(Object.op_Implicit((Object)(object)_amount) ? _amount.text : "1", out var result)) { return 1; } return Mathf.Clamp(result, 1, 999); } private static int Need(Requirement req, int crafts) { if (!Object.op_Implicit((Object)(object)req.m_resItem)) { return 0; } return req.GetAmount(1) * crafts; } private static void TakeMaterials() { TerminalSession session = TerminalSession.Current; Player localPlayer = Player.m_localPlayer; if (session == null || !Object.op_Implicit((Object)(object)localPlayer) || _selected == null) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); int crafts = Crafts(); List<KeyValuePair<SharedData, int>> list = new List<KeyValuePair<SharedData, int>>(); Requirement[] resources = _selected.Resources; foreach (Requirement val in resources) { int num = Need(val, crafts); if (num > 0) { SharedData shared = val.m_resItem.m_itemData.m_shared; int num2 = num - inventory.CountItems(shared.m_name, -1, true); if (num2 > 0) { list.Add(new KeyValuePair<SharedData, int>(shared, num2)); } } } if (list.Count == 0) { ((Character)localPlayer).Message((MessageType)2, "$st_nothing_needed", 0, (Sprite)null, false); return; } KeyValuePair<SharedData, int> keyValuePair = list.FirstOrDefault((KeyValuePair<SharedData, int> keyValuePair2) => session.CountAvailable(keyValuePair2.Key.m_name) < keyValuePair2.Value); if (keyValuePair.Key != null) { ((Character)localPlayer).Message((MessageType)2, Localization.instance.Localize("$st_missing: " + keyValuePair.Key.m_name), 0, (Sprite)null, false); return; } int num3 = 0; float num4 = 0f; foreach (KeyValuePair<SharedData, int> m in list) { int maxStack = Math.Max(1, m.Key.m_maxStackSize); int num5 = (from val2 in inventory.GetAllItems() where val2.m_shared.m_name == m.Key.m_name && val2.m_stack < maxStack select val2).Sum((ItemData val2) => maxStack - val2.m_stack); int num6 = m.Value - num5; if (num6 > 0) { num3 += (num6 + maxStack - 1) / maxStack; } num4 += m.Key.m_weight * (float)m.Value; } if (num3 > inventory.GetEmptySlots()) { ((Character)localPlayer).Message((MessageType)2, "$st_no_room", 0, (Sprite)null, false); return; } if (!Plugin.IgnoreWeight.Value && inventory.GetTotalWeight() + num4 > localPlayer.GetMaxCarryWeight()) { ((Character)localPlayer).Message((MessageType)2, "$st_too_heavy", 0, (Sprite)null, false); return; } foreach (KeyValuePair<SharedData, int> item in list) { session.TakeResource(item.Key.m_name, item.Value, inventory); } ((Character)localPlayer).Message((MessageType)2, "$st_taken", 0, (Sprite)null, false); UpdateAmounts(); } } internal static class ScrollStep { private static readonly Dictionary<ScrollRect, float> rows = new Dictionary<ScrollRect, float>(); public static void Register(ScrollRect rect, float rowHeight) { if (Object.op_Implicit((Object)(object)rect)) { rows[rect] = rowHeight; } } public static void Unregister(ScrollRect rect) { if ((Object)(object)rect != (Object)null) { rows.Remove(rect); } } public static bool IsRegistered(ScrollRect rect) { if ((Object)(object)rect != (Object)null) { return rows.ContainsKey(rect); } return false; } public static bool TryStep(ScrollRect rect, PointerEventData data) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rect == (Object)null || !rows.TryGetValue(rect, out var value)) { return false; } RectTransform content = rect.content; RectTransform val = (RectTransform)(Object.op_Implicit((Object)(object)rect.viewport) ? ((object)rect.viewport) : ((object)(RectTransform)((Component)rect).transform)); if (!Object.op_Implicit((Object)(object)content) || value <= 0f) { return true; } Rect rect2 = content.rect; float height = ((Rect)(ref rect2)).height; rect2 = val.rect; float num = height - ((Rect)(ref rect2)).height; if (num <= 0f) { return true; } float y = data.scrollDelta.y; if (Mathf.Approximately(y, 0f)) { return true; } int num2 = Math.Max(1, Mathf.RoundToInt(Mathf.Abs(y) / DeltaPerTick())); float num3 = (float)(Math.Sign(y) * num2) * value / num; rect.verticalNormalizedPosition = Mathf.Clamp01(rect.verticalNormalizedPosition + num3); return true; } private static float DeltaPerTick() { InputSystemUIInputModule val = (InputSystemUIInputModule)(Object.op_Implicit((Object)(object)EventSystem.current) ? /*isinst with value type is only supported in some contexts*/: null); float num = (Object.op_Implicit((Object)(object)val) ? val.scrollDeltaPerTick : 1f); if (!(num > 0f)) { return 1f; } return num; } } [HarmonyPatch(typeof(ScrollRect), "OnScroll")] internal static class ScrollRectOnScrollPatch { private static bool Prefix(ScrollRect __instance, PointerEventData data) { try { return !ScrollStep.TryStep(__instance, data); } catch (Exception arg) { Plugin.Log.LogError((object)$"Scroll step failed: {arg}"); return true; } } } internal sealed class TerminalMarker : MonoBehaviour { } internal static class TerminalPiece { public const string PrefabName = "piece_storage_terminal"; private const string BasePrefab = "piece_chest"; private static string _recipe; public static void Register(string recipe) { _recipe = recipe; PrefabManager.OnVanillaPrefabsAvailable += AddPiece; } public static bool IsTerminal(Container container) { if (Object.op_Implicit((Object)(object)container)) { return Object.op_Implicit((Object)(object)((Component)container).GetComponent<TerminalMarker>()); } return false; } private static void AddPiece() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown PrefabManager.OnVanillaPrefabsAvailable -= AddPiece; PieceConfig val = new PieceConfig { Name = "$piece_storage_terminal", Description = "$piece_storage_terminal_desc", PieceTable = PieceTables.Hammer, Category = PieceCategories.Furniture, Requirements = ParseRecipe(_recipe) }; CustomPiece val2 = new CustomPiece("piece_storage_terminal", "piece_chest", val); if ((Object)(object)val2.PiecePrefab == (Object)null) { Plugin.Log.LogError((object)"Could not clone 'piece_chest' — the terminal will not be available."); return; } Container component = val2.PiecePrefab.GetComponent<Container>(); if (Object.op_Implicit((Object)(object)component)) { component.m_name = "$piece_storage_terminal"; } val2.PiecePrefab.AddComponent<TerminalMarker>(); PieceManager.Instance.AddPiece(val2); } private static RequirementConfig[] ParseRecipe(string recipe) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); string[] array = (recipe ?? "").Split(','); foreach (string text in array) { string[] array2 = text.Split(':'); if (array2.Length != 2 || !int.TryParse(array2[1].Trim(), out var result) || result <= 0) { if (text.Trim().Length > 0) { Plugin.Log.LogWarning((object)("Invalid recipe entry: '" + text + "'")); } } else { list.Add(new RequirementConfig(array2[0].Trim(), result, 0, true)); } } if (list.Count == 0) { list.Add(new RequirementConfig("FineWood", 10, 0, true)); list.Add(new RequirementConfig("Iron", 2, 0, true)); } return list.ToArray(); } } internal enum SortMode { Name, Type, Amount } internal sealed class TerminalSession { private sealed class Entry { public ItemData View; public int Total; public readonly List<KeyValuePair<Container, ItemData>> Sources = new List<KeyValuePair<Container, ItemData>>(); } private const int Columns = 8; private readonly Container _terminal; private readonly Inventory _original; private readonly Inventory _virtual; private readonly Dictionary<ItemData, Entry> _entries = new Dictionary<ItemData, Entry>(); private bool _rebuilding; private bool _dirty; private bool _needsRebuild; private string _search = ""; private List<ItemFilter> _filters = new List<ItemFilter>(); public static TerminalSession Current { get; private set; } public Container Terminal => _terminal; public static bool IsView(Inventory inv) { if (inv != null && Current != null) { return inv == Current._virtual; } return false; } private TerminalSession(Container terminal) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown _terminal = terminal; _original = Access.ContainerInventory.Invoke(terminal); Inventory original = _original; _virtual = new Inventory("$piece_storage_terminal", (original != null) ? original.GetBkg() : null, 8, 1); Inventory obj = _virtual; obj.m_onChanged = (Action)Delegate.Combine(obj.m_onChanged, (Action)delegate { if (!_rebuilding) { _dirty = true; } }); } public static void Open(Container terminal) { Current?.Close(); TerminalSession terminalSession = new TerminalSession(terminal); terminalSession._filters = FilterSettings.Load(); Access.ContainerInventory.Invoke(terminal) = terminalSession._virtual; Current = terminalSession; terminalSession.Rebuild(); } public void Close() { if (Current == this) { if (_dirty && Object.op_Implicit((Object)(object)_terminal)) { ApplyDiff(); } if (Object.op_Implicit((Object)(object)_terminal)) { Access.ContainerInventory.Invoke(_terminal) = _original; } Current = null; } } public void SetSearch(string search) { _search = search ?? ""; Refresh(); } public void SetFilters(List<ItemFilter> filters) { _filters = filters ?? new List<ItemFilter>(); Refresh(); } public void SetSort(SortMode mode) { Plugin.Sort.Value = mode; Refresh(); } public void Tick(InventoryGui gui) { if (!Object.op_Implicit((Object)(object)_terminal)) { Current = null; } else if ((_dirty || _needsRebuild) && Access.DragItem.Invoke(gui) == null) { Refresh(); } } private void Refresh() { if (_dirty) { ApplyDiff(); } Rebuild(); } public int TakeTo(ItemData view, int amount, Inventory target, Vector2i? pos) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (view == null || !_entries.TryGetValue(view, out var value)) { return 0; } int num = Math.Max(1, view.m_shared.m_maxStackSize); amount = Math.Min(Math.Min(amount, value.Total), num); if (amount <= 0) { return 0; } ItemData val = ((num == 1) ? value.Sources[0].Value : view).Clone(); val.m_stack = amount; val.m_equipped = false; if (pos.HasValue) { Access.AddItemAt(target, val, val.m_stack, pos.Value); } if (val.m_stack > 0 && !FillStacks(target, val)) { FillEmptySlots(target, val); } int num2 = amount - val.m_stack; if (num2 > 0) { RemoveFromSources(value, num2); } _needsRebuild = true; return num2; } public int StoreFrom(Inventory from, ItemData item, int amount) { if (from == null || item == null) { return 0; } amount = Math.Min(amount, item.m_stack); if (amount <= 0) { return 0; } int num = Store(item, amount); if (num > 0) { from.RemoveItem(item, num); } if (num < amount) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "$st_no_space", 0, (Sprite)null, false); } } _needsRebuild = true; return num; } public int StackAllFrom(Inventory from) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) HashSet<string> hashSet = new HashSet<string>(); foreach (Container item in LinkedChests.Find(((Component)_terminal).transform.position, LinkFlags.CanInsert)) { foreach (ItemData allItem in Access.ContainerInventory.Invoke(item).GetAllItems()) { hashSet.Add(allItem.m_shared.m_name); } } int num = 0; foreach (ItemData item2 in from.GetAllItems().ToList()) { if (item2.m_shared.m_maxStackSize > 1 && !item2.m_equipped && hashSet.Contains(item2.m_shared.m_name)) { num += StoreFrom(from, item2, item2.m_stack); } } return num; } public int CountAvailable(string name) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (Container item in LinkedChests.Find(((Component)_terminal).transform.position, LinkFlags.CanTake)) { foreach (ItemData allItem in Access.ContainerInventory.Invoke(item).GetAllItems()) { if (allItem.m_shared.m_name == name) { num += allItem.m_stack; } } } return num; } public int TakeResource(string name, int amount, Inventory target) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<Inventory, ItemData>> list = new List<KeyValuePair<Inventory, ItemData>>(); foreach (Container item in LinkedChests.Find(((Component)_terminal).transform.position, LinkFlags.CanTake)) { Inventory val = Access.ContainerInventory.Invoke(item); foreach (ItemData allItem in val.GetAllItems()) { if (allItem.m_shared.m_name == name) { list.Add(new KeyValuePair<Inventory, ItemData>(val, allItem)); } } } list.Sort((KeyValuePair<Inventory, ItemData> a, KeyValuePair<Inventory, ItemData> b) => a.Value.m_stack.CompareTo(b.Value.m_stack)); int num = amount; foreach (KeyValuePair<Inventory, ItemData> item2 in list) { if (num <= 0) { break; } ItemData val2 = item2.Value.Clone(); val2.m_equipped = false; val2.m_stack = Math.Min(num, item2.Value.m_stack); int stack = val2.m_stack; if (!FillStacks(target, val2)) { FillEmptySlots(target, val2); } int num2 = stack - val2.m_stack; if (num2 > 0) { item2.Key.RemoveItem(item2.Value, num2); } num -= num2; if (val2.m_stack > 0) { break; } } _needsRebuild = true; return amount - num; } private void Rebuild() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) _rebuilding = true; try { List<Container> list = LinkedChests.Find(((Component)_terminal).transform.position, LinkFlags.CanTake); int num = 0; Dictionary<string, Entry> dictionary = new Dictionary<string, Entry>(); List<Entry> list2 = new List<Entry>(); foreach (Container item in list) { Inventory val = Access.ContainerInventory.Invoke(item); num += val.GetEmptySlots(); foreach (ItemData allItem in val.GetAllItems()) { Entry value; if (allItem.m_shared.m_maxStackSize > 1) { string key = allItem.m_shared.m_name + "|" + allItem.m_quality + "|" + allItem.m_worldLevel + "|" + allItem.m_variant; if (!dictionary.TryGetValue(key, out value)) { value = (dictionary[key] = new Entry()); list2.Add(value); } } else { value = new Entry(); list2.Add(value); } value.Sources.Add(new KeyValuePair<Container, ItemData>(item, allItem)); value.Total += allItem.m_stack; } } if (_filters.Count > 0) { list2 = list2.Where(delegate(Entry e) { int category = ItemCategory.Get(e.Sources[0].Value); return _filters.Any((ItemFilter f) => f.Matches(category)); }).ToList(); } if (_search.Length > 0) { string needle = Normalize(_search); list2 = list2.Where((Entry e) => Normalize(DisplayName(e.Sources[0].Value)).Contains(needle)).ToList(); } Sort(list2, Plugin.Sort.Value); int num2 = list2.Count + num; _virtual.SetHeight(Math.Max(1, (num2 + 8 - 1) / 8)); List<ItemData> list3 = Access.Items.Invoke(_virtual); list3.Clear(); _entries.Clear(); for (int num3 = 0; num3 < list2.Count; num3++) { Entry entry2 = list2[num3]; ItemData val2 = entry2.Sources[0].Value.Clone(); val2.m_stack = entry2.Total; val2.m_equipped = false; val2.m_gridPos = new Vector2i(num3 % 8, num3 / 8); entry2.View = val2; list3.Add(val2); _entries[val2] = entry2; } Access.Changed(_virtual); } finally { _rebuilding = false; _dirty = false; _needsRebuild = false; } } private static void Sort(List<Entry> entries, SortMode mode) { Comparison<Entry> byName = delegate(Entry a, Entry b) { ItemData value = a.Sources[0].Value; ItemData value2 = b.Sources[0].Value; int num = string.Compare(DisplayName(value), DisplayName(value2), StringComparison.CurrentCultureIgnoreCase); if (num != 0) { return num; } num = value2.m_quality.CompareTo(value.m_quality); return (num == 0) ? b.Total.CompareTo(a.Total) : num; }; switch (mode) { case SortMode.Type: { Dictionary<Entry, int> groups = entries.ToDictionary((Entry e) => e, (Entry e) => ItemCategory.Get(e.Sources[0].Value)); entries.Sort(delegate(Entry a, Entry b) { int num = groups[a].CompareTo(groups[b]); return (num == 0) ? byName(a, b) : num; }); break; } case SortMode.Amount: entries.Sort(delegate(Entry a, Entry b) { int num = b.Total.CompareTo(a.Total); return (num == 0) ? byName(a, b) : num; }); break; default: entries.Sort(byName); break; } } internal static string DisplayName(ItemData item) { if (Localization.instance == null) { return item.m_shared.m_name; } return Localization.instance.Localize(item.m_shared.m_name); } internal static string Normalize(string s) { StringBuilder stringBuilder = new StringBuilder(s.Length); string text = s.Normalize(NormalizationForm.FormD); foreach (char c in text) { if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } private void ApplyDiff() { List<ItemData> list = Access.Items.Invoke(_virtual); HashSet<ItemData> hashSet = new HashSet<ItemData>(list); List<KeyValuePair<ItemData, int>> list2 = new List<KeyValuePair<ItemData, int>>(); foreach (Entry value in _entries.Values) { int num = (hashSet.Contains(value.View) ? value.View.m_stack : 0); int num2 = value.Total - num; if (num2 > 0) { RemoveFromSources(value, num2); } else if (num2 < 0) { list2.Add(new KeyValuePair<ItemData, int>(value.View, -num2)); } } foreach (ItemData item in list) { if (!_entries.ContainsKey(item)) { list2.Add(new KeyValuePair<ItemData, int>(item, item.m_stack)); } } foreach (KeyValuePair<ItemData, int> item2 in list2) { int num3 = Store(item2.Key, item2.Value); if (num3 < item2.Value) { ReturnToPlayer(item2.Key, item2.Value - num3); } } _dirty = false; _needsRebuild = true; } private static void RemoveFromSources(Entry entry, int amount) { foreach (KeyValuePair<Container, ItemData> item in entry.Sources.OrderBy((KeyValuePair<Container, ItemData> s) => s.Value.m_stack)) { if (amount <= 0) { return; } Inventory val = (Object.op_Implicit((Object)(object)item.Key) ? Access.ContainerInventory.Invoke(item.Key) : null); if (val != null && val.ContainsItem(item.Value)) { int num = Math.Min(amount, item.Value.m_stack); val.RemoveItem(item.Value, num); amount -= num; } } if (amount > 0) { Plugin.Log.LogWarning((object)$"Could not remove {amount}x {entry.View?.m_shared.m_name} — the source changed."); } } private int Store(ItemData template, int amount) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) ItemData carrier = template.Clone(); carrier.m_stack = amount; carrier.m_equipped = false; List<Inventory> source = (from c in LinkedChests.Find(((Component)_terminal).transform.position, LinkFlags.CanInsert) select Access.ContainerInventory.Invoke(c)).ToList(); if (source.Any((Inventory inv) => FillStacks(inv, carrier)) || source.Where((Inventory inv) => Contains(inv, carrier)).Any((Inventory inv) => FillEmptySlots(inv, carrier))) { _ = 1; } else source.Any((Inventory inv) => FillEmptySlots(inv, carrier)); return amount - carrier.m_stack; } private static bool Matches(ItemData a, ItemData b) { if (a.m_shared.m_name == b.m_shared.m_name && a.m_quality == b.m_quality) { return a.m_worldLevel == b.m_worldLevel; } return false; } private static bool Contains(Inventory inv, ItemData carrier) { return inv.GetAllItems().Any((ItemData i) => Matches(i, carrier)); } private static bool FillStacks(Inventory inv, ItemData carrier) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (carrier.m_shared.m_maxStackSize <= 1) { return false; } foreach (ItemData item in inv.GetAllItems().ToList()) { if (Matches(item, carrier) && item.m_stack < item.m_shared.m_maxStackSize) { Access.AddItemAt(inv, carrier, carrier.m_stack, item.m_gridPos); if (carrier.m_stack <= 0) { return true; } } } return false; } private static bool FillEmptySlots(Inventory inv, ItemData carrier) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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) while (carrier.m_stack > 0) { Vector2i val = Access.FindEmptySlot(inv); if (val.x < 0) { return false; } int amount = Math.Min(carrier.m_stack, Math.Max(1, carrier.m_shared.m_maxStackSize)); if (!Access.AddItemAt(inv, carrier, amount, val)) { return false; } } return true; } private static void ReturnToPlayer(ItemData template, int amount) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } ((Character)localPlayer).Message((MessageType)2, "$st_no_space", 0, (Sprite)null, false); ItemData val = template.Clone(); val.m_stack = amount; val.m_equipped = false; Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (!FillStacks(inventory, val) && !FillEmptySlots(inventory, val)) { Transform transform = ((Component)localPlayer).transform; int val2 = Math.Max(1, val.m_shared.m_maxStackSize); while (val.m_stack > 0) { int num = Math.Min(val.m_stack, val2); ItemDrop.DropItem(val, num, transform.position + transform.forward + Vector3.up, transform.rotation); val.m_stack -= num; } } } } internal static class TerminalUi { [CompilerGenerated] private static class <>O { public static Action <0>__OnTerminalOpened; public static UnityAction <1>__Toggle; } private const float BarY = -24f; private const float FilterTop = -46f; private static InventoryGui _createdFor; private static GameObject _terminalRoot; private static GameObject _chestRoot; private static InputField _search; private static Text _filterButtonText; private static Toggle _take; private static Toggle _insert; private static Container _shownChest; private static ScrollRect _gridScroll; private static bool _blockingInput; public static void OnTerminalOpened() { if (Object.op_Implicit((Object)(object)_search)) { _search.SetTextWithoutNotify(""); } Safe("filter sync", delegate { FilterPanel.Sync(FilterSettings.Load()); }); Safe("recipe loading", RecipePanel.OnTerminalOpened); } public static void Update(InventoryGui gui) { if (!((Object)(object)_createdFor != (Object)(object)gui) || Create(gui)) { Container val = Access.CurrentContainer.Invoke(gui); bool flag = Object.op_Implicit((Object)(object)val) && TerminalPiece.IsTerminal(val); bool flag2 = Object.op_Implicit((Object)(object)val) && !flag && LinkedChests.IsLinkable(val); SetActive(_terminalRoot, flag); RecipePanel.SetActive(flag); SetActive(_chestRoot, flag2); if (flag && Object.op_Implicit((Object)(object)gui.m_takeAllButton)) { SetActive(((Component)gui.m_takeAllButton).gameObject, active: false); } if (Object.op_Implicit((Object)(object)_filterButtonText)) { _filterButtonText.text = (FilterPanel.IsOpen ? "Filters ▲" : "Filters ▼"); } UpdateScrollTarget(gui, flag); if (!flag2 || !Object.op_Implicit((Object)(object)_take) || !Object.op_Implicit((Object)(object)_insert)) { _shownChest = null; } else if ((Object)(object)val != (Object)(object)_shownChest) { _shownChest = val; _take.SetIsOnWithoutNotify(LinkFlags.CanTake(val)); _insert.SetIsOnWithoutNotify(LinkFlags.CanInsert(val)); } bool flag3 = flag && ((Object.op_Implicit((Object)(object)_search) && _search.isFocused) || RecipePanel.IsFocused); if (flag3 != _blockingInput) { SetInputBlock(flag3); } } } public static void ReleaseInput() { if (_blockingInput) { SetInputBlock(block: false); } } private static void SetInputBlock(bool block) { _blockingInput = block; GUIManager.BlockInput(block); } private static void UpdateScrollTarget(InventoryGui gui, bool terminal) { if (!terminal) { ScrollStep.Unregister(_gridScroll); } else if (!ScrollStep.IsRegistered(_gridScroll)) { InventoryGrid val = Access.ContainerGrid.Invoke(gui); _gridScroll = ((Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.m_gridRoot)) ? ((Component)val.m_gridRoot).GetComponentInParent<ScrollRect>() : null); if (!Object.op_Implicit((Object)(object)_gridScroll)) { Plugin.Log.LogWarning((object)"Terminal grid has no ScrollRect — row scrolling disabled."); } else { ScrollStep.Register(_gridScroll, val.m_elementSpace); } } } private static bool Create(InventoryGui gui) { if (!Object.op_Implicit((Object)(object)gui.m_container) || GUIManager.Instance == null || !Object.op_Implicit((Object)(object)GUIManager.Instance.AveriaSerifBold) || Localization.instance == null) { return false; } _createdFor = gui; _shownChest = null; _blockingInput = false; ScrollStep.Unregister(_gridScroll); _gridScroll = null; RecipePanel.Destroy(); RectTransform panel = gui.m_container; Safe("terminal bar", delegate { CreateTerminalBar(panel); }); Safe("chest checkboxes", delegate { CreateChestFlags((Transform)(object)panel); }); Safe("recipe panel", delegate { RecipePanel.Create((Transform)(object)panel); }); if (TerminalSession.Current != null) { OnTerminalOpened(); } return true; } private static void CreateTerminalBar(RectTransform panel) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) _terminalRoot = NewRoot("StorageTerminal_Bar", (Transform)(object)panel); _terminalRoot.SetActive(false); GUIManager instance = GUIManager.Instance; _search = instance.CreateInputField(_terminalRoot.transform, Vector2.zero, Vector2.zero, new Vector2(105f, -24f), (ContentType)0, Localization.instance.Localize("$st_search"), 16, 190f, 32f).GetComponent<InputField>(); ((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate(string text) { TerminalSession.Current?.SetSearch(text); }); AddSortButton("$st_sort_name", SortMode.Name, 250f); AddSortButton("$st_sort_type", SortMode.Type, 335f); AddSortButton("$st_sort_amount", SortMode.Amount, 420f); GameObject obj = instance.CreateButton("Filters ▼", _terminalRoot.transform, Vector2.zero, Vector2.zero, new Vector2(515f, -24f), 100f, 32f); ButtonClickedEvent onClick = obj.GetComponent<Button>().onClick; object obj2 = <>O.<1>__Toggle; if (obj2 == null) { UnityAction val = FilterPanel.Toggle; <>O.<1>__Toggle = val; obj2 = (object)val; } ((UnityEvent)onClick).AddListener((UnityAction)obj2); _filterButtonText = obj.GetComponentInChildren<Text>(); Rect rect = panel.rect; float num; if (!(((Rect)(ref rect)).width > 100f)) { num = 570f; } else { rect = panel.rect; num = ((Rect)(ref rect)).width; } float width = num; FilterPanel.Create(_terminalRoot.transform, width, -46f); } private static void CreateChestFlags(Transform panel) { _chestRoot = NewRoot("StorageTerminal_Flags", panel); _chestRoot.SetActive(false); _insert = AddToggle("$st_insert", 20f, delegate(bool v) { if (Object.op_Implicit((Object)(object)_shownChest)) { LinkFlags.SetInsert(_shownChest, v); } }); _take = AddToggle("$st_take", 280f, delegate(bool v) { if (Object.op_Implicit((Object)(object)_shownChest)) { LinkFlags.SetTake(_shownChest, v); } }); } private static GameObject NewRoot(string name, Transform parent) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0042: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(parent, false); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; Vector2 offsetMin = (val2.offsetMax = Vector2.zero); val2.offsetMin = offsetMin; return val; } private static void AddSortButton(string token, SortMode mode, float x) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0066: Expected O, but got Unknown ((UnityEvent)GUIManager.Instance.CreateButton(Localization.instance.Localize(token), _terminalRoot.transform, Vector2.zero, Vector2.zero, new Vector2(x, -24f), 80f, 32f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { TerminalSession.Current?.SetSort(mode); }); } private static Toggle AddToggle(string token, float x, Action<bool> onChanged) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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) GameObject obj = GUIManager.Instance.CreateToggle(_chestRoot.transform, 28f, 28f); RectTransform val = (RectTransform)obj.transform; Vector2 anchorMin = (val.anchorMax = Vector2.zero); val.anchorMin = anchorMin; val.anchoredPosition = new Vector2(x + 14f, -24f); GUIManager.Instance.CreateText(Localization.instance.Localize(token), _chestRoot.transform, Vector2.zero, Vector2.zero, new Vector2(x + 140f, -24f), GUIManager.Instance.AveriaSerifBold, 16, GUIManager.Instance.ValheimOrange, true, Color.black, 220f, 30f, false); Toggle component = obj.GetComponent<Toggle>(); ((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v) { onChanged(v); }); return component; } private static void SetActive(GameObject go, bool active) { if (Object.op_Implicit((Object)(object)go) && go.activeSelf != active) { go.SetActive(active); } } private static void Safe(string what, Action action) { try { action(); } catch (Exception arg) { Plugin.Log.LogError((object)$"UI ({what}) failed: {arg}"); } } } internal static class Texts { public static void Register() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "piece_storage_terminal", "Storage terminal" }, { "piece_storage_terminal_desc", "Shows the contents of all linked chests in range and stores items into them." }, { "st_take", "Enable terminal withdraw" }, { "st_insert", "Enable terminal insertion" }, { "st_search", "Search..." }, { "st_sort_name", "A-Z" }, { "st_sort_type", "Type" }, { "st_sort_amount", "Amount" }, { "st_no_space", "No space in linked chests" }, { "st_enabled_all", "Terminal enabled on $1 chests" }, { "st_recipes", "Recipes" }, { "st_recipe_search", "Search recipe..." }, { "st_amount", "Amount" }, { "st_take_button", "Take" }, { "st_select_recipe", "Select a recipe" }, { "st_no_room", "Not enough room in inventory" }, { "st_too_heavy", "You can't carry that much" }, { "st_missing", "Not enough materials" }, { "st_taken", "Materials taken" }, { "st_nothing_needed", "You already have everything" }, { "st_ignore_weight", "Ignore carry weight" } }); } } }