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 ChestTerminal v0.4.1
plugins/ChestTerminal.dll
Decompiled 6 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("ChestTerminal")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.4.1.0")] [assembly: AssemblyInformationalVersion("0.4.1")] [assembly: AssemblyProduct("ChestTerminal")] [assembly: AssemblyTitle("ChestTerminal")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.1.0")] [module: UnverifiableCode] [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 ChestTerminal { public enum Category { All, Materials, Food, Potions, Weapons, Armor, Ammo, Tools, Trophies, Fish, Misc } internal static class Catalog { private static bool _changedResolved; private static MethodInfo _changed; private static MethodInfo _updateWeight; private static FieldInfo _onChanged; private static MethodInfo _showMessage; public static List<Container> FindContainers(Vector3 center, float radius) { //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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) List<Container> list = new List<Container>(); PlayerProfile val = (Object.op_Implicit((Object)(object)Game.instance) ? Game.instance.GetPlayerProfile() : null); if (val == null) { return list; } long playerID = val.GetPlayerID(); float num = radius * radius; Container[] array = Object.FindObjectsOfType<Container>(); foreach (Container val2 in array) { if (Object.op_Implicit((Object)(object)val2) && !Terminal.Is(val2)) { Vector3 val3 = ((Component)val2).transform.position - center; if (!(((Vector3)(ref val3)).sqrMagnitude > num) && !((Object)(object)val2.m_nview == (Object)null) && val2.m_nview.IsValid() && val2.GetInventory() != null && !Object.op_Implicit((Object)(object)((Component)val2).GetComponent<TombStone>()) && (Plugin.IncludeCartsAndShips.Value || (!Object.op_Implicit((Object)(object)val2.m_wagon) && !Object.op_Implicit((Object)(object)((Component)val2).GetComponentInParent<Vagon>()) && !Object.op_Implicit((Object)(object)((Component)val2).GetComponentInParent<Ship>()))) && val2.CheckAccess(playerID) && (!val2.m_checkGuardStone || PrivateArea.CheckAccess(((Component)val2).transform.position, 0f, false, false))) { list.Add(val2); } } } return list; } public static bool Stackable(ItemData item) { return item.m_shared.m_maxStackSize > 1; } public static string Key(ItemData item) { return item.m_shared.m_name + "|" + item.m_quality + "|" + item.m_variant + "|" + item.m_worldLevel; } public static string SearchText(ItemData item) { string text = Localization.instance.Localize(item.m_shared.m_name); string text2 = (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : ""); return (text + " " + text2 + " " + Loc.Category(CategoryOf(item))).ToLowerInvariant(); } public static Category CategoryOf(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_0074: Expected I4, but got Unknown ItemType itemType = item.m_shared.m_itemType; switch (itemType - 1) { case 0: return Category.Materials; case 1: if (!(item.m_shared.m_food > 0f)) { return Category.Potions; } return Category.Food; case 2: case 3: case 13: case 19: case 21: return Category.Weapons; case 4: case 5: case 6: case 10: case 11: case 16: case 17: case 23: return Category.Armor; case 8: case 22: return Category.Ammo; case 14: case 18: return Category.Tools; case 12: return Category.Trophies; case 20: return Category.Fish; default: return Category.Misc; } } public static int MaxFit(Inventory target, ItemData item, int amount) { if (amount <= 0) { return 0; } if (target.CanAddItem(item, amount)) { return amount; } int num = 0; int num2 = amount; while (num < num2) { int num3 = (num + num2 + 1) / 2; if (target.CanAddItem(item, num3)) { num = num3; } else { num2 = num3 - 1; } } return num; } public static void NotifyChanged(Inventory inv) { if (inv == null) { return; } if (!_changedResolved) { _changedResolved = true; _changed = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Changed" && m.GetParameters().All((ParameterInfo p) => p.IsOptional)); _updateWeight = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "UpdateTotalWeight" && m.GetParameters().Length == 0); _onChanged = typeof(Inventory).GetField("m_onChanged", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Plugin.Log.LogInfo((object)((_changed != null) ? $"Inventory change notification: {_changed}" : $"Inventory.Changed not found, using fallback (weight: {_updateWeight != null}, event: {_onChanged != null})")); } if (_changed != null) { _changed.Invoke(inv, (from p in _changed.GetParameters() select p.DefaultValue).ToArray()); } else { _updateWeight?.Invoke(inv, null); (_onChanged?.GetValue(inv) as Action)?.Invoke(); } } public static void ShowMessage(MessageType type, string text) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)MessageHud.instance)) { return; } if (_showMessage == null) { _showMessage = (from m in typeof(MessageHud).GetMethods(BindingFlags.Instance | BindingFlags.Public) where m.Name == "ShowMessage" orderby m.GetParameters().Length descending select m).FirstOrDefault(delegate(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); return parameters.Length >= 2 && parameters[0].ParameterType == typeof(MessageType) && parameters[1].ParameterType == typeof(string) && parameters.Skip(2).All((ParameterInfo p) => p.IsOptional); }); } if (!(_showMessage == null)) { object[] array = (from p in _showMessage.GetParameters() select p.DefaultValue).ToArray(); array[0] = type; array[1] = text; _showMessage.Invoke(MessageHud.instance, array); } } public static bool EnsureOwner(Container c) { ZNetView nview = c.m_nview; if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } if (!nview.IsOwner()) { nview.ClaimOwnership(); } return nview.IsOwner(); } } internal static class Loc { private static readonly Dictionary<string, string> En = new Dictionary<string, string> { { "open", "Open terminal (radius {0} m)" }, { "search", "Search item or category..." }, { "status", "Chests in range: {0} Radius: {1} m" }, { "chests_full", "No room in the chests, item returned" }, { "title", "Chest terminal" }, { "set_radius", "Chest radius" }, { "set_radius_tip", "Chests within this many meters of the terminal are shown." }, { "set_columns", "Window width (slots)" }, { "set_columns_tip", "How many slots wide the terminal window is. Applies the next time you open it." }, { "set_merge", "One slot per item" }, { "set_merge_tip", "Show all items of one kind as a single slot with the total amount. You take out up to one full stack at a time." }, { "set_carts", "Include carts and ships" }, { "set_carts_tip", "Also show what is stored in carts and ships in range." }, { "cat_All", "All" }, { "cat_Materials", "Materials" }, { "cat_Food", "Food" }, { "cat_Potions", "Meads" }, { "cat_Weapons", "Weapons" }, { "cat_Armor", "Armor" }, { "cat_Ammo", "Ammo" }, { "cat_Tools", "Tools" }, { "cat_Trophies", "Trophies" }, { "cat_Fish", "Fish" }, { "cat_Misc", "Misc" } }; private static readonly Dictionary<string, string> Ru = new Dictionary<string, string> { { "open", "Открыть терминал (радиус {0} м)" }, { "search", "Поиск предмета или категории..." }, { "status", "Сундуков рядом: {0} Радиус: {1} м" }, { "chests_full", "В сундуках нет места, предмет возвращён" }, { "title", "Терминал сундуков" }, { "set_radius", "Радиус сундуков" }, { "set_radius_tip", "Показываются сундуки в пределах этого расстояния от терминала, в метрах." }, { "set_columns", "Ширина окна (ячеек)" }, { "set_columns_tip", "Сколько ячеек в ширину у окна терминала. Применяется при следующем открытии." }, { "set_merge", "Одна ячейка на предмет" }, { "set_merge_tip", "Показывать одинаковые предметы одной ячейкой с общим количеством. За раз берётся до одной полной стопки." }, { "set_carts", "Телеги и корабли" }, { "set_carts_tip", "Показывать также содержимое телег и кораблей в радиусе." }, { "cat_All", "Все" }, { "cat_Materials", "Материалы" }, { "cat_Food", "Еда" }, { "cat_Potions", "Зелья" }, { "cat_Weapons", "Оружие" }, { "cat_Armor", "Броня" }, { "cat_Ammo", "Боеприпасы" }, { "cat_Tools", "Инструменты" }, { "cat_Trophies", "Трофеи" }, { "cat_Fish", "Рыба" }, { "cat_Misc", "Прочее" } }; public static bool IsRussian { get { if (Localization.instance != null) { return Localization.instance.GetSelectedLanguage() == "Russian"; } return false; } } public static string T(string key) { if (!(IsRussian ? Ru : En).TryGetValue(key, out var value)) { return key; } return value; } public static string Category(Category c) { return T("cat_" + c); } } internal static class Terminal { public static bool Is(Container c) { if (Object.op_Implicit((Object)(object)c)) { return ((Object)((Component)c).gameObject).name.StartsWith("piece_chestterminal"); } return false; } public static IEnumerable<MethodBase> Methods(string name) { return from m in typeof(Container).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == name && m.DeclaringType == typeof(Container) select m; } } [HarmonyPatch] internal static class ContainerInteractPatch { private static IEnumerable<MethodBase> TargetMethods() { return Terminal.Methods("Interact"); } [HarmonyPriority(800)] private static void Prefix(Container __instance, object[] __args) { if (!Terminal.Is(__instance)) { return; } Humanoid val = (Humanoid)((__args.Length != 0) ? /*isinst with value type is only supported in some contexts*/: null); bool flag = default(bool); int num; if (__args.Length > 1) { object obj = __args[1]; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) == 0 && Object.op_Implicit((Object)(object)val) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)TerminalSession.Instance) && !TerminalSession.IsViewing(__instance)) { TerminalSession.Instance.Begin(__instance); } } } [HarmonyPatch] internal static class ContainerHoverPatch { private static IEnumerable<MethodBase> TargetMethods() { return Terminal.Methods("GetHoverText"); } [HarmonyPriority(0)] private static void Postfix(Container __instance, ref string __result) { if (Terminal.Is(__instance)) { __result = Localization.instance.Localize("$piece_chestterminal\n[<color=yellow><b>$KEY_Use</b></color>] ") + string.Format(Loc.T("open"), Mathf.RoundToInt(Plugin.Radius.Value)); } } } [HarmonyPatch] internal static class ContainerSavePatch { private static IEnumerable<MethodBase> TargetMethods() { return Terminal.Methods("Save"); } [HarmonyPriority(800)] private static bool Prefix(Container __instance) { return !Terminal.Is(__instance); } } [HarmonyPatch] internal static class ContainerLoadPatch { private static IEnumerable<MethodBase> TargetMethods() { return Terminal.Methods("Load"); } [HarmonyPriority(800)] private static bool Prefix(Container __instance) { return !Terminal.Is(__instance); } } [HarmonyPatch] internal static class ZInputPatch { private static readonly string[] Names = new string[6] { "GetButtonDown", "GetButton", "GetButtonUp", "GetKeyDown", "GetKey", "GetKeyUp" }; private static IEnumerable<MethodBase> TargetMethods() { return from m in typeof(ZInput).GetMethods(BindingFlags.Static | BindingFlags.Public) where Names.Contains(m.Name) && m.ReturnType == typeof(bool) && m.DeclaringType == typeof(ZInput) select m; } private static bool Prefix(ref bool __result) { if (!TerminalSession.SearchFocused) { return true; } __result = false; return false; } } [BepInPlugin("asinit.ChestTerminal", "ChestTerminal", "0.4.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "asinit.ChestTerminal"; public const string ModName = "ChestTerminal"; public const string Version = "0.4.1"; public const string PrefabName = "piece_chestterminal"; internal static Plugin Instance; internal static ManualLogSource Log; internal static ConfigEntry<float> Radius; internal static ConfigEntry<bool> IncludeCartsAndShips; internal static ConfigEntry<string> Recipe; internal static ConfigEntry<float> UiScale; internal static ConfigEntry<float> SearchBarOffset; internal static ConfigEntry<int> Columns; internal static ConfigEntry<bool> MergeStacks; internal static ConfigEntry<string> BasePrefab; internal static ConfigEntry<bool> Glow; private Harmony _harmony; private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 20f, new ConfigDescription("Radius (meters) around the terminal in which chests are scanned. / Радиус поиска сундуков вокруг терминала (м).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); IncludeCartsAndShips = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IncludeCartsAndShips", false, "Also show the contents of carts and ships in range. / Показывать также содержимое телег и кораблей."); Recipe = ((BaseUnityPlugin)this).Config.Bind<string>("Piece", "Recipe", "Wood:20,Resin:4", "Build cost as Item:Amount pairs separated by commas (restart required). / Стоимость постройки, Предмет:Кол-во через запятую (нужен перезапуск)."); if (Recipe.Value == "FineWood:10,Bronze:2,SurtlingCore:1") { Recipe.Value = (string)((ConfigEntryBase)Recipe).DefaultValue; } BasePrefab = ((BaseUnityPlugin)this).Config.Bind<string>("Piece", "BasePrefab", "piece_chest_blackmetal", "Vanilla chest the terminal takes its components and materials from; the model itself is the terminal's own (restart required). / Сундук игры, из которого берутся компоненты и материалы; модель у терминала своя (нужен перезапуск)."); Glow = ((BaseUnityPlugin)this).Config.Bind<bool>("Piece", "Glow", true, "Soft blue light from the terminal crystal (restart required). / Синяя подсветка от кристалла терминала (нужен перезапуск)."); UiScale = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Scale", 1f, new ConfigDescription("Search bar scale. / Масштаб панели поиска.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>())); Columns = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "Columns", 8, new ConfigDescription("Width of the terminal window in slots. / Ширина окна терминала в ячейках.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 16), Array.Empty<object>())); MergeStacks = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "MergeStacks", true, "Show all items of one kind as a single slot with the total amount. / Показывать одинаковые предметы одной ячейкой с общим количеством."); SearchBarOffset = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "SearchBarOffset", 12f, new ConfigDescription("Distance of the search bar from the top of the screen (at 1080p). / Отступ панели поиска от верха экрана.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 900f), Array.Empty<object>())); AddLocalizations(); PrefabManager.OnVanillaPrefabsAvailable += AddPiece; PrefabManager.OnVanillaPrefabsAvailable += AddSeneaLSettings; GameObject val = new GameObject("ChestTerminal_Session"); Object.DontDestroyOnLoad((Object)val); val.AddComponent<TerminalSession>(); _harmony = new Harmony("asinit.ChestTerminal"); Type[] array = new Type[11] { typeof(ContainerInteractPatch), typeof(ContainerHoverPatch), typeof(ContainerSavePatch), typeof(ContainerLoadPatch), typeof(ZInputPatch), typeof(MoveOutPatch), typeof(MoveAtPatch), typeof(MoveAllPatch), typeof(DragPatch), typeof(SplitPatch), typeof(DropPatch) }; foreach (Type type in array) { try { _harmony.CreateClassProcessor(type).Patch(); } catch (Exception arg) { Log.LogError((object)$"Harmony patch {type.Name} failed: {arg}"); } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void AddPiece() { //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown //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_00bc: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = PrefabManager.Instance.CreateClonedPrefab("piece_chestterminal", BasePrefab.Value); if (!Object.op_Implicit((Object)(object)val) && BasePrefab.Value != "piece_chest_wood") { Log.LogWarning((object)("Base prefab '" + BasePrefab.Value + "' not found, using piece_chest_wood")); val = PrefabManager.Instance.CreateClonedPrefab("piece_chestterminal", "piece_chest_wood"); } if (!Object.op_Implicit((Object)(object)val)) { Log.LogError((object)"No base chest prefab found, terminal piece not added"); return; } Container component = val.GetComponent<Container>(); if (Object.op_Implicit((Object)(object)component)) { component.m_name = "$piece_chestterminal"; } TerminalModel.Build(val); PieceConfig val2 = new PieceConfig { Name = "$piece_chestterminal", Description = "$piece_chestterminal_desc", PieceTable = "Hammer", Category = "Furniture", CraftingStation = "piece_workbench", Requirements = ParseRecipe(Recipe.Value) }; try { val2.Icon = RenderManager.Instance.Render(val, RenderManager.IsometricRotation); } catch (Exception ex) { Log.LogWarning((object)("Could not render the terminal icon, using the chest icon: " + ex.Message)); } PieceManager.Instance.AddPiece(new CustomPiece(val, false, val2)); } catch (Exception arg) { Log.LogError((object)$"Failed to add terminal piece: {arg}"); } finally { PrefabManager.OnVanillaPrefabsAvailable -= AddPiece; } } private static void AddSeneaLSettings() { PrefabManager.OnVanillaPrefabsAvailable -= AddSeneaLSettings; SeneaL.AddSetting((ConfigEntryBase)(object)Radius, () => Loc.T("set_radius"), () => Loc.T("set_radius_tip")); SeneaL.AddSetting((ConfigEntryBase)(object)Columns, () => Loc.T("set_columns"), () => Loc.T("set_columns_tip")); SeneaL.AddSetting((ConfigEntryBase)(object)MergeStacks, () => Loc.T("set_merge"), () => Loc.T("set_merge_tip")); SeneaL.AddSetting((ConfigEntryBase)(object)IncludeCartsAndShips, () => Loc.T("set_carts"), () => Loc.T("set_carts_tip")); } private static RequirementConfig[] ParseRecipe(string recipe) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); string[] array = (recipe ?? "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length != 2 || !int.TryParse(array2[1].Trim(), out var result) || result <= 0) { Log.LogWarning((object)("Ignoring bad recipe entry '" + text + "'")); } else { list.Add(new RequirementConfig(array2[0].Trim(), result, 0, true)); } } if (list.Count == 0) { list.Add(new RequirementConfig("Wood", 10, 0, true)); } return list.ToArray(); } private static void AddLocalizations() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "piece_chestterminal", "Chest terminal" }, { "piece_chestterminal_desc", "Opens all chests nearby as one big chest, with search and categories." } }); text = "Russian"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "piece_chestterminal", "Терминал сундуков" }, { "piece_chestterminal_desc", "Открывает все сундуки поблизости как один большой сундук, с поиском и категориями." } }); } } internal class SearchBar { public struct Result { public string Search; public Category Category; public bool Focused; } private const float Width = 900f; private const string SearchControl = "ChestTerminal_Search"; private static readonly Category[] Categories = (Category[])Enum.GetValues(typeof(Category)); private bool _stylesReady; private GUIStyle _panel; private GUIStyle _field; private GUIStyle _placeholder; private GUIStyle _tab; private GUIStyle _tabActive; private GUIStyle _info; public Result Draw(string search, Category category, int chestCount) { //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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00c3: 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) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Invalid comparison between Unknown and I4 //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Invalid comparison between Unknown and I4 //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Invalid comparison between Unknown and I4 //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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_0126: Invalid comparison between Unknown and I4 //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) EnsureStyles(); Result result = new Result { Search = search, Category = category }; Matrix4x4 matrix = GUI.matrix; float num = (float)Screen.height / 1080f * Plugin.UiScale.Value; GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f)); float num2 = (float)Screen.width / num; Rect val = default(Rect); ((Rect)(ref val))..ctor(Mathf.Round((num2 - 900f) / 2f), Plugin.SearchBarOffset.Value, 900f, 92f); Event current = Event.current; if ((int)current.type == 0 && !((Rect)(ref val)).Contains(current.mousePosition)) { GUI.FocusControl((string)null); } GUI.Box(val, GUIContent.none, _panel); GUI.BeginGroup(val); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(12f, 10f, 420f, 32f); bool flag = GUI.GetNameOfFocusedControl() == "ChestTerminal_Search"; if (flag && (int)current.type == 4 && ((int)current.keyCode == 27 || (int)current.keyCode == 13 || (int)current.keyCode == 271)) { GUI.FocusControl((string)null); current.Use(); flag = false; } GUI.SetNextControlName("ChestTerminal_Search"); result.Search = GUI.TextField(val2, search ?? "", 64, _field); if (string.IsNullOrEmpty(result.Search) && !flag) { GUI.Label(new Rect(((Rect)(ref val2)).x + 10f, ((Rect)(ref val2)).y, ((Rect)(ref val2)).width - 10f, ((Rect)(ref val2)).height), Loc.T("search"), _placeholder); } if (!string.IsNullOrEmpty(result.Search) && GUI.Button(new Rect(((Rect)(ref val2)).xMax + 6f, ((Rect)(ref val2)).y, 32f, 32f), "X", _tab)) { result.Search = ""; GUI.FocusControl((string)null); } GUI.Label(new Rect(480f, 10f, 408f, 32f), string.Format(Loc.T("status"), chestCount, Mathf.RoundToInt(Plugin.Radius.Value)), _info); float num3 = 12f; float num4 = 4f; float num5 = (876f - num4 * (float)(Categories.Length - 1)) / (float)Categories.Length; Category[] categories = Categories; foreach (Category category2 in categories) { if (GUI.Button(new Rect(num3, 50f, num5, 30f), Loc.Category(category2), (category2 == category) ? _tabActive : _tab)) { result.Category = category2; GUI.FocusControl((string)null); } num3 += num5 + num4; } GUI.EndGroup(); GUI.matrix = matrix; result.Focused = GUI.GetNameOfFocusedControl() == "ChestTerminal_Search"; return result; } private void EnsureStyles() { //IL_004d: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0066: Expected O, but got Unknown //IL_0080: 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) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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) //IL_00c7: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_00db: Expected O, but got Unknown //IL_00ef: 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_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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_016c: 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_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: 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_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Expected O, but got Unknown //IL_01e9: 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_01f5: 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_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown //IL_0244: Expected O, but got Unknown //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Expected O, but got Unknown //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) if (!_stylesReady) { _stylesReady = true; Color frame = default(Color); ((Color)(ref frame))..ctor(0.8f, 0.66f, 0.4f); Color val = default(Color); ((Color)(ref val))..ctor(0.93f, 0.88f, 0.78f); Font font = PickFont(); _panel = new GUIStyle(GUI.skin.box) { border = new RectOffset(2, 2, 2, 2) }; SetBackground(_panel, Framed(new Color(0.09f, 0.075f, 0.06f, 0.94f), frame)); _field = new GUIStyle(GUI.skin.textField) { font = font, fontSize = 18, alignment = (TextAnchor)3, padding = new RectOffset(10, 10, 4, 4), border = new RectOffset(2, 2, 2, 2) }; Texture2D val2 = Framed(new Color(0.04f, 0.035f, 0.03f, 1f), new Color(0.45f, 0.37f, 0.24f)); Texture2D val3 = Framed(new Color(0.06f, 0.05f, 0.04f, 1f), frame); SetStates(_field, val2, val2, val3, Color.white); _field.focused.background = val3; _placeholder = new GUIStyle(GUI.skin.label) { font = font, fontSize = 17, fontStyle = (FontStyle)2, alignment = (TextAnchor)3 }; _placeholder.normal.textColor = new Color(val.r, val.g, val.b, 0.45f); _info = new GUIStyle(GUI.skin.label) { font = font, fontSize = 16, alignment = (TextAnchor)5 }; _info.normal.textColor = new Color(val.r, val.g, val.b, 0.75f); _tab = new GUIStyle(GUI.skin.button) { font = font, fontSize = 15, alignment = (TextAnchor)4, border = new RectOffset(2, 2, 2, 2) }; SetStates(_tab, Framed(new Color(0.16f, 0.13f, 0.1f), new Color(0.4f, 0.33f, 0.22f)), Framed(new Color(0.24f, 0.19f, 0.13f), frame), Framed(new Color(0.3f, 0.24f, 0.15f), frame), val); _tabActive = new GUIStyle(_tab); Texture2D val4 = Framed(new Color(0.78f, 0.62f, 0.33f), new Color(0.95f, 0.82f, 0.55f)); SetStates(_tabActive, val4, val4, val4, new Color(0.12f, 0.09f, 0.05f)); } } private static Font PickFont() { Font val = null; try { GUIManager instance = GUIManager.Instance; val = ((instance != null) ? instance.AveriaSerifBold : null); } catch { } if (!Object.op_Implicit((Object)(object)val)) { return null; } if (Loc.IsRussian && !val.HasCharacter('П')) { return null; } return val; } private static void SetBackground(GUIStyle style, Texture2D tex) { style.normal.background = tex; style.hover.background = tex; style.active.background = tex; style.focused.background = tex; } private static void SetStates(GUIStyle style, Texture2D normal, Texture2D hover, Texture2D active, Color textColor) { //IL_005a: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) style.normal.background = normal; style.hover.background = hover; style.active.background = active; style.focused.background = normal; style.onNormal.background = normal; style.onHover.background = hover; style.onActive.background = active; style.normal.textColor = textColor; style.hover.textColor = textColor; style.active.textColor = textColor; style.focused.textColor = textColor; } private static Texture2D Framed(Color fill, Color frame) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0037: 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) Texture2D val = new Texture2D(6, 6, (TextureFormat)4, false) { hideFlags = (HideFlags)61, filterMode = (FilterMode)0 }; for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { val.SetPixel(j, i, (j < 2 || i < 2 || j >= 4 || i >= 4) ? frame : fill); } } val.Apply(); return val; } } internal static class SeneaL { public const string UiGuid = "seneaL.valheim.ui"; public const string ApiGuid = "seneaL.valheim.api"; private static bool _resolved; public static Type SearchBox { get; private set; } public static Type ChipBar { get; private set; } public static bool HasWidgets { get { if (!_resolved) { _resolved = true; SearchBox = AccessTools.TypeByName("SeneaLUI.Components.SearchBox"); ChipBar = AccessTools.TypeByName("SeneaLUI.Components.ChipBar"); } if (SearchBox != null) { return ChipBar != null; } return false; } } public static void AddSetting(ConfigEntryBase entry, Func<string> label, Func<string> tip) { try { MethodInfo methodInfo = AccessTools.TypeByName("SeneaL.API.ModSettings")?.GetMethod("Add", BindingFlags.Static | BindingFlags.Public); if (!(methodInfo == null)) { methodInfo.Invoke(null, new object[5] { "ChestTerminal", Loc.IsRussian ? "Терминал сундуков" : "Chest terminal", entry, label, tip }); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not add setting " + entry.Definition.Key + " to SeneaL UI: " + ex.Message)); } } public static object Get(object target, string member) { Type type = target.GetType(); FieldInfo field = type.GetField(member, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(target); } return type.GetProperty(member, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target, null); } public static void Set(object target, string member, object value) { FieldInfo field = target.GetType().GetField(member, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(target, value); } } public static object Call(object target, string method, params object[] args) { return target.GetType().GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(target, args); } } internal class PanelBar { private static readonly string[] CategoryIcons = new string[11] { null, "ore", "fork", "spark", "swords", "helmet", "quiver", "hammer", "trophy", "anchor", "other" }; private const float Pad = 22f; private const float Gap = 8f; private const float SearchH = 32f; private readonly RectTransform _panel; private readonly RectTransform _gridHost; private readonly RectTransform _gridBar; private readonly float _gridBaseY; private readonly object _search; private readonly object _chips; private readonly RectTransform _searchRoot; private readonly RectTransform _chipsRoot; private readonly PropertyInfo _focused; private float _applied; private float _lastWidth = -1f; private string _lastLang; private int _lastCat = -1; public bool Focused { get { try { return _focused != null && (bool)_focused.GetValue(_search, null); } catch { return false; } } } public bool Alive { get { if (Object.op_Implicit((Object)(object)_panel) && Object.op_Implicit((Object)(object)_searchRoot)) { return Object.op_Implicit((Object)(object)_chipsRoot); } return false; } } private PanelBar(RectTransform panel, RectTransform gridHost, RectTransform gridBar, object search, object chips, RectTransform searchRoot, RectTransform chipsRoot) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) _panel = panel; _gridHost = gridHost; _gridBar = gridBar; _gridBaseY = gridHost.anchoredPosition.y; _search = search; _chips = chips; _searchRoot = searchRoot; _chipsRoot = chipsRoot; _focused = search.GetType().GetProperty("Focused"); } public static PanelBar TryCreate(Action<string> onSearch, Action<int> onCategory) { if (!SeneaL.HasWidgets) { return null; } InventoryGui instance = InventoryGui.instance; InventoryGrid val = (Object.op_Implicit((Object)(object)instance) ? instance.m_containerGrid : null); RectTransform val2 = (RectTransform)(Object.op_Implicit((Object)(object)val) ? /*isinst with value type is only supported in some contexts*/: null); RectTransform val3 = (RectTransform)(Object.op_Implicit((Object)(object)val2) ? /*isinst with value type is only supported in some contexts*/: null); if (!Object.op_Implicit((Object)(object)val2) || ((Object)val2).name != "grid" || !Object.op_Implicit((Object)(object)val3) || ((Object)val3).name != "container" || !((Component)val3).gameObject.activeInHierarchy) { return null; } object obj = Activator.CreateInstance(SeneaL.SearchBox, val3, "terminal_search", 300f, "search"); object obj2 = Activator.CreateInstance(SeneaL.ChipBar, val3, "terminal_cats", CategoryIcons, onCategory); object obj3 = SeneaL.Get(obj, "Root"); RectTransform val4 = (RectTransform)((obj3 is RectTransform) ? obj3 : null); object obj4 = SeneaL.Get(obj2, "Root"); RectTransform val5 = (RectTransform)((obj4 is RectTransform) ? obj4 : null); if (!Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val5)) { return null; } SeneaL.Call(obj, "SetPlaceholder", Loc.T("search")); obj.GetType().GetEvent("Changed")?.AddEventHandler(obj, onSearch); Transform obj5 = ((Transform)val3).Find("gridbar"); return new PanelBar(val3, val2, (RectTransform)(object)((obj5 is RectTransform) ? obj5 : null), obj, obj2, val4, val5); } public void Tick(Category category) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!Alive) { return; } float num = Mathf.Max(200f, _panel.sizeDelta.x - 44f); string text = ((Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : ""); if (Mathf.Abs(num - _lastWidth) > 0.5f || text != _lastLang) { _lastWidth = num; _lastLang = text; SeneaL.Call(_search, "SetWidth", num); SeneaL.Call(_search, "SetPlaceholder", Loc.T("search")); SeneaL.Set(_chips, "MaxWidth", num); string[] array = new string[CategoryIcons.Length]; for (int i = 0; i < array.Length; i++) { array[i] = Loc.Category((Category)i); } SeneaL.Call(_chips, "SetLabels", new object[1] { array }); } if (category != (Category)_lastCat) { _lastCat = (int)category; SeneaL.Call(_chips, "SetOn", _lastCat); } float num2 = 0f - _gridBaseY; Place(_searchRoot, 22f, num2); Place(_chipsRoot, 22f, num2 + 32f + 8f); float num3 = ((SeneaL.Get(_chips, "Height") is float num4) ? num4 : 28f); ApplyOffset(40f + num3 + 14f); } private static void Place(RectTransform rt, float x, float y) { //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_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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0051: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 1f); if (rt.anchorMin != val) { Vector2 val2 = (rt.pivot = val); Vector2 anchorMin = (rt.anchorMax = val2); rt.anchorMin = anchorMin; } Vector2 val5 = default(Vector2); ((Vector2)(ref val5))..ctor(x, 0f - y); if (rt.anchoredPosition != val5) { rt.anchoredPosition = val5; } } private void ApplyOffset(float extra) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Abs(_gridHost.anchoredPosition.y - _gridBaseY) < 0.5f) { _applied = 0f; } float num = extra - _applied; if (!(Mathf.Abs(num) < 0.5f)) { Shift(num); _applied = extra; } } private void Shift(float delta) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0061: 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) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) RectTransform gridHost = _gridHost; gridHost.anchoredPosition -= new Vector2(0f, delta); if (Object.op_Implicit((Object)(object)_gridBar)) { RectTransform gridBar = _gridBar; gridBar.anchoredPosition -= new Vector2(0f, delta); } RectTransform panel = _panel; panel.sizeDelta += new Vector2(0f, delta); } public void Destroy() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) try { if (Object.op_Implicit((Object)(object)_panel) && Object.op_Implicit((Object)(object)_gridHost) && Mathf.Abs(_gridHost.anchoredPosition.y - _gridBaseY) > 0.5f) { Shift(0f - _applied); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not restore the chest panel layout: " + ex.Message)); } if (Object.op_Implicit((Object)(object)_searchRoot)) { Object.Destroy((Object)(object)((Component)_searchRoot).gameObject); } if (Object.op_Implicit((Object)(object)_chipsRoot)) { Object.Destroy((Object)(object)((Component)_chipsRoot).gameObject); } } } internal static class Stacks { public static bool Active => Plugin.MergeStacks.Value; public static bool Oversized(ItemData item) { if (item != null && Catalog.Stackable(item)) { return item.m_stack > item.m_shared.m_maxStackSize; } return false; } public static int TakeStack(Inventory to, Inventory view, ItemData item) { ItemData val = item.Clone(); val.m_stack = Mathf.Min(item.m_stack, item.m_shared.m_maxStackSize); val.m_equipped = false; int stack = val.m_stack; int num = (to.AddItem(val) ? stack : (stack - val.m_stack)); if (num > 0) { view.RemoveItem(item, num); } return num; } public static bool PutIntoView(Inventory view, Inventory from, ItemData item, int amount, int x, int y) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00da: 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) amount = Mathf.Min(amount, item.m_stack); if (amount <= 0) { return false; } string key = Catalog.Key(item); ItemData val = (Catalog.Stackable(item) ? ((IEnumerable<ItemData>)view.m_inventory).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i != item && Catalog.Stackable(i) && Catalog.Key(i) == key)) : null); if (val != null) { val.m_stack += amount; } else { Vector2i val2 = (Vector2i)((x >= 0 && y >= 0 && x < view.m_width && y < view.m_height && view.GetItemAt(x, y) == null) ? new Vector2i(x, y) : view.FindEmptySlot(false)); if (val2.x < 0) { return false; } ItemData val3 = item.Clone(); val3.m_stack = amount; val3.m_equipped = false; val3.m_gridPos = val2; view.m_inventory.Add(val3); } ItemData obj = item; obj.m_stack -= amount; if (item.m_stack <= 0) { from.RemoveItem(item); } else { Catalog.NotifyChanged(from); } Catalog.NotifyChanged(view); return true; } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData) })] internal static class MoveOutPatch { [HarmonyPriority(600)] private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item) { if (!Stacks.Active || __instance == fromInventory || !TerminalSession.IsView(fromInventory) || !Stacks.Oversized(item)) { return true; } Stacks.TakeStack(__instance, fromInventory, item); return false; } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int) })] internal static class MoveAtPatch { [HarmonyPriority(600)] private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item, ref int amount, int x, int y, ref bool __result) { if (!Stacks.Active || item == null || __instance == fromInventory) { return true; } if (TerminalSession.IsView(fromInventory)) { if (Catalog.Stackable(item)) { amount = Mathf.Min(amount, item.m_shared.m_maxStackSize); } return true; } if (!TerminalSession.IsView(__instance)) { return true; } __result = Stacks.PutIntoView(__instance, fromInventory, item, amount, x, y); return false; } } [HarmonyPatch(typeof(Inventory), "MoveAll")] internal static class MoveAllPatch { [HarmonyPriority(600)] private static bool Prefix(Inventory __instance, Inventory fromInventory) { if (!Stacks.Active || __instance == fromInventory || !TerminalSession.IsView(fromInventory)) { return true; } foreach (ItemData item in fromInventory.GetAllItems().ToList()) { if (Catalog.Stackable(item)) { while (fromInventory.ContainsItem(item) && Stacks.TakeStack(__instance, fromInventory, item) > 0) { } } else if (__instance.AddItem(item)) { fromInventory.RemoveItem(item); } } Catalog.NotifyChanged(__instance); Catalog.NotifyChanged(fromInventory); return false; } } [HarmonyPatch(typeof(InventoryGui), "SetupDragItem")] internal static class DragPatch { private static void Prefix(ItemData item, Inventory inventory, ref int amount) { if (Stacks.Active && item != null && Catalog.Stackable(item) && TerminalSession.IsView(inventory)) { amount = Mathf.Min(amount, item.m_shared.m_maxStackSize); } } } [HarmonyPatch(typeof(InventoryGui), "ShowSplitDialog")] internal static class SplitPatch { private static void Postfix(InventoryGui __instance, object[] __args) { object obj = __args[0]; ItemData val = (ItemData)((obj is ItemData) ? obj : null); if (Stacks.Active && Stacks.Oversized(val) && TerminalSession.IsView((Inventory)/*isinst with value type is only supported in some contexts*/)) { bool flag = ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true); object obj2 = AccessTools.Field(typeof(InventoryGui), "m_splitDialog")?.GetValue(__instance); ((obj2 == null) ? null : AccessTools.Method(obj2.GetType(), "UpdateLimits", new Type[2] { typeof(int), typeof(bool) }, (Type[])null))?.Invoke(obj2, new object[2] { val.m_shared.m_maxStackSize, flag }); } } } [HarmonyPatch(typeof(Humanoid), "DropItem")] internal static class DropPatch { private static void Prefix(Inventory inventory, ItemData item, ref int amount) { if (Stacks.Active && item != null && Catalog.Stackable(item) && TerminalSession.IsView(inventory)) { amount = Mathf.Min(amount, item.m_shared.m_maxStackSize); } } } internal static class TerminalModel { private static readonly Color GlowColor = new Color(0.35f, 0.75f, 1f); private static readonly Dictionary<string, Material> Cache = new Dictionary<string, Material>(); public static void Build(GameObject prefab) { //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04c5: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Unknown result type (might be due to invalid IL or missing references) //IL_0511: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_05f1: Unknown result type (might be due to invalid IL or missing references) //IL_0618: Unknown result type (might be due to invalid IL or missing references) //IL_0631: Unknown result type (might be due to invalid IL or missing references) //IL_0576: Unknown result type (might be due to invalid IL or missing references) //IL_057b: Unknown result type (might be due to invalid IL or missing references) //IL_058e: Unknown result type (might be due to invalid IL or missing references) //IL_05a3: Unknown result type (might be due to invalid IL or missing references) //IL_05ba: Unknown result type (might be due to invalid IL or missing references) List<Material> source = (from m in prefab.GetComponentsInChildren<Renderer>(true).SelectMany((Renderer r) => r.sharedMaterials) where Object.op_Implicit((Object)(object)m) select m).Distinct().ToList(); Material val = ((IEnumerable<Material>)source).FirstOrDefault((Func<Material, bool>)((Material m) => ((Object)m).name.ToLowerInvariant().Contains("wood"))) ?? source.FirstOrDefault(); Material source2 = ((IEnumerable<Material>)source).FirstOrDefault((Func<Material, bool>)delegate(Material m) { string text = ((Object)m).name.ToLowerInvariant(); return text.Contains("metal") || text.Contains("iron") || text.Contains("black"); }) ?? val; if (!Object.op_Implicit((Object)(object)val)) { Plugin.Log.LogWarning((object)"No base material found, keeping the base chest model"); return; } foreach (Transform item in ((IEnumerable)prefab.transform).Cast<Transform>().ToList()) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } Collider[] components = prefab.GetComponents<Collider>(); for (int num = 0; num < components.Length; num++) { Object.DestroyImmediate((Object)(object)components[num]); } Renderer[] components2 = prefab.GetComponents<Renderer>(); for (int num = 0; num < components2.Length; num++) { Object.DestroyImmediate((Object)(object)components2[num]); } MeshFilter[] components3 = prefab.GetComponents<MeshFilter>(); for (int num = 0; num < components3.Length; num++) { Object.DestroyImmediate((Object)(object)components3[num]); } LODGroup[] components4 = prefab.GetComponents<LODGroup>(); for (int num = 0; num < components4.Length; num++) { Object.DestroyImmediate((Object)(object)components4[num]); } int num2 = LayerMask.NameToLayer("piece"); if (num2 < 0) { num2 = prefab.layer; } GameObject val2 = new GameObject("terminal_model"); val2.transform.SetParent(prefab.transform, false); val2.layer = num2; Material mat = Tinted(val, new Color(0.62f, 0.5f, 0.42f), "terminal_wood"); Material mat2 = Tinted(source2, new Color(0.38f, 0.4f, 0.46f), "terminal_metal"); Material mat3 = Glowing(source2, GlowColor, "terminal_glow"); Shape(val2, (PrimitiveType)3, new Vector3(0f, 0.1f, 0f), Vector3.zero, new Vector3(1.3f, 0.2f, 0.85f), mat2, num2); Shape(val2, (PrimitiveType)3, new Vector3(0f, 0.5f, 0f), Vector3.zero, new Vector3(1.1f, 0.6f, 0.7f), mat, num2); Shape(val2, (PrimitiveType)3, new Vector3(0f, 0.62f, 0f), Vector3.zero, new Vector3(1.16f, 0.07f, 0.76f), mat2, num2); float[] array = new float[2] { -0.55f, 0.55f }; foreach (float num3 in array) { float[] array2 = new float[2] { -0.35f, 0.35f }; foreach (float num5 in array2) { Shape(val2, (PrimitiveType)3, new Vector3(num3, 0.5f, num5), Vector3.zero, new Vector3(0.12f, 0.82f, 0.12f), mat2, num2); } } array = new float[2] { 0.36f, 0.48f }; foreach (float num6 in array) { Shape(val2, (PrimitiveType)3, new Vector3(0f, num6, -0.355f), Vector3.zero, new Vector3(0.7f, 0.035f, 0.02f), mat3, num2); } Shape(val2, (PrimitiveType)3, new Vector3(0f, 0.42f, -0.355f), new Vector3(0f, 0f, 45f), new Vector3(0.1f, 0.1f, 0.02f), mat3, num2); GameObject parent = Holder(val2, new Vector3(0f, 0.95f, -0.05f), new Vector3(-22f, 0f, 0f), num2); Shape(parent, (PrimitiveType)3, Vector3.zero, Vector3.zero, new Vector3(1.2f, 0.08f, 0.82f), mat, num2); Shape(parent, (PrimitiveType)3, new Vector3(0f, 0.045f, 0f), Vector3.zero, new Vector3(0.86f, 0.02f, 0.52f), mat3, num2); Shape(parent, (PrimitiveType)3, new Vector3(0f, 0.03f, 0f), Vector3.zero, new Vector3(0.94f, 0.03f, 0.6f), mat2, num2); Shape(val2, (PrimitiveType)2, new Vector3(0f, 1.18f, 0.3f), Vector3.zero, new Vector3(0.08f, 0.16f, 0.08f), mat2, num2); Shape(val2, (PrimitiveType)3, new Vector3(0f, 1.5f, 0.3f), new Vector3(45f, 0f, 35f), new Vector3(0.17f, 0.17f, 0.17f), mat3, num2); if (Plugin.Glow.Value) { GameObject val3 = new GameObject("terminal_light"); val3.transform.SetParent(val2.transform, false); val3.transform.localPosition = new Vector3(0f, 1.5f, 0.3f); Light obj = val3.AddComponent<Light>(); obj.type = (LightType)2; obj.color = GlowColor; obj.range = 3.5f; obj.intensity = 1.3f; obj.shadows = (LightShadows)0; } GameObject val4 = new GameObject("terminal_collider") { layer = num2 }; val4.transform.SetParent(prefab.transform, false); BoxCollider obj2 = val4.AddComponent<BoxCollider>(); obj2.center = new Vector3(0f, 0.7f, 0f); obj2.size = new Vector3(1.3f, 1.4f, 0.85f); WearNTear component = prefab.GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component)) { component.m_new = val2; component.m_worn = val2; component.m_broken = val2; component.m_wet = null; component.m_fragmentRoots = (GameObject[])(object)new GameObject[1] { val2 }; } Container component2 = prefab.GetComponent<Container>(); if (Object.op_Implicit((Object)(object)component2)) { component2.m_open = null; component2.m_closed = null; } } private static GameObject Holder(GameObject parent, Vector3 pos, Vector3 euler, int layer) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_003c: Expected O, but got Unknown GameObject val = new GameObject("part") { layer = layer }; val.transform.SetParent(parent.transform, false); val.transform.localPosition = pos; val.transform.localEulerAngles = euler; return val; } private unsafe static void Shape(GameObject parent, PrimitiveType type, Vector3 pos, Vector3 euler, Vector3 size, Material mat, int layer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_005e: Unknown result type (might be due to invalid IL or missing references) GameObject val = Holder(parent, pos, euler, layer); GameObject obj = GameObject.CreatePrimitive(type); ((Object)obj).name = ((object)(*(PrimitiveType*)(&type))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); obj.layer = layer; Collider component = obj.GetComponent<Collider>(); if (Object.op_Implicit((Object)(object)component)) { Object.DestroyImmediate((Object)(object)component); } obj.transform.SetParent(val.transform, false); obj.transform.localScale = size; obj.GetComponent<Renderer>().sharedMaterial = mat; } private static Material Tinted(Material source, Color tint, string name) { //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_001f: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (Cache.TryGetValue(name, out var value)) { return value; } Material val = new Material(source) { name = name }; if (val.HasProperty("_Color")) { val.color = tint; } Cache[name] = val; return val; } private static Material Glowing(Material source, Color color, string name) { //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_001f: Expected O, but got Unknown //IL_002d: 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_0057: Unknown result type (might be due to invalid IL or missing references) if (Cache.TryGetValue(name, out var value)) { return value; } Material val = new Material(source) { name = name }; if (val.HasProperty("_Color")) { val.color = color; } if (val.HasProperty("_EmissionColor")) { val.EnableKeyword("_EMISSION"); val.SetColor("_EmissionColor", color * 2f); } Cache[name] = val; return val; } } public class TerminalSession : MonoBehaviour { private class ViewEntry { public ItemData Item; public Source? Source; } private struct Source { public Container Container; public ItemData Item; } private const int MinRows = 4; private int _viewWidth = 8; private PanelBar _panelBar; private float _panelDeadline; private bool _active; private bool _shown; private float _startTime; private bool _syncing; private bool _dirty; private Container _terminal; private Inventory _view; private List<Container> _chests = new List<Container>(); private Dictionary<string, int> _counts = new Dictionary<string, int>(); private readonly Dictionary<ItemData, Source> _unique = new Dictionary<ItemData, Source>(); private string _search = ""; private Category _category; private SearchBar _bar; public static TerminalSession Instance { get; private set; } public static bool SearchFocused { get; private set; } private bool UsePanelBar { get { if (_panelBar == null) { return Time.unscaledTime <= _panelDeadline; } return true; } } private void Awake() { Instance = this; } public static bool IsViewing(Container c) { if (Object.op_Implicit((Object)(object)Instance) && Instance._active) { return (Object)(object)Instance._terminal == (Object)(object)c; } return false; } public static bool IsView(Inventory inv) { if (inv != null && Object.op_Implicit((Object)(object)Instance) && Instance._active) { return Instance._view == inv; } return false; } public void Begin(Container terminal) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) End(); Inventory val = (Object.op_Implicit((Object)(object)terminal) ? terminal.GetInventory() : null); if (val == null) { return; } _active = true; _shown = false; _viewWidth = Plugin.Columns.Value; _search = ""; _category = Category.All; _startTime = Time.unscaledTime; _terminal = terminal; _view = val; _chests = Catalog.FindContainers(((Component)terminal).transform.position, Plugin.Radius.Value); foreach (Container chest in _chests) { Inventory inventory = chest.GetInventory(); inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnRealChanged)); } Inventory view = _view; view.m_onChanged = (Action)Delegate.Combine(view.m_onChanged, new Action(OnViewChanged)); try { Rebuild(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Terminal failed to read chests: {arg}"); End(); return; } Plugin.Log.LogInfo((object)$"Terminal opened: {_chests.Count} chests in range"); } public void End() { if (!_active) { return; } _active = false; SearchFocused = false; _panelBar?.Destroy(); _panelBar = null; foreach (Container chest in _chests) { Inventory val = (Object.op_Implicit((Object)(object)chest) ? chest.GetInventory() : null); if (val != null) { val.m_onChanged = (Action)Delegate.Remove(val.m_onChanged, new Action(OnRealChanged)); } } _chests.Clear(); if (_view != null) { Inventory view = _view; view.m_onChanged = (Action)Delegate.Remove(view.m_onChanged, new Action(OnViewChanged)); _syncing = true; try { _view.m_inventory.Clear(); Catalog.NotifyChanged(_view); } catch (Exception arg) { Plugin.Log.LogError((object)$"Terminal failed to clear its view: {arg}"); } finally { _syncing = false; } } _view = null; _terminal = null; _counts.Clear(); _unique.Clear(); Plugin.Log.LogInfo((object)"Terminal closed"); } private void OnDestroy() { End(); } private void Update() { if (!_active) { return; } InventoryGui instance = InventoryGui.instance; if (Object.op_Implicit((Object)(object)_terminal) && Object.op_Implicit((Object)(object)instance) && InventoryGui.IsVisible() && (Object)(object)instance.m_currentContainer == (Object)(object)_terminal) { if (!_shown) { _panelDeadline = Time.unscaledTime + 1f; } _shown = true; } else if (_shown || !Object.op_Implicit((Object)(object)_terminal) || Time.unscaledTime - _startTime > 3f) { End(); return; } if (!_dirty || Object.op_Implicit((Object)(object)instance.m_dragGo)) { return; } try { Rebuild(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Terminal refresh failed: {arg}"); End(); } } private void LateUpdate() { if (!_active || !_shown) { return; } if (_panelBar == null && Time.unscaledTime <= _panelDeadline) { try { _panelBar = PanelBar.TryCreate(OnSearchChanged, OnCategoryClicked); if (_panelBar != null) { Plugin.Log.LogInfo((object)"Terminal search placed inside the SeneaL UI chest panel"); } } catch (Exception arg) { Plugin.Log.LogWarning((object)$"Could not build the SeneaL UI search bar, using the fallback bar: {arg}"); _panelDeadline = 0f; } } if (_panelBar == null) { return; } try { _panelBar.Tick(_category); SearchFocused = _panelBar.Focused; } catch (Exception arg2) { Plugin.Log.LogWarning((object)$"SeneaL UI search bar failed, using the fallback bar: {arg2}"); _panelBar.Destroy(); _panelBar = null; _panelDeadline = 0f; SearchFocused = false; } } private void OnSearchChanged(string text) { _search = text ?? ""; _dirty = true; } private void OnCategoryClicked(int index) { _category = (Category)index; _dirty = true; } private void OnRealChanged() { if (!_syncing) { _dirty = true; } } private void OnViewChanged() { if (_syncing || !_active) { return; } try { Sync(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Terminal sync failed: {arg}"); _dirty = true; } } private void Rebuild() { //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) _dirty = false; if (!_active || _view == null) { return; } Dictionary<string, int> dictionary = new Dictionary<string, int>(); Dictionary<string, ItemData> dictionary2 = new Dictionary<string, ItemData>(); List<Source> list = new List<Source>(); _chests.RemoveAll((Container c) => !Object.op_Implicit((Object)(object)c) || c.GetInventory() == null); foreach (Container chest in _chests) { foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { if (allItem?.m_shared == null || !Matches(allItem)) { continue; } if (Catalog.Stackable(allItem)) { string key = Catalog.Key(allItem); dictionary.TryGetValue(key, out var value); dictionary[key] = value + allItem.m_stack; if (!dictionary2.ContainsKey(key)) { dictionary2[key] = allItem; } } else { list.Add(new Source { Container = chest, Item = allItem }); } } } List<ViewEntry> list2 = new List<ViewEntry>(); foreach (KeyValuePair<string, int> item2 in dictionary) { ItemData val = dictionary2[item2.Key]; int num = item2.Value; int num2 = (Plugin.MergeStacks.Value ? int.MaxValue : Mathf.Max(1, val.m_shared.m_maxStackSize)); while (num > 0) { int num3 = Mathf.Min(num, num2); list2.Add(new ViewEntry { Item = Copy(val, num3) }); num -= num3; } } foreach (Source item3 in list) { list2.Add(new ViewEntry { Item = Copy(item3.Item, item3.Item.m_stack), Source = item3 }); } List<ViewEntry> list3 = (from e in list2 orderby Catalog.CategoryOf(e.Item), Localization.instance.Localize(e.Item.m_shared.m_name), e.Item.m_quality descending select e).ToList(); _syncing = true; try { _view.m_inventory.Clear(); _unique.Clear(); for (int num4 = 0; num4 < list3.Count; num4++) { ItemData item = list3[num4].Item; item.m_gridPos = new Vector2i(num4 % _viewWidth, num4 / _viewWidth); _view.m_inventory.Add(item); if (list3[num4].Source.HasValue) { _unique[item] = list3[num4].Source.Value; } } int num5 = Mathf.Max(4, (list3.Count + _viewWidth - 1) / _viewWidth + 1); _view.m_width = _viewWidth; _view.m_height = Mathf.Max(num5, _shown ? _view.m_height : 0); _counts = CountStacks(_view); Catalog.NotifyChanged(_view); } finally { _syncing = false; } } private bool Matches(ItemData item) { if (_category != Category.All && Catalog.CategoryOf(item) != _category) { return false; } string text = _search.Trim().ToLowerInvariant(); if (text.Length != 0) { return Catalog.SearchText(item).Contains(text); } return true; } private static ItemData Copy(ItemData item, int stack) { ItemData obj = item.Clone(); obj.m_stack = stack; obj.m_equipped = false; return obj; } private static Dictionary<string, int> CountStacks(Inventory inv) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (ItemData item in inv.m_inventory) { if (Catalog.Stackable(item)) { string key = Catalog.Key(item); dictionary.TryGetValue(key, out var value); dictionary[key] = value + item.m_stack; } } return dictionary; } private void Sync() { _syncing = true; try { Dictionary<string, int> dictionary = CountStacks(_view); Dictionary<string, ItemData> dictionary2 = new Dictionary<string, ItemData>(); HashSet<ItemData> hashSet = new HashSet<ItemData>(); foreach (ItemData item in _view.m_inventory) { if (Catalog.Stackable(item)) { dictionary2[Catalog.Key(item)] = item; } else { hashSet.Add(item); } } foreach (string item2 in _counts.Keys.Union(dictionary.Keys).ToList()) { _counts.TryGetValue(item2, out var value); dictionary.TryGetValue(item2, out var value2); if (value2 < value) { RemoveFromChests(item2, value - value2); } else if (value2 > value) { ItemData val = dictionary2[item2]; int num = AddToChests(val, value2 - value); if (num > 0) { ReturnToPlayer(val, num); } } } foreach (KeyValuePair<ItemData, Source> item3 in _unique.ToList()) { if (!hashSet.Contains(item3.Key)) { Source value3 = item3.Value; Inventory val2 = (Object.op_Implicit((Object)(object)value3.Container) ? value3.Container.GetInventory() : null); if (val2 != null && val2.ContainsItem(value3.Item) && Catalog.EnsureOwner(value3.Container)) { val2.RemoveItem(value3.Item); } else { Plugin.Log.LogWarning((object)("Terminal: " + value3.Item.m_shared.m_name + " was already gone from its chest")); } _unique.Remove(item3.Key); } } foreach (ItemData item4 in hashSet) { if (!_unique.ContainsKey(item4)) { if (AddUniqueToChests(item4, out var source)) { _unique[item4] = source; } else { ReturnToPlayer(item4, item4.m_stack); } } } if (MergeDuplicates()) { Catalog.NotifyChanged(_view); } _counts = CountStacks(_view); if (_view.GetEmptySlots() < _viewWidth) { Inventory view = _view; view.m_height++; } } finally { _syncing = false; } } private bool MergeDuplicates() { if (!Plugin.MergeStacks.Value) { return false; } bool result = false; Dictionary<string, ItemData> dictionary = new Dictionary<string, ItemData>(); foreach (ItemData item in _view.m_inventory.ToList()) { if (Catalog.Stackable(item)) { string key = Catalog.Key(item); if (dictionary.TryGetValue(key, out var value)) { ItemData obj = value; obj.m_stack += item.m_stack; _view.m_inventory.Remove(item); result = true; } else { dictionary[key] = item; } } } return result; } private void RemoveFromChests(string key, int amount) { foreach (Container chest in _chests) { if (amount <= 0) { return; } Inventory val = (Object.op_Implicit((Object)(object)chest) ? chest.GetInventory() : null); if (val == null) { continue; } foreach (ItemData item in val.GetAllItems().ToList()) { if (amount <= 0) { break; } if (Catalog.Stackable(item) && !(Catalog.Key(item) != key) && Catalog.EnsureOwner(chest)) { int num = Mathf.Min(item.m_stack, amount); val.RemoveItem(item, num); amount -= num; } } } if (amount > 0) { Plugin.Log.LogWarning((object)$"Terminal: {amount} x {key} were already gone from the chests"); } } private int AddToChests(ItemData template, int amount) { string key = Catalog.Key(template); foreach (Container item in from c in _chests where Object.op_Implicit((Object)(object)c) && c.GetInventory() != null orderby c.GetInventory().GetAllItems().Any((ItemData i) => Catalog.Key(i) == key) descending select c) { if (amount <= 0) { break; } Inventory inventory = item.GetInventory(); int num = Catalog.MaxFit(inventory, template, amount); if (num > 0 && Catalog.EnsureOwner(item) && inventory.AddItem(Copy(template, num))) { amount -= num; } } return amount; } private bool AddUniqueToChests(ItemData item, out Source source) { foreach (Container chest in _chests) { Inventory val = (Object.op_Implicit((Object)(object)chest) ? chest.GetInventory() : null); if (val != null && val.HaveEmptySlot() && Catalog.EnsureOwner(chest)) { ItemData val2 = Copy(item, item.m_stack); if (val.AddItem(val2)) { source = new Source { Container = chest, Item = val2 }; return true; } } } source = default(Source); return false; } private void ReturnToPlayer(ItemData viewItem, int amount) { //IL_0052: 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_0062: 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_006c: 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) Player localPlayer = Player.m_localPlayer; ItemData val = Copy(viewItem, amount); _view.RemoveItem(viewItem, amount); if (Object.op_Implicit((Object)(object)localPlayer) && ((Humanoid)localPlayer).GetInventory().CanAddItem(val, amount)) { ((Humanoid)localPlayer).GetInventory().AddItem(val); } else if (Object.op_Implicit((Object)(object)localPlayer)) { ItemDrop.DropItem(val, amount, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward + Vector3.up, Quaternion.identity); } Message(Loc.T("chests_full")); } private static void Message(string text) { Catalog.ShowMessage((MessageType)2, text); } private void OnGUI() { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) if (!_active || !_shown) { SearchFocused = false; } else { if (UsePanelBar) { return; } _bar = _bar ?? new SearchBar(); try { SearchBar.Result result = _bar.Draw(_search, _category, _chests.Count); SearchFocused = result.Focused; if (result.Search != _search || result.Category != _category) { _search = result.Search; _category = result.Category; _dirty = true; } } catch (Exception arg) { Plugin.Log.LogError((object)$"Terminal search bar failed: {arg}"); SearchFocused = false; GUI.matrix = Matrix4x4.identity; } } } } }