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 NearbyStore v1.1.4
plugins/Jarki-NearbyStore/NearbyStore.dll
Decompiled an hour agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NearbyStore")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.4.0")] [assembly: AssemblyInformationalVersion("1.1.4+3916ab94dac7f58ae99d82d33ec6c613cbad8063")] [assembly: AssemblyProduct("NearbyStore")] [assembly: AssemblyTitle("NearbyStore")] [assembly: AssemblyVersion("1.1.4.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 NearbyStore { [BepInPlugin("jarki.nearbystore", "NearbyStore", "1.1.4")] public sealed class Plugin : BaseUnityPlugin { private struct TransferRequest { public Container Chest; public bool Answered; public bool Granted; public bool Loaded; public float Deadline; public int ItemIndex; } private static Plugin instance; private static readonly FieldRef<Container, ZNetView> View = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); private static readonly Func<Container, bool> LoadContainer = AccessTools.MethodDelegate<Func<Container, bool>>(AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Container, long, bool> HasAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null), (object)null, true); private static readonly FieldRef<InventoryGui, ItemData> DragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem"); private static readonly FieldRef<InventoryGrid, List<InventoryElement>> Elements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements"); private static readonly FieldRef<InventoryGui, float> CraftTimer = AccessTools.FieldRefAccess<InventoryGui, float>("m_craftTimer"); private const int MaxRequests = 4; private const int MaxStepsPerFrame = 32; private const float RequestTimeout = 5f; private const float OperationTimeout = 15f; private static readonly long FrameBudgetTicks = Math.Max(1L, Stopwatch.Frequency / 500); private static readonly Predicate<Container> DestroyedContainer = (Container chest) => !Object.op_Implicit((Object)(object)chest); private readonly List<Container> chests = new List<Container>(); private readonly HashSet<Container> outstanding = new HashSet<Container>(); private readonly HashSet<Container> vanillaOutstanding = new HashSet<Container>(); private readonly TransferRequest[] requests = new TransferRequest[4]; private readonly List<ItemData> transferItems = new List<ItemData>(); private readonly Dictionary<InventoryElement, TMP_Text> markers = new Dictionary<InventoryElement, TMP_Text>(); private ConfigEntry<float> radius; private ConfigEntry<KeyboardShortcut> favoriteKey; private Harmony harmony; private GameObject panel; private Button storeButton; private Player actor; private bool running; private bool skippedTimeout; private int index; private int moved; private int nextRequest; private float deadline; private float nextPrune; private InventoryGrid markerGrid; private InventoryElement firstMarkerCell; private int markerCellCount; private Func<ItemData, bool> protectedItem; private void Awake() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown instance = this; radius = ((BaseUnityPlugin)this).Config.Bind<float>("Storage", "Radius", 10f, new ConfigDescription("Nearby chest radius in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>())); favoriteKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "FavoriteShortcut", new KeyboardShortcut((KeyCode)102, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Toggle favorite on the hovered player-inventory stack while inventory is open."); protectedItem = IsProtected; harmony = new Harmony("jarki.nearbystore"); harmony.PatchAll(typeof(Plugin)); } private bool Ready(bool storage = true) { Player localPlayer = Player.m_localPlayer; InventoryGui val = InventoryGui.instance; if (Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead() && !((Character)localPlayer).IsTeleporting() && !((Character)localPlayer).InCutscene() && Object.op_Implicit((Object)(object)val) && InventoryGui.IsVisible() && DragItem.Invoke(val) == null && !val.m_splitDialog.IsActive && !Menu.IsVisible() && !Console.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Minimap.IsOpen() && !TextInput.IsVisible()) { if (storage) { if (!val.IsContainerOpen() && !Object.op_Implicit((Object)(object)localPlayer.GetCurrentCraftingStation()) && CraftTimer.Invoke(val) < 0f && !val.IsSkillsPanelOpen && !val.IsTextPanelOpen && !val.IsTrophisPanelOpen && !val.IsAchievementsPanelOpen && !((Component)val.m_variantDialog).gameObject.activeInHierarchy && !StoreGui.IsVisible() && (!Object.op_Implicit((Object)(object)TextViewer.instance) || !TextViewer.instance.IsVisible()) && !PlayerCustomizaton.IsBarberGuiVisible() && !Hud.IsPieceSelectionVisible() && !Hud.InRadial()) { return !GameCamera.InFreeFly(); } return false; } return true; } return false; } private bool IsProtected(ItemData item) { if (!item.m_shared.m_questItem) { if (Object.op_Implicit((Object)(object)actor)) { return actor.IsEquipActionQueued(item); } return false; } return true; } private void LateUpdate() { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: 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_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime >= nextPrune) { outstanding.RemoveWhere(DestroyedContainer); vanillaOutstanding.RemoveWhere(DestroyedContainer); nextPrune = Time.unscaledTime + 1f; } InventoryGui val = InventoryGui.instance; if (!Object.op_Implicit((Object)(object)val) || !InventoryGui.IsVisible()) { if (Object.op_Implicit((Object)(object)panel) && panel.activeSelf) { panel.SetActive(false); } if (running) { Finish(); } return; } EnsurePanel(val); bool flag = Ready(); if (panel.activeSelf != flag) { panel.SetActive(flag); } ((Selectable)storeButton).interactable = flag && !running; if (running && (!flag || (Object)(object)actor != (Object)(object)Player.m_localPlayer)) { Finish(); } if (Ready(storage: false)) { KeyboardShortcut value = favoriteKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Vector3 pointerPosition = ZInput.pointerPosition; ItemData item = val.m_playerGrid.GetItem(new Vector2i((int)pointerPosition.x, (int)pointerPosition.y)); if (item != null) { bool flag2 = StorageTransfer.ToggleFavorite(item); ((Humanoid)Player.m_localPlayer).GetInventory().m_onChanged?.Invoke(); ((Character)Player.m_localPlayer).Message((MessageType)1, (flag2 ? "Favorited: " : "Unfavorited: ") + Localization.instance.Localize(item.m_shared.m_name), 0, (Sprite)null, false); } } } if (running) { Advance(); } UpdateMarkers(val.m_playerGrid); } private void EnsurePanel(InventoryGui gui) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Expected O, but got Unknown //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Expected O, but got Unknown //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_029b: 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_02ac: Expected O, but got Unknown //IL_02ac: 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_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Expected O, but got Unknown //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Expected O, but got Unknown //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)panel)) { ClearMarkers(); panel = new GameObject("NearbyStore", new Type[1] { typeof(RectTransform) }); RectTransform val = (RectTransform)panel.transform; ((Transform)val).SetParent((Transform)(object)gui.m_player, false); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(1f, 0.5f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(0f, 0.5f); val.anchoredPosition = new Vector2(8f, 0f); val.sizeDelta = new Vector2(56f, 56f); Button craftButton = gui.m_craftButton; Image val3 = (Image)((Selectable)craftButton).targetGraphic; GameObject val4 = new GameObject("StoreButton", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Button) }); RectTransform val5 = (RectTransform)val4.transform; ((Transform)val5).SetParent((Transform)(object)val, false); val5.anchorMin = Vector2.zero; val5.anchorMax = Vector2.one; val2 = (val5.offsetMin = (val5.offsetMax = Vector2.zero)); Image component = val4.GetComponent<Image>(); component.sprite = val3.sprite; component.type = val3.type; component.pixelsPerUnitMultiplier = val3.pixelsPerUnitMultiplier; ((Graphic)component).material = ((Graphic)val3).material; ((Graphic)component).color = ((Graphic)val3).color; storeButton = val4.GetComponent<Button>(); ((Selectable)storeButton).targetGraphic = (Graphic)(object)component; ((Selectable)storeButton).spriteState = ((Selectable)craftButton).spriteState; ((Selectable)storeButton).colors = ((Selectable)craftButton).colors; ((Selectable)storeButton).transition = ((Selectable)craftButton).transition; ((UnityEvent)storeButton.onClick).AddListener(new UnityAction(Begin)); Color color = default(Color); ((Color)(ref color))..ctor(1f, 0.73f, 0.3f); Color color2 = default(Color); ((Color)(ref color2))..ctor(1f, 0.94f, 0.72f); MakeWandPart(val5, "Wand", new Vector2(-3f, -3f), new Vector2(5f, 30f), -45f, color); MakeWandPart(val5, "Tip", new Vector2(8f, 8f), new Vector2(5f, 8f), -45f, color2); MakeWandPart(val5, "SparkVertical", new Vector2(13f, 14f), new Vector2(2f, 11f), 0f, color2); MakeWandPart(val5, "SparkHorizontal", new Vector2(13f, 14f), new Vector2(11f, 2f), 0f, color2); MakeWandPart(val5, "SparkLeft", new Vector2(-13f, 9f), new Vector2(4f, 4f), 45f, color); MakeWandPart(val5, "SparkRight", new Vector2(14f, -10f), new Vector2(3f, 3f), 45f, color); } } private static void MakeWandPart(RectTransform parent, string name, Vector2 position, Vector2 size, float rotation, Color color) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent((Transform)(object)parent, false); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 0.5f); val2.pivot = val3; Vector2 anchorMin = (val2.anchorMax = val3); val2.anchorMin = anchorMin; val2.anchoredPosition = position; val2.sizeDelta = size; ((Transform)val2).localRotation = Quaternion.Euler(0f, 0f, rotation); Image component = val.GetComponent<Image>(); ((Graphic)component).color = color; ((Graphic)component).raycastTarget = false; } private static TMP_Text MakeText(Transform parent, TMP_Text template, string text, float size) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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) GameObject val = new GameObject("NearbyStoreText", new Type[1] { typeof(RectTransform) }); val.SetActive(false); TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).transform.SetParent(parent, false); ((TMP_Text)obj).font = template.font; ((TMP_Text)obj).fontSharedMaterial = template.fontSharedMaterial; ((TMP_Text)obj).fontSize = size; ((Graphic)obj).color = new Color(1f, 0.84f, 0.45f); ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; ((Graphic)obj).raycastTarget = false; ((TMP_Text)obj).text = text; RectTransform rectTransform = ((TMP_Text)obj).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; Vector2 offsetMin = (rectTransform.offsetMax = Vector2.zero); rectTransform.offsetMin = offsetMin; val.SetActive(true); return (TMP_Text)(object)obj; } private void ClearMarkers() { foreach (TMP_Text value in markers.Values) { if (Object.op_Implicit((Object)(object)value)) { Object.Destroy((Object)(object)((Component)value).gameObject); } } markers.Clear(); } private void UpdateMarkers(InventoryGrid grid) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = grid.GetInventory(); if (inventory == null) { return; } List<InventoryElement> list = Elements.Invoke(grid); InventoryElement val = ((list.Count == 0) ? null : list[0]); if ((Object)(object)grid != (Object)(object)markerGrid || list.Count != markerCellCount || (Object)(object)val != (Object)(object)firstMarkerCell) { ClearMarkers(); markerGrid = grid; firstMarkerCell = val; markerCellCount = list.Count; } foreach (InventoryElement item in list) { ItemData itemAt = inventory.GetItemAt(item.Position.x, item.Position.y); bool flag = itemAt != null && StorageTransfer.IsFavorite(itemAt); if (!markers.TryGetValue(item, out var value) || !Object.op_Implicit((Object)(object)value)) { if (!flag) { continue; } value = MakeText(((Component)item).transform, item.m_amount, "F", 16f); value.alignment = (TextAlignmentOptions)257; value.rectTransform.offsetMin = new Vector2(4f, 0f); value.rectTransform.offsetMax = new Vector2(0f, -3f); markers[item] = value; } ((Component)value).gameObject.SetActive(flag); } } private bool Eligible(Container chest) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)chest) && Object.op_Implicit((Object)(object)actor) && !chest.m_autoDestroyEmpty && Object.op_Implicit((Object)(object)((Component)chest).GetComponent<Piece>()) && !Object.op_Implicit((Object)(object)((Component)chest).GetComponent<TombStone>()) && chest.GetInventory() != null && !chest.IsInUse() && (!Object.op_Implicit((Object)(object)chest.m_wagon) || !chest.m_wagon.InUse())) { Vector3 val = ((Component)chest).transform.position - ((Component)actor).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > radius.Value * radius.Value)) { ZNetView val2 = View.Invoke(chest); if (Object.op_Implicit((Object)(object)val2) && val2.IsValid() && HasAccess(chest, actor.GetPlayerID())) { if (chest.m_checkGuardStone) { return PrivateArea.CheckAccess(((Component)chest).transform.position, 0f, false, false); } return true; } return false; } } return false; } private bool HasWork() { List<ItemData> allItems = ((Humanoid)actor).GetInventory().GetAllItems(); foreach (ItemData transferItem in transferItems) { if (allItems.Contains(transferItem) && StorageTransfer.CanTransfer(transferItem, protectedItem)) { return true; } } return false; } private void Begin() { if (running || !Ready()) { return; } actor = Player.m_localPlayer; index = (moved = (nextRequest = 0)); skippedTimeout = false; transferItems.Clear(); if (!StorageTransfer.HasTransferableItems(((Humanoid)actor).GetInventory(), protectedItem)) { Finish(); return; } transferItems.AddRange(((Humanoid)actor).GetInventory().GetAllItems()); chests.Clear(); outstanding.RemoveWhere(DestroyedContainer); vanillaOutstanding.RemoveWhere(DestroyedContainer); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val in array) { if (Eligible(val) && !vanillaOutstanding.Contains(val) && (!outstanding.Contains(val) || val.IsOwner())) { chests.Add(val); } } chests.Sort(delegate(Container a, Container b) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_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) Vector3 val2 = ((Component)a).transform.position - ((Component)actor).transform.position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; val2 = ((Component)b).transform.position - ((Component)actor).transform.position; return sqrMagnitude.CompareTo(((Vector3)(ref val2)).sqrMagnitude); }); deadline = Time.unscaledTime + 15f; running = true; } private void Advance() { if (Time.unscaledTime >= deadline) { Finish(timedOut: true); return; } if (!HasWork()) { Finish(); return; } long num = Stopwatch.GetTimestamp() + FrameBudgetTicks; int num2 = 0; int num3 = 0; while (num3 < 32 && Stopwatch.GetTimestamp() < num) { int num4 = nextRequest; nextRequest = (nextRequest + 1) % requests.Length; ref TransferRequest reference = ref requests[num4]; bool flag = false; if (!Object.op_Implicit((Object)(object)reference.Chest)) { reference = default(TransferRequest); if (index < chests.Count) { Container val = chests[index++]; num3++; flag = true; if (Eligible(val) && !vanillaOutstanding.Contains(val)) { if (val.IsOwner()) { reference.Chest = val; reference.Answered = (reference.Granted = true); reference.Deadline = Time.unscaledTime + 5f; } else if (!outstanding.Contains(val)) { reference.Chest = val; reference.Deadline = Time.unscaledTime + 5f; outstanding.Add(val); View.Invoke(val).InvokeRPC("RPC_RequestStack", new object[1] { actor.GetPlayerID() }); } } } } else if (!reference.Loaded && Time.unscaledTime >= reference.Deadline) { skippedTimeout = true; reference = default(TransferRequest); flag = true; } else if (reference.Answered) { Container chest = reference.Chest; if (!reference.Granted || !Eligible(chest) || vanillaOutstanding.Contains(chest)) { reference = default(TransferRequest); flag = true; } else if (chest.IsOwner()) { if (!reference.Loaded) { LoadContainer(chest); reference.Loaded = true; } if (reference.ItemIndex < transferItems.Count) { ItemData item = transferItems[reference.ItemIndex++]; int num5 = StorageTransfer.Deposit(((Humanoid)actor).GetInventory(), chest.GetInventory(), item, protectedItem); moved += num5; if (num5 > 0) { num3++; } if (num5 > 0 && !HasWork()) { Finish(); return; } } if (reference.ItemIndex >= transferItems.Count) { reference = default(TransferRequest); } flag = true; } else if (reference.Loaded) { reference = default(TransferRequest); flag = true; } } num2 = ((!flag) ? (num2 + 1) : 0); if (num2 >= requests.Length) { break; } } bool flag2 = false; TransferRequest[] array = requests; for (int i = 0; i < array.Length; i++) { if (Object.op_Implicit((Object)(object)array[i].Chest)) { flag2 = true; break; } } if ((!flag2 && index >= chests.Count) || !HasWork()) { Finish(); } } private void Finish(bool timedOut = false) { running = false; Array.Clear(requests, 0, requests.Length); bool flag = timedOut || skippedTimeout; if (Object.op_Implicit((Object)(object)actor)) { ((Character)actor).Message((MessageType)1, flag ? ("Stacked " + moved + " items nearby; some chests timed out. Retry to continue.") : ((moved > 0) ? ("Stacked " + moved + " items nearby.") : "Nothing stacked: no room in matching chests or eligible items."), 0, (Sprite)null, false); } actor = null; chests.Clear(); transferItems.Clear(); } private bool HasRequest(Container chest) { TransferRequest[] array = requests; for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i].Chest == (Object)(object)chest) { return true; } } return false; } [HarmonyPatch(typeof(Container), "StackAll")] [HarmonyPrefix] private static bool VanillaStack(Container __instance) { if (!Object.op_Implicit((Object)(object)instance)) { return true; } if (instance.outstanding.Contains(__instance) || instance.HasRequest(__instance) || instance.vanillaOutstanding.Contains(__instance)) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)1, "Waiting for this chest's previous stack response.", 0, (Sprite)null, false); } return false; } instance.vanillaOutstanding.Add(__instance); return true; } [HarmonyPatch(typeof(Container), "RPC_StackResponse")] [HarmonyPrefix] private static bool StackResponse(Container __instance, bool granted) { if (!Object.op_Implicit((Object)(object)instance)) { return true; } if (instance.vanillaOutstanding.Remove(__instance)) { return true; } if (!instance.outstanding.Remove(__instance)) { return true; } if (instance.running) { for (int i = 0; i < instance.requests.Length; i++) { ref TransferRequest reference = ref instance.requests[i]; if (!((Object)(object)reference.Chest != (Object)(object)__instance) && !reference.Answered) { reference.Answered = true; reference.Granted = granted; break; } } } return false; } private void OnDestroy() { if (running) { Finish(); } Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if (Object.op_Implicit((Object)(object)panel)) { Object.Destroy((Object)(object)panel); } ClearMarkers(); if ((Object)(object)instance == (Object)(object)this) { instance = null; } } } internal static class StorageTransfer { internal const string FavoriteKey = "jarki.nearbystore.favorite"; internal static bool IsFavorite(ItemData item) { return item.m_customData.ContainsKey("jarki.nearbystore.favorite"); } internal static bool ToggleFavorite(ItemData item) { if (item.m_customData.Remove("jarki.nearbystore.favorite")) { return false; } item.m_customData["jarki.nearbystore.favorite"] = "1"; return true; } internal static bool CanTransfer(ItemData item, Func<ItemData, bool> protectedItem) { if (!item.m_equipped && !IsFavorite(item)) { if (protectedItem != null) { return !protectedItem(item); } return true; } return false; } internal static bool HasTransferableItems(Inventory source, Func<ItemData, bool> protectedItem = null) { foreach (ItemData allItem in source.GetAllItems()) { if (CanTransfer(allItem, protectedItem)) { return true; } } return false; } internal static int Deposit(Inventory source, Inventory destination, ItemData item, Func<ItemData, bool> protectedItem = null) { if (source == destination || !source.GetAllItems().Contains(item) || !CanTransfer(item, protectedItem) || !HasCapacity(destination, item)) { return 0; } int stack = item.m_stack; destination.MoveItemToThis(source, item); if (!source.GetAllItems().Contains(item)) { return stack; } return stack - item.m_stack; } private static bool HasCapacity(Inventory destination, ItemData item) { List<ItemData> allItems = destination.GetAllItems(); bool flag = allItems.Count < destination.GetWidth() * destination.GetHeight(); foreach (ItemData item2 in allItems) { if (!(item2.m_shared.m_name != item.m_shared.m_name)) { if (flag) { return true; } if (item.m_shared.m_maxStackSize > 1 && item2.m_quality == item.m_quality && item2.m_worldLevel == item.m_worldLevel && item2.m_stack < item2.m_shared.m_maxStackSize) { return true; } } } return false; } } }