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 QuickStackToChests v1.0.0
BepInEx/plugins/QuickStackToChests.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("QuickStackToChests")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Valheim BepInEx mod: quick stack inventory into nearby chests by hotkey.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+2d883ccf93068ef6443f7796b032a5faeaf7d882")] [assembly: AssemblyProduct("QuickStackToChests")] [assembly: AssemblyTitle("QuickStackToChests")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace QuickStackToChests { [BepInPlugin("blajion.quickstacktochests", "QuickStackToChests", "1.0.0")] [BepInProcess("valheim.exe")] public class QuickStackPlugin : BaseUnityPlugin { public const string PluginGuid = "blajion.quickstacktochests"; public const string PluginName = "QuickStackToChests"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry<KeyboardShortcut> HotKey; internal static ConfigEntry<float> Radius; internal static ConfigEntry<bool> SkipFirstRow; internal static ConfigEntry<bool> SkipEquipped; internal static ConfigEntry<bool> IncludeNonStackable; internal static ConfigEntry<bool> FillEmptySlots; internal static ConfigEntry<bool> RespectWards; internal static ConfigEntry<bool> SkipContainersInUse; internal static ConfigEntry<string> ExcludedItems; internal static ConfigEntry<string> ExcludedContainers; internal static ConfigEntry<bool> ShowMessage; internal static ConfigEntry<bool> VerboseLog; private float _nextAllowedRun; private bool _settingsOpen; private bool _waitingForHotKey; private Rect _settingsRect = new Rect(30f, 100f, 460f, 365f); private static MethodInfo _chatHasFocus; private static bool _chatHasFocusResolved; private void Awake() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; HotKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1. Управление", "HotKey", new KeyboardShortcut((KeyCode)113, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Горячая клавиша переноса. Формат BepInEx: 'Q + LeftControl', 'V', 'S + LeftAlt' и т.п."); Radius = ((BaseUnityPlugin)this).Config.Bind<float>("2. Поиск сундуков", "Radius", 12f, new ConfigDescription("Радиус поиска сундуков вокруг игрока (метры).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); SkipContainersInUse = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Поиск сундуков", "SkipContainersInUse", true, "Пропускать сундуки, которые сейчас открыты кем-то (в том числе вами)."); RespectWards = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Поиск сундуков", "RespectWards", true, "Учитывать ворды (Ward) и приватные сундуки: не трогать чужое."); ExcludedContainers = ((BaseUnityPlugin)this).Config.Bind<string>("2. Поиск сундуков", "ExcludedContainers", "", "Префабы сундуков, которые игнорировать. Через запятую, например: piece_chest_private, Container_wood"); SkipFirstRow = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Предметы", "SkipFirstRow", true, "Не трогать первый ряд инвентаря (хотбар) - там обычно инструменты и еда."); SkipEquipped = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Предметы", "SkipEquipped", true, "Не трогать экипированные предметы."); IncludeNonStackable = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Предметы", "IncludeNonStackable", false, "Переносить и нестакающиеся предметы (оружие, броня, инструменты), если такие же лежат в сундуке."); FillEmptySlots = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Предметы", "FillEmptySlots", true, "Если в сундуке уже есть такой предмет, но стаки заполнены - докладывать остаток в свободные слоты этого сундука."); ExcludedItems = ((BaseUnityPlugin)this).Config.Bind<string>("3. Предметы", "ExcludedItems", "", "Предметы, которые никогда не переносить. Через запятую, префаб или имя: Wood, Coins, $item_coins"); ShowMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Прочее", "ShowMessage", true, "Показывать сообщение о результате переноса на экране."); VerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Прочее", "VerboseLog", false, "Подробный лог в консоль BepInEx (для отладки)."); Log.LogInfo((object)string.Format("{0} v{1} loaded. Hotkey: {2}", "QuickStackToChests", "1.0.0", HotKey.Value)); } private void Update() { //IL_007d: 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) if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return; } if (Input.GetKeyDown((KeyCode)289) && !Console.IsVisible() && !TextInput.IsVisible()) { _settingsOpen = !_settingsOpen; _waitingForHotKey = false; } if (_settingsOpen) { if (_waitingForHotKey) { TryReadSideMouseBinding(); } } else { if (Time.time < _nextAllowedRun || IsTypingOrBlocked()) { return; } KeyboardShortcut value = HotKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _nextAllowedRun = Time.time + 0.3f; try { QuickStack.Run(); } catch (Exception arg) { Log.LogError((object)$"Quick stack error: {arg}"); } } } } private void OnGUI() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //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) if (_settingsOpen) { _settingsRect = GUI.Window(731942, _settingsRect, new WindowFunction(DrawSettingsWindow), Translations.Text("QuickStackToChests — Settings", "QuickStackToChests — Настройки")); } } private void DrawSettingsWindow(int windowId) { //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_027b: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.Label(Translations.Text("F8 — close. Changes save immediately.", "F8 — закрыть. Настройки сохраняются сразу."), Array.Empty<GUILayoutOption>()); GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(Translations.Text("Quick stack hotkey:", "Быстрая сортировка:"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); if (GUILayout.Button(_waitingForHotKey ? Translations.Text("Press a key or side mouse button… (Esc — cancel)", "Нажми клавишу или боковую кнопку мыши… (Esc — отмена)") : ((object)HotKey.Value/*cast due to .constrained prefix*/).ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(260f) })) { _waitingForHotKey = true; } GUILayout.EndHorizontal(); if (_waitingForHotKey) { ReadNewHotKey(Event.current); } GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(Translations.Text($"Chest radius: {Radius.Value:0} m", $"Радиус сундуков: {Radius.Value:0} м"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) }); float num = Mathf.Round(GUILayout.HorizontalSlider(Radius.Value, 1f, 60f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) })); if (!Mathf.Approximately(num, Radius.Value)) { Radius.Value = num; ((BaseUnityPlugin)this).Config.Save(); } GUILayout.EndHorizontal(); DrawToggle(Translations.Text("Skip first inventory row", "Не трогать первый ряд инвентаря"), SkipFirstRow); DrawToggle(Translations.Text("Skip equipped items", "Не трогать экипированные вещи"), SkipEquipped); DrawToggle(Translations.Text("Respect wards and private chests", "Уважать ворды и приватные сундуки"), RespectWards); DrawToggle(Translations.Text("Skip chests currently in use", "Пропускать открытые сундуки"), SkipContainersInUse); DrawToggle(Translations.Text("Fill empty slots in matching chests", "Класть остаток в свободные ячейки сундука"), FillEmptySlots); DrawToggle(Translations.Text("Include weapons, armor and tools", "Переносить оружие, броню и инструменты"), IncludeNonStackable); GUILayout.FlexibleSpace(); if (GUILayout.Button(Translations.Text("Close (F8)", "Закрыть (F8)"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { _settingsOpen = false; _waitingForHotKey = false; } GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f)); } private void DrawToggle(string label, ConfigEntry<bool> setting) { bool flag = GUILayout.Toggle(setting.Value, label, Array.Empty<GUILayoutOption>()); if (flag != setting.Value) { setting.Value = flag; ((BaseUnityPlugin)this).Config.Save(); } } private void ReadNewHotKey(Event currentEvent) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_0026: 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_0096: 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) if (currentEvent == null || (int)currentEvent.type != 4) { return; } if ((int)currentEvent.keyCode == 27) { _waitingForHotKey = false; currentEvent.Use(); } else if (!IsModifierKey(currentEvent.keyCode)) { List<KeyCode> list = new List<KeyCode>(); if (currentEvent.control) { list.Add((KeyCode)306); } if (currentEvent.shift) { list.Add((KeyCode)304); } if (currentEvent.alt) { list.Add((KeyCode)308); } if (currentEvent.command) { list.Add((KeyCode)310); } HotKey.Value = new KeyboardShortcut(currentEvent.keyCode, list.ToArray()); ((BaseUnityPlugin)this).Config.Save(); Log.LogInfo((object)$"New quick stack hotkey: {HotKey.Value}"); _waitingForHotKey = false; currentEvent.Use(); } } private void TryReadSideMouseBinding() { if (Input.GetMouseButtonDown(3)) { SetMouseHotKey((KeyCode)326); } else if (Input.GetMouseButtonDown(4)) { SetMouseHotKey((KeyCode)327); } else if (Input.GetMouseButtonDown(5)) { SetMouseHotKey((KeyCode)328); } } private void SetMouseHotKey(KeyCode mouseButton) { //IL_0005: 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_002f: Unknown result type (might be due to invalid IL or missing references) HotKey.Value = new KeyboardShortcut(mouseButton, Array.Empty<KeyCode>()); ((BaseUnityPlugin)this).Config.Save(); Log.LogInfo((object)$"New quick stack hotkey: {HotKey.Value}"); _waitingForHotKey = false; } private static bool IsModifierKey(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Invalid comparison between Unknown and I4 if ((int)key != 306 && (int)key != 305 && (int)key != 304 && (int)key != 303 && (int)key != 308 && (int)key != 307 && (int)key != 310) { return (int)key == 309; } return true; } private static bool IsTypingOrBlocked() { if (Console.IsVisible()) { return true; } if (TextInput.IsVisible()) { return true; } if (Menu.IsVisible()) { return true; } if (IsChatFocused()) { return true; } return false; } private static bool IsChatFocused() { if ((Object)(object)Chat.instance == (Object)null) { return false; } if (!_chatHasFocusResolved) { _chatHasFocusResolved = true; _chatHasFocus = typeof(Chat).GetMethod("HasFocus", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, Type.EmptyTypes, null); } if (_chatHasFocus == null) { return false; } try { object obj = _chatHasFocus.Invoke(Chat.instance, null); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } } internal static class QuickStack { private const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags AllStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static readonly MethodInfo ContainerSaveMethod = typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); private static readonly MethodInfo ContainerLoadMethod = typeof(Container).GetMethod("Load", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); private static readonly FieldInfo ContainerNViewField = typeof(Container).GetField("m_nview", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo ContainerCheckAccessMethod = typeof(Container).GetMethod("CheckAccess", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(long) }, null); private static readonly MethodInfo MoveItemToThisMethod = typeof(Inventory).GetMethod("MoveItemToThis", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[5] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int) }, null); private static readonly MethodInfo InventoryChangedNoArgs = typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); private static readonly MethodInfo InventoryChangedTwoArgs = typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(bool), typeof(bool) }, null); private static readonly MethodInfo PrivateAreaCheckAccess4 = typeof(PrivateArea).GetMethod("CheckAccess", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[4] { typeof(Vector3), typeof(float), typeof(bool), typeof(bool) }, null); private static readonly MethodInfo PrivateAreaCheckAccess3 = typeof(PrivateArea).GetMethod("CheckAccess", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(Vector3), typeof(float), typeof(bool) }, null); private static readonly MethodInfo InCutsceneMethod = typeof(Character).GetMethod("InCutscene", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); private static readonly FieldInfo WorldLevelField = typeof(ItemData).GetField("m_worldLevel", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static int _layerMask; private static readonly Collider[] HitBuffer = (Collider[])(object)new Collider[512]; internal static void Run() { //IL_012c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || IsInCutscene(localPlayer)) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return; } HashSet<string> excluded = ParseList(QuickStackPlugin.ExcludedItems.Value); HashSet<string> excluded2 = ParseList(QuickStackPlugin.ExcludedContainers.Value); List<Container> list = FindNearbyContainers(localPlayer, excluded2); if (list.Count == 0) { Message(localPlayer, Translations.NoNearbyChests); return; } int num = 0; int num2 = 0; foreach (Container item in list) { Inventory val = PrepareContainer(item); if (val == null) { continue; } int num3 = 0; foreach (ItemData item2 in inventory.GetAllItems().ToList()) { if (IsTransferable(item2, excluded)) { num3 += StackItemIntoContainer(inventory, val, item2); } } if (num3 > 0) { num += num3; num2++; FinishContainer(item); if (QuickStackPlugin.VerboseLog.Value) { QuickStackPlugin.Log.LogInfo((object)$"Перенесено {num3} шт. в {((Object)item).name} ({((Component)item).transform.position})"); } } } if (num > 0) { NotifyChanged(inventory); Message(localPlayer, Translations.Stacked(num, num2)); } else { Message(localPlayer, Translations.NothingToStack); } } private static List<Container> FindNearbyContainers(Player player, HashSet<string> excluded) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); HashSet<Container> hashSet = new HashSet<Container>(); Vector3 center = ((Component)player).transform.position; float value = QuickStackPlugin.Radius.Value; long playerID = player.GetPlayerID(); int num = Physics.OverlapSphereNonAlloc(center, value, HitBuffer, GetLayerMask()); for (int i = 0; i < num; i++) { Collider val = HitBuffer[i]; if (!((Object)(object)val == (Object)null)) { Container componentInParent = ((Component)val).GetComponentInParent<Container>(); if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent) && IsUsableContainer(componentInParent, playerID, excluded)) { list.Add(componentInParent); } } } list.Sort((Container a, Container b) => Vector3.SqrMagnitude(((Component)a).transform.position - center).CompareTo(Vector3.SqrMagnitude(((Component)b).transform.position - center))); return list; } private static bool IsUsableContainer(Container container, long playerId, HashSet<string> excluded) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) ZNetView containerNView = GetContainerNView(container); if ((Object)(object)containerNView == (Object)null || !containerNView.IsValid()) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Player>() != (Object)null) { return false; } if (container.GetInventory() == null) { return false; } if (QuickStackPlugin.SkipContainersInUse.Value && container.IsInUse()) { return false; } if (!HasContainerAccess(container, playerId)) { return false; } if (QuickStackPlugin.RespectWards.Value && !CheckWardAccess(((Component)container).transform.position)) { return false; } if (excluded.Count > 0) { string prefabName = Utils.GetPrefabName(((Component)container).gameObject); if (excluded.Contains(Normalize(prefabName)) || excluded.Contains(Normalize(container.m_name))) { return false; } } return true; } private static ZNetView GetContainerNView(Container container) { if ((Object)(object)container == (Object)null) { return null; } try { object? obj = ContainerNViewField?.GetValue(container); return (ZNetView)(((obj is ZNetView) ? obj : null) ?? container.m_rootObjectOverride ?? ((Component)container).GetComponent<ZNetView>()); } catch (Exception ex) { QuickStackPlugin.Log.LogWarning((object)("Не удалось получить ZNetView сундука: " + ex.Message)); return null; } } private static bool HasContainerAccess(Container container, long playerId) { if (ContainerCheckAccessMethod == null) { QuickStackPlugin.Log.LogWarning((object)"Container.CheckAccess не найден; сундук пропущен."); return false; } try { return (bool)ContainerCheckAccessMethod.Invoke(container, new object[1] { playerId }); } catch (Exception ex) { QuickStackPlugin.Log.LogWarning((object)("Не удалось проверить доступ к сундуку: " + ex.Message)); return false; } } private static bool CheckWardAccess(Vector3 position) { //IL_001b: 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) try { if (PrivateAreaCheckAccess4 != null) { return (bool)PrivateAreaCheckAccess4.Invoke(null, new object[4] { position, 0f, false, false }); } if (PrivateAreaCheckAccess3 != null) { return (bool)PrivateAreaCheckAccess3.Invoke(null, new object[3] { position, 0f, false }); } } catch (Exception ex) { QuickStackPlugin.Log.LogWarning((object)("PrivateArea.CheckAccess недоступен: " + ex.Message)); } return true; } private static bool IsInCutscene(Player player) { if (InCutsceneMethod == null) { return false; } try { return (bool)InCutsceneMethod.Invoke(player, null); } catch { return false; } } private static int GetLayerMask() { if (_layerMask != 0) { return _layerMask; } string[] obj = new string[7] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "vehicle", "item" }; int num = 0; string[] array = obj; for (int i = 0; i < array.Length; i++) { int num2 = LayerMask.NameToLayer(array[i]); if (num2 >= 0) { num |= 1 << num2; } } _layerMask = ((num != 0) ? num : (-1)); return _layerMask; } private static Inventory PrepareContainer(Container container) { ZNetView containerNView = GetContainerNView(container); if ((Object)(object)containerNView == (Object)null || !containerNView.IsValid()) { return null; } if (!containerNView.IsOwner()) { containerNView.ClaimOwnership(); Invoke(ContainerLoadMethod, container, "Container.Load"); } return container.GetInventory(); } private static void FinishContainer(Container container) { Inventory inventory = container.GetInventory(); if (inventory != null) { NotifyChanged(inventory); } Invoke(ContainerSaveMethod, container, "Container.Save"); } private static void NotifyChanged(Inventory inventory) { if (inventory == null) { return; } try { if (InventoryChangedNoArgs != null) { InventoryChangedNoArgs.Invoke(inventory, null); } else if (InventoryChangedTwoArgs != null) { InventoryChangedTwoArgs.Invoke(inventory, new object[2] { false, false }); } } catch (Exception ex) { QuickStackPlugin.Log.LogWarning((object)("Inventory.Changed завершился ошибкой: " + ex.Message)); } } private static void Invoke(MethodInfo method, Container container, string label) { if (method == null) { return; } try { method.Invoke(container, null); } catch (Exception ex) { QuickStackPlugin.Log.LogWarning((object)(label + " завершился ошибкой: " + ex.Message)); } } private static bool IsTransferable(ItemData item, HashSet<string> excluded) { if (item == null || item.m_shared == null || item.m_stack <= 0) { return false; } if (QuickStackPlugin.SkipEquipped.Value && item.m_equipped) { return false; } if (QuickStackPlugin.SkipFirstRow.Value && item.m_gridPos.y == 0) { return false; } if (item.m_shared.m_questItem) { return false; } if (!QuickStackPlugin.IncludeNonStackable.Value && item.m_shared.m_maxStackSize <= 1) { return false; } if (excluded.Count > 0) { string value = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : string.Empty); if (excluded.Contains(Normalize(value)) || excluded.Contains(Normalize(item.m_shared.m_name)) || excluded.Contains(Normalize(Localization.instance.Localize(item.m_shared.m_name)))) { return false; } } return true; } private static bool IsSameItem(ItemData a, ItemData b) { if (a == null || b == null || a.m_shared == null || b.m_shared == null) { return false; } if (a == b) { return false; } if (a.m_shared.m_name != b.m_shared.m_name) { return false; } if (a.m_quality != b.m_quality || a.m_variant != b.m_variant) { return false; } if (WorldLevelField != null) { object? value = WorldLevelField.GetValue(a); object value2 = WorldLevelField.GetValue(b); if (!object.Equals(value, value2)) { return false; } } return true; } private static int StackItemIntoContainer(Inventory from, Inventory to, ItemData item) { if (!to.GetAllItems().Any((ItemData existing) => IsSameItem(existing, item))) { return 0; } int num = 0; foreach (ItemData item2 in (from existing in to.GetAllItems() where IsSameItem(existing, item) && existing.m_stack < existing.m_shared.m_maxStackSize select existing).ToList()) { if (item.m_stack <= 0 || !from.ContainsItem(item)) { break; } int num2 = item2.m_shared.m_maxStackSize - item2.m_stack; if (num2 > 0) { int num3 = Mathf.Min(num2, item.m_stack); if (!MoveStack(from, to, item, num3, item2.m_gridPos.x, item2.m_gridPos.y)) { break; } num += num3; } } if (QuickStackPlugin.FillEmptySlots.Value) { int x; int y; while (item.m_stack > 0 && from.ContainsItem(item) && FindEmptySlot(to, out x, out y)) { int num4 = Mathf.Min(item.m_stack, Mathf.Max(1, item.m_shared.m_maxStackSize)); if (!MoveStack(from, to, item, num4, x, y)) { break; } num += num4; } } return num; } private static bool MoveStack(Inventory from, Inventory to, ItemData item, int amount, int x, int y) { if (amount <= 0) { return false; } if (MoveItemToThisMethod != null) { try { if (MoveItemToThisMethod.Invoke(to, new object[5] { from, item, amount, x, y }) is bool result) { return result; } return true; } catch (Exception ex) { QuickStackPlugin.Log.LogWarning((object)("MoveItemToThis недоступен (" + ex.Message + "), переключаюсь на ручной перенос.")); } } return MoveStackFallback(from, to, item, amount, x, y); } private static bool MoveStackFallback(Inventory from, Inventory to, ItemData item, int amount, int x, int y) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) ItemData itemAt = to.GetItemAt(x, y); if (itemAt != null) { if (!IsSameItem(itemAt, item)) { return false; } if (itemAt.m_shared.m_maxStackSize - itemAt.m_stack < amount) { return false; } itemAt.m_stack += amount; } else { ItemData val = item.Clone(); val.m_stack = amount; val.m_gridPos = new Vector2i(x, y); if (!to.AddItem(val)) { return false; } } from.RemoveItem(item, amount); return true; } private static bool FindEmptySlot(Inventory inventory, out int x, out int y) { int width = inventory.GetWidth(); int height = inventory.GetHeight(); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (inventory.GetItemAt(j, i) == null) { x = j; y = i; return true; } } } x = -1; y = -1; return false; } private static HashSet<string> ParseList(string raw) { HashSet<string> hashSet = new HashSet<string>(); if (string.IsNullOrEmpty(raw)) { return hashSet; } string[] array = raw.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = Normalize(array[i]); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } private static string Normalize(string value) { if (!string.IsNullOrEmpty(value)) { return value.Trim().ToLowerInvariant(); } return string.Empty; } private static void Message(Player player, string text) { if (QuickStackPlugin.ShowMessage.Value && !((Object)(object)player == (Object)null)) { ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); } } } internal static class Translations { internal static bool IsRussian { get { try { return Localization.instance != null && string.Equals(Localization.instance.GetSelectedLanguage(), "Russian", StringComparison.OrdinalIgnoreCase); } catch { return false; } } } internal static string NoNearbyChests => Text("No accessible chests nearby", "Рядом нет доступных сундуков"); internal static string NothingToStack => Text("Nothing to stack", "Нечего раскладывать"); internal static string Text(string english, string russian) { if (!IsRussian) { return english; } return russian; } internal static string Stacked(int items, int chests) { return Text($"Stacked {items} item(s) into {chests} chest(s)", $"Разложено {items} шт. по {chests} сундукам"); } } }