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 NearbyStorage v1.0.1
Landoria.NearbyStorage.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Landoria.Shared; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Landoria.NearbyStorage")] [assembly: AssemblyDescription("Stacks nearby items and crafts from nearby chests.")] [assembly: AssemblyCompany("Landoria")] [assembly: AssemblyProduct("Landoria.NearbyStorage")] [assembly: ComVisible(false)] [assembly: AssemblyFileVersion("1.0.1")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.1.24460")] [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 Landoria.Shared { internal static class ConfigWatcher { private const int ReloadDelayMilliseconds = 250; private const int MaximumReloadAttempts = 5; private static ConfigFile config; private static string configPath; private static ManualLogSource logger; private static FileSystemWatcher watcher; private static long lastChangeTicks; private static int reloadPending; private static int reloadAttempts; private static long ignoredWriteTicks; private static string displayName; private static Action restoreDefaults; private static Action applyConfiguration; internal static void Initialize(ConfigFile configFile, ManualLogSource logSource, string configurationDisplayName, Action restoreDefaultsAction, Action applyConfigurationAction = null) { Dispose(); config = configFile; logger = logSource; displayName = configurationDisplayName; restoreDefaults = restoreDefaultsAction; applyConfiguration = applyConfigurationAction; configPath = Path.GetFullPath(config.ConfigFilePath); watcher = new FileSystemWatcher(Path.GetDirectoryName(configPath), Path.GetFileName(configPath)); watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime; watcher.Changed += OnChanged; watcher.Created += OnChanged; watcher.Deleted += OnChanged; watcher.Renamed += OnRenamed; watcher.EnableRaisingEvents = true; } internal static void IgnoreCurrentFileVersion() { if (string.IsNullOrEmpty(configPath) || !File.Exists(configPath)) { return; } try { Interlocked.Exchange(ref ignoredWriteTicks, File.GetLastWriteTimeUtc(configPath).Ticks); Interlocked.Exchange(ref reloadPending, 0); } catch (IOException) { ManualLogSource obj = logger; if (obj != null) { obj.LogDebug((object)"Could not mark the internal configuration write."); } } } internal static void Update() { if (Volatile.Read(in reloadPending) == 0 || !ReloadDelayElapsed()) { return; } Interlocked.Exchange(ref reloadPending, 0); try { bool flag = !File.Exists(configPath); if (flag) { restoreDefaults?.Invoke(); } else { config.Reload(); } applyConfiguration?.Invoke(); reloadAttempts = 0; logger.LogInfo((object)(flag ? "Recreated the deleted configuration with default values." : "Reloaded configuration after a file change.")); ShowReloadMessage(flag); } catch (Exception exception) { RetryReload(exception); } } internal static void Dispose() { if (watcher != null) { watcher.EnableRaisingEvents = false; watcher.Dispose(); watcher = null; } Interlocked.Exchange(ref reloadPending, 0); Interlocked.Exchange(ref ignoredWriteTicks, 0L); reloadAttempts = 0; displayName = null; restoreDefaults = null; applyConfiguration = null; } private static void OnChanged(object sender, FileSystemEventArgs eventArgs) { QueueReload(); } private static void OnRenamed(object sender, RenamedEventArgs eventArgs) { QueueReload(); } private static void QueueReload() { if (!IsIgnoredWrite()) { Interlocked.Exchange(ref lastChangeTicks, DateTime.UtcNow.Ticks); Interlocked.Exchange(ref reloadPending, 1); reloadAttempts = 0; } } private static bool IsIgnoredWrite() { try { long num = (File.Exists(configPath) ? File.GetLastWriteTimeUtc(configPath).Ticks : 0); return num != 0L && num == Interlocked.Read(in ignoredWriteTicks); } catch (IOException) { return false; } } private static bool ReloadDelayElapsed() { return DateTime.UtcNow.Ticks - Interlocked.Read(in lastChangeTicks) >= 2500000; } private static void RetryReload(Exception exception) { reloadAttempts++; logger.LogWarning((object)("Configuration reload failed: " + exception.Message)); if (reloadAttempts < 5) { Interlocked.Exchange(ref lastChangeTicks, DateTime.UtcNow.Ticks); Interlocked.Exchange(ref reloadPending, 1); } } private static void ShowReloadMessage(bool recreated) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, recreated ? (displayName + " configuration restored to defaults.") : (displayName + " configuration reloaded."), 0, (Sprite)null, false); } } } } namespace Landoria.NearbyStorage { [HarmonyPatch(typeof(Player), "ConsumeResources", new Type[] { typeof(Requirement[]), typeof(int), typeof(int), typeof(int) })] internal static class BuildingDebitPatch { private static bool Prefix(Player __instance, Requirement[] requirements, int qualityLevel) { if (!BuildingState.Matches(__instance, requirements, qualityLevel)) { return true; } BuildingState.Consume(__instance); return false; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class BuildingPlacementPatch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if (BuildingState.Prepare(__instance, piece)) { return true; } __result = false; return false; } private static void Postfix(bool __result) { if (!__result) { BuildingState.Reset(); } } private static Exception Finalizer(Exception __exception) { if (__exception != null) { BuildingState.Reset(); } return __exception; } } internal static class BuildingPlan { internal static bool IsBuildPiece(Player player, Piece piece) { if ((Object)(object)player != (Object)null && ((Character)player).InPlaceMode()) { return (Object)(object)piece != (Object)null; } return false; } internal static CraftPlan Build(Player player, Piece piece) { if (!CanBuild(player, piece)) { return null; } CraftPlan craftPlan = new CraftPlan(); StorageSupply storageSupply = new StorageSupply(player); Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; int amount = val.GetAmount(0); amount = storageSupply.AllocateAnyQuality(craftPlan, name, amount); if (amount > 0) { return null; } } } return craftPlan; } private static bool CanBuild(Player player, Piece piece) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (IsBuildPiece(player, piece) && (piece.m_dlc.Length == 0 || DLCMan.instance.IsDLCInstalled(piece.m_dlc))) { if (!((Object)(object)piece.m_craftingStation == (Object)null) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)player).transform.position))) { return ZoneSystem.instance.GetGlobalKey((GlobalKeys)27); } return true; } return false; } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class BuildingRequirementsPatch { private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if (!__result && ((int)mode == 0 || (int)mode == 2) && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && NearbyStorageActionInput.IsHeld() && BuildingPlan.IsBuildPiece(__instance, piece)) { __result = BuildingPlan.Build(__instance, piece) != null; } } } internal static class BuildingState { private static CraftPlan _plan; private static Player _player; private static Piece _piece; internal static bool Matches(Player player, Requirement[] requirements, int qualityLevel) { if (_plan != null && (Object)(object)player == (Object)(object)_player && qualityLevel == 0) { return requirements == _piece.m_resources; } return false; } internal static bool Prepare(Player player, Piece piece) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) Reset(); if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !NearbyStorageActionInput.IsHeld() || !BuildingPlan.IsBuildPiece(player, piece) || player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey())) { return true; } CraftPlan craftPlan = BuildingPlan.Build(player, piece); if (craftPlan == null || !craftPlan.ClaimSources(player) || !craftPlan.StillAvailable(player)) { return false; } _player = player; _piece = piece; _plan = craftPlan; return true; } internal static void Consume(Player player) { if ((Object)(object)player != (Object)(object)_player || _plan == null) { return; } try { _plan.Consume(); } finally { Reset(); } } internal static void Reset() { _plan = null; _player = null; _piece = null; } } internal static class BuildingUiRefresh { private static readonly MethodInfo RefreshHudIcons = AccessTools.Method(typeof(Hud), "UpdatePieceBuildStatusAll", (Type[])null, (Type[])null); private static bool _lastHeld; internal static void Update() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !((Character)localPlayer).InPlaceMode()) { _lastHeld = false; return; } bool flag = NearbyStorageActionInput.IsHeld(); if (flag == _lastHeld) { return; } _lastHeld = flag; try { if ((Object)(object)Hud.instance != (Object)null && RefreshHudIcons != null) { RefreshHudIcons.Invoke(Hud.instance, new object[2] { localPlayer.GetBuildPieces(), localPlayer }); } BuildUiPieceButton[] array = Object.FindObjectsByType<BuildUiPieceButton>((FindObjectsSortMode)0); foreach (BuildUiPieceButton val in array) { if (((Behaviour)val).isActiveAndEnabled && (Object)(object)val.Piece != (Object)null) { val.UpdateRequirements(); } } } catch (Exception ex) { Debug.LogError((object)("Nearby Storage build icon refresh failed: " + ex)); } } internal static void Reset() { _lastHeld = false; } } internal sealed class ModConfigFile { private const float DefaultRadius = 60f; internal ConfigEntry<float> Radius { get; } internal ConfigEntry<bool> KeepOneIngredientPerChest { get; } internal ConfigEntry<KeyboardShortcut> NearbyStorageShortcut { get; } internal ModConfigFile(ConfigFile config) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) Radius = config.Bind<float>("General", "SearchRadius", 60f, new ConfigDescription("Radius around the player for nearby storage and ground items, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 100f), Array.Empty<object>())); KeepOneIngredientPerChest = config.Bind<bool>("General", "KeepOneIngredientPerChest", true, "Keep at least one of each item type in every storage container when using the nearby storage shortcut."); NearbyStorageShortcut = config.Bind<KeyboardShortcut>("Controls", "NearbyStorageShortcut", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Hold this shortcut to use nearby storage while crafting, building, refueling, or feeding."); } internal void RestoreDefaults(ConfigFile config) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { Radius.Value = 60f; KeepOneIngredientPerChest.Value = true; NearbyStorageShortcut.Value = new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()); } finally { config.SaveOnConfigSet = saveOnConfigSet; } config.Save(); ConfigWatcher.IgnoreCurrentFileVersion(); } } internal static class NearbyStorageActionInput { internal static bool IsHeld() { //IL_0024: 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_002c: 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_0054: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Instance?.Settings == null) { return false; } KeyboardShortcut value = Plugin.Instance.Settings.NearbyStorageShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKey(((KeyboardShortcut)(ref value)).MainKey, true)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!ZInput.GetKey(modifier, true)) { return false; } } return true; } } internal static class ButtonHalo { private static Image _craft; private static Sprite _glowSprite; internal static void Update() { bool flag = InventoryGui.IsVisible() && (Object)(object)Player.m_localPlayer != (Object)null && NearbyStorageActionInput.IsHeld(); InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null) { Clear(); } else { Set(ref _craft, instance.m_craftButton, flag && ((Selectable)instance.m_craftButton).interactable); } } internal static void Clear() { if ((Object)(object)_craft != (Object)null) { ((Behaviour)_craft).enabled = false; } } internal static void Dispose() { if ((Object)(object)_craft != (Object)null) { Object.Destroy((Object)(object)((Component)_craft).gameObject); } _craft = null; _glowSprite = null; } private static void Set(ref Image glow, Button button, bool active) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)button == (Object)null || (Object)(object)((Selectable)button).targetGraphic == (Object)null) { if ((Object)(object)glow != (Object)null) { ((Behaviour)glow).enabled = false; } return; } if (!active || !((Component)button).gameObject.activeInHierarchy) { if ((Object)(object)glow != (Object)null) { ((Behaviour)glow).enabled = false; } return; } if ((Object)(object)_glowSprite == (Object)null) { _glowSprite = FindGlowSprite(); if ((Object)(object)_glowSprite == (Object)null) { return; } } if ((Object)(object)glow == (Object)null || (Object)(object)((Component)glow).transform.parent != (Object)(object)((Component)((Selectable)button).targetGraphic).transform) { glow = CreateGlow(glow, button); } ((Behaviour)glow).enabled = true; float num = 0.5f + 0.15f * Mathf.Sin(Time.unscaledTime * 3f); ((Graphic)glow).color = new Color(1f, 61f / 85f, 0.35686275f, num); } private static Sprite FindGlowSprite() { Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>(); foreach (Sprite val in array) { if (((Object)val).name == "button_glow") { return val; } } return null; } private static Image CreateGlow(Image existingGlow, Button button) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)existingGlow != (Object)null) { Object.Destroy((Object)(object)((Component)existingGlow).gameObject); } GameObject val = new GameObject("NearbyStorageGlow", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(((Component)((Selectable)button).targetGraphic).transform, false); val.transform.SetAsFirstSibling(); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; Image component = val.GetComponent<Image>(); component.sprite = _glowSprite; component.type = (Type)1; ((Graphic)component).raycastTarget = false; return component; } } [HarmonyPatch(typeof(Inventory), "ItemCheated", new Type[] { typeof(Requirement[]), typeof(int), typeof(bool) })] internal static class CheatedIngredientPatch { private static void Postfix(Inventory __instance, ref bool __result) { if (!__result && CraftState.Armed && CraftState.Plan != null && (Object)(object)Player.m_localPlayer != (Object)null && __instance == ((Humanoid)Player.m_localPlayer).GetInventory()) { __result = CraftState.Plan.HasCheatedIngredient(); } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftCancelPressed")] internal static class CraftCancelPatch { private static void Postfix() { CraftState.Reset(); } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] internal static class CraftClickPatch { private static bool Prefix(InventoryGui __instance) { return CraftState.Arm(__instance); } private static void Postfix(InventoryGui __instance) { CraftState.ResetIfNoTimer(__instance); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class CraftCompletionPatch { private static bool Prefix(InventoryGui __instance, Player player) { return CraftState.Prepare(__instance, player); } private static void Postfix() { CraftState.Reset(); } } internal sealed class CraftPlan { internal readonly List<Withdrawal> Withdrawals = new List<Withdrawal>(); internal ItemData SingleItem; internal int SingleNeed; internal int SingleExtra; internal static CraftPlan Build(Player player, Recipe recipe, int quality, int multiplier) { if (!CanPlan(player, recipe, multiplier)) { return null; } CraftPlan craftPlan = new CraftPlan(); StorageSupply supply = new StorageSupply(player); CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); bool flag = false; Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if (!Relevant(val, currentCraftingStation)) { continue; } int num = val.GetAmount(quality) * multiplier; if (num <= 0) { continue; } if (TryRequirement(craftPlan, supply, val, num, recipe.m_requireOnlyOneIngredient)) { flag = true; if (recipe.m_requireOnlyOneIngredient) { craftPlan.SingleNeed = num; craftPlan.SingleExtra = val.m_extraAmountOnlyOneIngredient; break; } } else if (!recipe.m_requireOnlyOneIngredient) { return null; } } if (!(!recipe.m_requireOnlyOneIngredient || flag)) { return null; } return craftPlan; } private static bool CanPlan(Player player, Recipe recipe, int multiplier) { if ((Object)(object)player != (Object)null && (Object)(object)recipe != (Object)null) { return multiplier >= 1; } return false; } private static bool TryRequirement(CraftPlan plan, StorageSupply supply, Requirement requirement, int need, bool single) { string name = requirement.m_resItem.m_itemData.m_shared.m_name; int maxQuality = requirement.m_resItem.m_itemData.m_shared.m_maxQuality; for (int i = 1; i <= maxQuality; i++) { if (supply.Available(plan, name, i) >= need) { int num = supply.Allocate(plan, name, i, need); if (single) { plan.SingleItem = FindItem(plan, name, i); } return num == 0; } } return false; } private static ItemData FindItem(CraftPlan plan, string name, int quality) { foreach (Withdrawal withdrawal in plan.Withdrawals) { if (withdrawal.Name != name || withdrawal.Quality != quality) { continue; } if ((Object)(object)withdrawal.Drop != (Object)null) { return withdrawal.GroundItem; } foreach (ItemData allItem in withdrawal.Inventory.GetAllItems()) { if (allItem.m_shared.m_name == name && allItem.m_quality == quality) { return allItem; } } } return null; } private static bool Relevant(Requirement requirement, CraftingStation station) { if ((Object)(object)requirement.m_resItem != (Object)null) { if (!((Object)(object)station == (Object)null) || requirement.m_upgraderResource) { if ((Object)(object)station != (Object)null) { return station.m_upgrader == requirement.m_upgraderResource; } return false; } return true; } return false; } internal bool ClaimSources(Player player) { foreach (Withdrawal withdrawal in Withdrawals) { if ((Object)(object)withdrawal.Chest != (Object)null && !StorageLocator.TryClaimAndLoad(withdrawal.Chest, player)) { return false; } if ((Object)(object)withdrawal.Drop != (Object)null && !GroundSource.TryClaim(withdrawal.Drop, player, withdrawal.GroundItem, PlannedForDrop(withdrawal))) { return false; } } return true; } internal bool StillAvailable(Player player) { foreach (Withdrawal withdrawal in Withdrawals) { if ((Object)(object)withdrawal.Drop != (Object)null) { if (!GroundSource.TryClaim(withdrawal.Drop, player, withdrawal.GroundItem, PlannedForDrop(withdrawal))) { return false; } continue; } if ((Object)(object)withdrawal.Chest != (Object)null && !StorageLocator.Eligible(withdrawal.Chest, player, StorageLocator.CurrentContainer(), Plugin.Instance.Settings.Radius.Value)) { return false; } int num = 0; foreach (Withdrawal withdrawal2 in Withdrawals) { if (withdrawal2.Inventory == withdrawal.Inventory && withdrawal2.Name == withdrawal.Name && withdrawal2.Quality == withdrawal.Quality) { num += withdrawal2.Amount; } } if (withdrawal.Inventory.CountItems(withdrawal.Name, withdrawal.Quality, true) < num) { return false; } if ((Object)(object)withdrawal.Chest != (Object)null && Plugin.Instance.Settings.KeepOneIngredientPerChest.Value && withdrawal.Inventory.CountItems(withdrawal.Name, -1, false) - PlannedForName(withdrawal) < 1) { return false; } } return true; } private int PlannedForName(Withdrawal step) { int num = 0; foreach (Withdrawal withdrawal in Withdrawals) { if (withdrawal.Inventory == step.Inventory && withdrawal.Name == step.Name) { num += withdrawal.Amount; } } return num; } private int PlannedForDrop(Withdrawal step) { int num = 0; foreach (Withdrawal withdrawal in Withdrawals) { if ((Object)(object)withdrawal.Drop == (Object)(object)step.Drop) { num += withdrawal.Amount; } } return num; } internal void Consume() { foreach (Withdrawal withdrawal in Withdrawals) { if ((Object)(object)withdrawal.Drop == (Object)null) { withdrawal.Inventory.RemoveItem(withdrawal.Name, withdrawal.Amount, withdrawal.Quality, true); continue; } for (int i = 0; i < withdrawal.Amount; i++) { if (!GroundSource.RemoveOne(withdrawal.Drop, Player.m_localPlayer, withdrawal.GroundItem)) { break; } } } } internal bool HasCheatedIngredient() { foreach (Withdrawal withdrawal in Withdrawals) { if (((Object)(object)withdrawal.Drop != (Object)null) ? withdrawal.GroundItem.m_cheated : withdrawal.Inventory.ItemCheated(withdrawal.Name, withdrawal.Quality, true)) { return true; } } return false; } } internal static class CraftState { private static readonly FieldInfo SelectedField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); private static readonly FieldInfo RecipeField = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe"); private static readonly FieldInfo UpgradeField = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem"); private static readonly FieldInfo MultiField = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting"); private static readonly FieldInfo TouchField = AccessTools.Field(typeof(InventoryGui), "m_touchMultiCrafting"); private static readonly FieldInfo TimerField = AccessTools.Field(typeof(InventoryGui), "m_craftTimer"); private static readonly PropertyInfo SelectedRecipe = AccessTools.Property(SelectedField.FieldType, "Recipe"); private static readonly PropertyInfo SelectedItem = AccessTools.Property(SelectedField.FieldType, "ItemData"); internal static bool Armed { get; private set; } internal static bool Consuming { get; private set; } internal static CraftPlan Plan { get; private set; } internal static bool Checking { get { if ((Object)(object)Plugin.Instance != (Object)null && InventoryGui.IsVisible()) { if (!NearbyStorageActionInput.IsHeld()) { return Armed; } return true; } return false; } } internal static bool Arm(InventoryGui gui) { Reset(); if (!NearbyStorageActionInput.IsHeld()) { return true; } object value = SelectedField.GetValue(gui); object? value2 = SelectedRecipe.GetValue(value); Recipe val = (Recipe)((value2 is Recipe) ? value2 : null); object? value3 = SelectedItem.GetValue(value); ItemData val2 = (ItemData)((value3 is ItemData) ? value3 : null); if ((Object)(object)val == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } int multiplier = ((val2 != null || (!ZInput.GetButton("AltPlace") && !ZInput.GetButton("JoyLStick") && !(bool)TouchField.GetValue(gui))) ? 1 : gui.m_multiCraftAmount); int quality = ((val2 == null) ? 1 : (val2.m_quality + 1)); if ((val.m_requireOnlyOneIngredient || !FreeCraft(Player.m_localPlayer)) && CraftPlan.Build(Player.m_localPlayer, val, quality, multiplier) == null) { return false; } Armed = true; return true; } internal static bool Prepare(InventoryGui gui, Player player) { if (!Armed) { return true; } object? value = RecipeField.GetValue(gui); Recipe val = (Recipe)((value is Recipe) ? value : null); object? value2 = UpgradeField.GetValue(gui); ItemData val2 = (ItemData)((value2 is ItemData) ? value2 : null); int quality = ((val2 == null) ? 1 : (val2.m_quality + 1)); int multiplier = ((!(bool)MultiField.GetValue(gui)) ? 1 : gui.m_multiCraftAmount); if (FreeCraft(player)) { if ((Object)(object)val != (Object)null) { if (val.m_requireOnlyOneIngredient) { return CraftPlan.Build(player, val, quality, multiplier) != null; } return true; } return false; } Plan = CraftPlan.Build(player, val, quality, multiplier); if (Plan == null || !Plan.ClaimSources(player)) { return false; } Plan = CraftPlan.Build(player, val, quality, multiplier); if (Plan != null) { return Plan.StillAvailable(player); } return false; } internal static void Consume() { if (Plan == null || Consuming) { return; } Consuming = true; try { Plan.Consume(); } finally { Consuming = false; Plan = null; } } internal static void ResetIfNoTimer(InventoryGui gui) { if ((float)TimerField.GetValue(gui) < 0f) { Reset(); } } internal static void Reset() { Armed = false; Consuming = false; Plan = null; } internal static bool FreeCraft(Player player) { if (!player.NoCostCheat()) { return ZoneSystem.instance.GetGlobalKey((GlobalKeys)25); } return true; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] internal static class CraftTooltipPatch { private static void Prefix(InventoryGui __instance, out string __state) { UITooltip component = ((Component)__instance.m_craftButton).GetComponent<UITooltip>(); __state = (((Object)(object)component == (Object)null) ? null : component.m_text); } private static void Postfix(InventoryGui __instance, string __state) { //IL_003d: 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) UITooltip component = ((Component)__instance.m_craftButton).GetComponent<UITooltip>(); if (!((Object)(object)component == (Object)null) && !(component.m_text == __state)) { string text = component.m_text; component.m_text = __state; component.Set(component.m_topic, text, (RectTransform)null, default(Vector2)); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] internal static class InventoryClosePatch { private static void Postfix() { CraftState.Reset(); ButtonHalo.Clear(); } } [HarmonyPatch(typeof(InventoryGui), "Update")] internal static class RecipeListRefreshPatch { private static readonly MethodInfo UpdatePanel = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", (Type[])null, (Type[])null); private static InventoryGui _lastGui; private static bool _lastChecking; private static void Postfix(InventoryGui __instance) { if ((Object)(object)_lastGui != (Object)(object)__instance) { _lastGui = __instance; _lastChecking = false; } bool checking = CraftState.Checking; if (checking == _lastChecking) { return; } _lastChecking = checking; if (!InventoryGui.IsVisible() || UpdatePanel == null) { return; } try { UpdatePanel.Invoke(__instance, new object[1] { false }); } catch (Exception ex) { Debug.LogError((object)("Nearby Storage recipe refresh failed: " + ex)); } } internal static void Reset() { _lastGui = null; _lastChecking = false; } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] internal static class RequirementDisplayPatch { private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, bool __result) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) if (!__result || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)req?.m_resItem == (Object)null) { return; } bool num = craft && CraftState.Checking; bool flag = ((Character)player).InPlaceMode() && NearbyStorageActionInput.IsHeld(); if (!num && !flag) { return; } string name = req.m_resItem.m_itemData.m_shared.m_name; if (new StorageSupply(player).Available(null, name, -1) >= req.GetAmount(quality) * craftMultiplier) { Transform val = elementRoot.Find("res_amount"); if ((Object)(object)val != (Object)null) { ((Graphic)((Component)val).GetComponent<TMP_Text>()).color = Color.white; } } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class RequirementPatch { private static void Postfix(Player __instance, Recipe recipe, bool discover, int qualityLevel, int amount, ref bool __result) { if (!(__result || discover) && CraftState.Checking && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && __instance.RequiredCraftingStation(recipe, qualityLevel, true)) { string dlc = recipe.m_item.m_itemData.m_shared.m_dlc; if (dlc.Length <= 0 || DLCMan.instance.IsDLCInstalled(dlc)) { __result = CraftPlan.Build(__instance, recipe, qualityLevel, amount) != null; } } } } [HarmonyPatch(typeof(Player), "ConsumeResources", new Type[] { typeof(Requirement[]), typeof(int), typeof(int), typeof(int) })] internal static class ResourceDebitPatch { private static bool Prefix(Player __instance) { if (!CraftState.Armed || CraftState.Plan == null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } CraftState.Consume(); return false; } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(bool) })] internal static class SingleDebitPatch { private static bool Prefix(Inventory __instance) { if (!CraftState.Armed || CraftState.Plan == null || CraftState.Consuming || (Object)(object)Player.m_localPlayer == (Object)null || __instance != ((Humanoid)Player.m_localPlayer).GetInventory()) { return true; } CraftState.Consume(); return false; } } [HarmonyPatch(typeof(Player), "GetFirstRequiredItem")] internal static class SingleIngredientPatch { private static void Postfix(Player __instance, Recipe recipe, int qualityLevel, int craftMultiplier, ref ItemData __result, ref int amount, ref int extraAmount) { if (__result == null && CraftState.Checking && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { CraftPlan craftPlan = CraftPlan.Build(__instance, recipe, qualityLevel, craftMultiplier); if (craftPlan != null) { __result = craftPlan.SingleItem; amount = craftPlan.SingleNeed; extraAmount = craftPlan.SingleExtra; } } } } internal sealed class Withdrawal { internal Inventory Inventory; internal Container Chest; internal ItemDrop Drop; internal ItemData GroundItem; internal ItemData SelectedItem; internal string Name; internal int Quality; internal int Amount; } [HarmonyPatch(typeof(CookingStation), "OnInteract")] internal static class CookingFeedPatch { private static void Prefix(Humanoid user) { FeedContext.Begin(user); } private static void Finalizer() { FeedContext.Reset(); } } [HarmonyPatch(typeof(CookingStation), "FindCookableItem")] internal static class CookingInputPatch { private static void Postfix(CookingStation __instance, Inventory inventory, ref ItemData __result) { if (__result == null) { __result = FeedContext.FindConversion(inventory, __instance.m_conversion, (ItemConversion conversion) => conversion.m_from); } } } internal static class FeedContext { private static Player _player; private static Container _chest; private static ItemDrop _drop; private static ItemData _item; internal static void Begin(Humanoid user) { Reset(); if ((Object)(object)user == (Object)(object)Player.m_localPlayer && NearbyStorageActionInput.IsHeld()) { _player = Player.m_localPlayer; } } internal static ItemData Find(Inventory inventory, IEnumerable<string> names) { if (names == null) { return null; } List<string> candidates = new List<string>(names); return FindStored(inventory, delegate(Inventory source) { foreach (string item2 in candidates) { if (!string.IsNullOrEmpty(item2)) { ItemData item = source.GetItem(item2, -1, false); if (StorageSupply.CanWithdrawOne(source, item)) { return item; } } } return (ItemData)null; }, (ItemData candidate) => candidates.Contains(candidate.m_shared.m_name)); } internal static ItemData FindConversion<T>(Inventory inventory, IEnumerable<T> conversions, Func<T, ItemDrop> sourceItem) { List<string> list = new List<string>(); foreach (T conversion in conversions) { ItemDrop val = sourceItem(conversion); if ((Object)(object)val != (Object)null) { list.Add(val.m_itemData.m_shared.m_name); } } return Find(inventory, list); } internal static ItemData FindAmmo(Inventory inventory, string ammoType, string prefab) { Func<ItemData, bool> matches = (ItemData candidate) => ((int)candidate.m_shared.m_itemType == 9 || (int)candidate.m_shared.m_itemType == 23 || (int)candidate.m_shared.m_itemType == 2) && candidate.m_shared.m_ammoType == ammoType && (prefab == null || ((Object)candidate.m_dropPrefab).name == prefab); return FindStored(inventory, delegate(Inventory source) { ItemData ammoItem = source.GetAmmoItem(ammoType, prefab); if (StorageSupply.CanWithdrawOne(source, ammoItem)) { return ammoItem; } foreach (ItemData allItem in source.GetAllItems()) { if (matches(allItem) && StorageSupply.CanWithdrawOne(source, allItem)) { return allItem; } } return (ItemData)null; }, matches); } internal static ItemData FindByPriority(Inventory inventory, IEnumerable<string> names) { if ((Object)(object)_player == (Object)null || inventory != ((Humanoid)_player).GetInventory() || names == null) { return null; } foreach (string name in names) { if (!string.IsNullOrEmpty(name)) { ItemData item = inventory.GetItem(name, -1, false); if (item != null) { return item; } ItemData val = FindStored(inventory, delegate(Inventory source) { ItemData item2 = source.GetItem(name, -1, false); return (!StorageSupply.CanWithdrawOne(source, item2)) ? null : item2; }, (ItemData candidate) => candidate.m_shared.m_name == name); if (val != null) { return val; } } } return null; } internal static bool IsBorrowed(Inventory inventory, ItemData item) { if ((Object)(object)_player != (Object)null && inventory == ((Humanoid)_player).GetInventory()) { return item == _item; } return false; } internal static bool RemoveBorrowed(Inventory inventory, ItemData item, int amount, ref bool result) { if (!IsBorrowed(inventory, item)) { return true; } result = Withdraw(amount); return false; } internal static bool Withdraw(int amount) { if ((Object)(object)_drop != (Object)null) { if (amount == 1) { return GroundSource.RemoveOne(_drop, _player, _item); } return false; } if ((Object)(object)_chest == (Object)null || _item == null || amount != 1 || !StorageLocator.Eligible(_chest, _player, StorageLocator.CurrentContainer(), Plugin.Instance.Settings.Radius.Value)) { return false; } ZNetView val = StorageLocator.View(_chest); if ((Object)(object)val == (Object)null || !val.IsOwner() || !_chest.GetInventory().ContainsItem(_item) || !StorageSupply.CanWithdrawOne(_chest.GetInventory(), _item)) { return false; } return _chest.GetInventory().RemoveOneItem(_item); } internal static void Reset() { _player = null; _chest = null; _drop = null; _item = null; } private static ItemData FindStored(Inventory inventory, Func<Inventory, ItemData> selectChest, Func<ItemData, bool> matchesGround) { if ((Object)(object)_player == (Object)null || inventory != ((Humanoid)_player).GetInventory()) { return null; } Withdrawal withdrawal = new StorageSupply(_player).FindStored(selectChest, matchesGround); if (withdrawal == null) { return null; } _chest = withdrawal.Chest; _drop = withdrawal.Drop; _item = withdrawal.SelectedItem; return _item; } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData), typeof(int) })] internal static class FeedRemoveAmountPatch { private static bool Prefix(Inventory __instance, ItemData item, int amount, ref bool __result) { return FeedContext.RemoveBorrowed(__instance, item, amount, ref __result); } } [HarmonyPatch(typeof(Inventory), "RemoveOneItem")] internal static class FeedRemoveOnePatch { private static bool Prefix(Inventory __instance, ItemData item, ref bool __result) { return FeedContext.RemoveBorrowed(__instance, item, 1, ref __result); } } [HarmonyPatch(typeof(Fermenter), "Interact")] internal static class FermenterFeedPatch { private static void Prefix(Humanoid user) { FeedContext.Begin(user); } private static void Finalizer() { FeedContext.Reset(); } } [HarmonyPatch(typeof(Fermenter), "FindCookableItem")] internal static class FermenterInputPatch { private static void Postfix(Fermenter __instance, Inventory inventory, ref ItemData __result) { if (__result == null) { __result = FeedContext.FindConversion(inventory, __instance.m_conversion, (ItemConversion conversion) => conversion.m_from); } } } [HarmonyPatch(typeof(Smelter), "OnAddOre")] internal static class SmelterFeedPatch { private static void Prefix(Humanoid user, ItemData item) { if (item == null) { FeedContext.Begin(user); } } private static void Finalizer() { FeedContext.Reset(); } } [HarmonyPatch(typeof(Smelter), "FindCookableItem")] internal static class SmelterInputPatch { private static readonly string[] KilnWoodPriority = new string[3] { "$item_wood", "$item_roundlog", "$item_finewood" }; private static void Postfix(Smelter __instance, Inventory inventory, ref ItemData __result) { List<string> list = new List<string>(); foreach (ItemConversion item2 in __instance.m_conversion) { if ((Object)(object)item2.m_from != (Object)null) { list.Add(item2.m_from.m_itemData.m_shared.m_name); } } if (((Object)((Component)__instance).gameObject).name.StartsWith("charcoal_kiln", StringComparison.OrdinalIgnoreCase)) { List<string> list2 = new List<string>(); string[] kilnWoodPriority = KilnWoodPriority; foreach (string item in kilnWoodPriority) { if (list.Contains(item)) { list2.Add(item); } } ItemData val = FeedContext.FindByPriority(inventory, list2); if (val != null) { __result = val; } } else if (__result == null) { __result = FeedContext.Find(inventory, list); } } } [HarmonyPatch(typeof(Turret), "UseItem")] internal static class TurretFeedPatch { private static void Prefix(Humanoid user, ItemData item) { if (item == null) { FeedContext.Begin(user); } } private static void Finalizer() { FeedContext.Reset(); } } [HarmonyPatch(typeof(Turret), "FindAmmoItem")] internal static class TurretInputPatch { private static void Postfix(Turret __instance, Inventory inventory, bool onlyCurrentlyLoadableType, ref ItemData __result) { if (__result == null) { string prefab = ((onlyCurrentlyLoadableType && __instance.HasAmmo()) ? __instance.GetAmmoType() : null); __result = FeedContext.FindAmmo(inventory, __instance.m_ammoType, prefab); } } } internal static class NearbyStorageCatalog { internal static List<NearbyStorageItem> Read(Player player) { Dictionary<string, NearbyStorageItem> dictionary = new Dictionary<string, NearbyStorageItem>(); foreach (Container item in StorageLocator.Nearby(player)) { foreach (ItemData allItem in item.GetInventory().GetAllItems()) { if (allItem != null && !((Object)(object)allItem.m_dropPrefab == (Object)null) && allItem.m_stack > 0) { string key = NearbyStorageItemKey.For(allItem, item); if (!dictionary.TryGetValue(key, out var value)) { value = new NearbyStorageItem { Key = key, Sample = allItem, Name = Localization.instance.Localize(allItem.m_shared.m_name) }; dictionary.Add(key, value); } else if (value.Sample.m_stack < value.Sample.m_shared.m_maxStackSize && allItem.m_stack >= allItem.m_shared.m_maxStackSize) { value.Sample = allItem; } value.Count += allItem.m_stack; AddSource(value, item, allItem); } } } return new List<NearbyStorageItem>(dictionary.Values); } private static void AddSource(NearbyStorageItem entry, Container chest, ItemData item) { foreach (NearbyStorageSource source in entry.Sources) { if (!((Object)(object)source.Chest != (Object)(object)chest)) { source.Count += item.m_stack; return; } } entry.Sources.Add(new NearbyStorageSource { Chest = chest, Item = item, Count = item.m_stack }); } } internal static class NearbyStorageCategory { private static readonly HashSet<string> Valuables = new HashSet<string>(StringComparer.Ordinal) { "Amber", "AmberPearl", "AncientCoin", "AncientGemstoneBlack", "AncientGemstoneGreen", "AncientGemstoneOrange", "AncientGemstonePurple", "Coins", "Ruby", "SilverNecklace", "GemstoneBlue", "GemstoneGreen", "GemstoneRed" }; internal static readonly string[] French = new string[13] { "Matériaux", "Précieux", "Nourriture", "Boissons", "Armes", "Boucliers", "Armures", "Accessoires", "Outils", "Munitions", "Poissons", "Trophées", "Divers" }; internal static readonly string[] English = new string[13] { "Materials", "Valuables", "Food", "Drinks", "Weapons", "Shields", "Armor", "Accessories", "Tools", "Ammunition", "Fish", "Trophies", "Miscellaneous" }; internal static string Label(int index) { if (Localization.instance == null || !(Localization.instance.GetSelectedLanguage() == "French")) { return English[index]; } return French[index]; } internal static int For(ItemData item) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected I4, but got Unknown if ((Object)(object)item?.m_dropPrefab != (Object)null && Valuables.Contains(((Object)item.m_dropPrefab).name)) { return 1; } ItemType itemType = item.m_shared.m_itemType; switch (itemType - 1) { case 0: return 0; case 1: if (!item.m_shared.m_isDrink) { return 2; } return 3; case 2: case 3: case 13: case 21: return 4; case 4: return 5; case 5: case 6: case 10: case 11: case 16: return 6; case 17: case 23: return 7; case 14: case 18: return 8; case 8: case 22: return 9; case 20: return 10; case 12: return 11; default: return 12; } } } internal static class NearbyStorageDeposit { private static readonly HashSet<Container> Expired = new HashSet<Container>(); private static Container _pending; private static ItemData _item; private static Player _player; private static int _remaining; private static int _moved; internal static bool Running { get; private set; } internal static bool TryStart(ItemData item, int amount, bool clearDrag) { Player localPlayer = Player.m_localPlayer; if (Running || (Object)(object)localPlayer == (Object)null || (Object)(object)item?.m_dropPrefab == (Object)null || amount <= 0 || !((Humanoid)localPlayer).GetInventory().ContainsItem(item)) { return false; } NearbyStorageDialog.FocusInventoryItem(item); List<Container> list = Candidates(item, localPlayer); if (list.Count == 0) { return false; } if (clearDrag) { NearbyStorageTransfer.ClearPlayerDrag(); } ((MonoBehaviour)Plugin.Instance).StartCoroutine(Run(item, localPlayer, amount, list)); return true; } private static List<Container> Candidates(ItemData item, Player player) { List<Container> list = new List<Container>(); foreach (Container item2 in StorageLocator.Nearby(player)) { if (Capacity(item2.GetInventory(), item) > 0) { list.Add(item2); } } NearbyStorageDestination.Sort(list, item, player); return list; } private static IEnumerator Run(ItemData item, Player player, int amount, List<Container> chests) { Running = true; _item = item; _player = player; _remaining = Mathf.Min(amount, item.m_stack); _moved = 0; try { foreach (Container chest in chests) { if (_remaining <= 0 || !((Humanoid)player).GetInventory().ContainsItem(item)) { break; } if (StorageLocator.Eligible(chest, player, StorageLocator.CurrentContainer(), Plugin.Instance.Settings.Radius.Value)) { yield return RequestChest(chest); } } } finally { if (_moved > 0) { NearbyStorageDialog.FocusInventoryItem(item); } _pending = null; _item = null; _player = null; _remaining = 0; Running = false; } } private static IEnumerator RequestChest(Container chest) { _pending = chest; chest.StackAll(); float deadline = Time.realtimeSinceStartup + 10f; while ((Object)(object)_pending == (Object)(object)chest && Time.realtimeSinceStartup < deadline) { yield return (object)new WaitForSecondsRealtime(0.1f); } if ((Object)(object)_pending == (Object)(object)chest) { Expired.Add(chest); _pending = null; } } internal static bool AllowResponse(Container chest, bool granted) { if (Expired.Remove(chest)) { return false; } if (!Running || (Object)(object)chest != (Object)(object)_pending) { return true; } _pending = null; if (granted) { try { Store(chest); } catch (Exception ex) { Debug.LogError((object)("Nearby Storage deposit failed: " + ex)); } } return false; } private static void Store(Container chest) { //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = ((Humanoid)_player).GetInventory(); if (!inventory.ContainsItem(_item) || _remaining <= 0) { return; } Inventory inventory2 = chest.GetInventory(); int num = Mathf.Min(new int[3] { _remaining, _item.m_stack, Capacity(inventory2, _item) }); if (num <= 0) { return; } ItemData val = _item.Clone(); val.m_stack = num; val.m_equipped = false; int num2 = inventory2.NrOfItemsIncludingStacks(); inventory2.AddItem(val); int num3 = inventory2.NrOfItemsIncludingStacks() - num2; if (num3 > 0) { if (num3 == _item.m_stack && ((Humanoid)_player).IsItemEquiped(_item)) { ((Humanoid)_player).RemoveEquipAction(_item); ((Humanoid)_player).UnequipItem(_item, true); } inventory.RemoveItem(_item, num3); _remaining -= num3; _moved += num3; InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null) { instance.m_moveItemEffects.Create(((Component)instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } NearbyStorageDialog.RefreshSoon(); } } internal static int Capacity(Inventory inventory, ItemData item) { int num = inventory.GetEmptySlots() * item.m_shared.m_maxStackSize; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_shared.m_name == item.m_shared.m_name && allItem.m_quality == item.m_quality && allItem.m_worldLevel == item.m_worldLevel) { num += Mathf.Max(0, allItem.m_shared.m_maxStackSize - allItem.m_stack); } } return num; } internal static void Reset() { _pending = null; _item = null; _player = null; _remaining = 0; _moved = 0; Expired.Clear(); Running = false; } } internal static class NearbyStorageDestination { internal static void Sort(List<Container> chests, ItemData item, Player player) { Dictionary<Container, (int level, int count)> scores = new Dictionary<Container, (int, int)>(); foreach (Container chest in chests) { Score(chest, item, out var level, out var count); scores.Add(chest, (level, count)); } chests.Sort((Container a, Container b) => Compare(a, b, player, scores)); } private static int Compare(Container a, Container b, Player player, Dictionary<Container, (int level, int count)> scores) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) int num = scores[b].level.CompareTo(scores[a].level); if (num != 0) { return num; } int num2 = scores[b].count.CompareTo(scores[a].count); if (num2 != 0) { return num2; } Vector3 val = ((Component)a).transform.position - ((Component)player).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)b).transform.position - ((Component)player).transform.position; float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude; return sqrMagnitude.CompareTo(sqrMagnitude2); } private static void Score(Container chest, ItemData selected, out int level, out int count) { string name = Localization.instance.Localize(selected.m_shared.m_name); int selectedCategory = NearbyStorageCategory.For(selected); CountContents(chest, selected, name, selectedCategory, out var identical, out var family, out var similar, out var category); level = ((identical > 0) ? 4 : ((family > 0) ? 3 : ((similar > 0) ? 2 : ((category > 0) ? 1 : 0)))); count = ((level == 4) ? identical : ((level == 3) ? family : ((level == 2) ? similar : category))); } private static void CountContents(Container chest, ItemData selected, string name, int selectedCategory, out int identical, out int family, out int similar, out int category) { identical = 0; family = 0; similar = 0; category = 0; foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { if (allItem?.m_shared == null || allItem.m_stack <= 0) { continue; } int num = NearbyStorageCategory.For(allItem); if (NearbyStorageItemKey.For(allItem) == NearbyStorageItemKey.For(selected)) { identical += allItem.m_stack; } else { if (num != selectedCategory) { goto IL_00ff; } GameObject dropPrefab = selected.m_dropPrefab; string left = ((dropPrefab != null) ? ((Object)dropPrefab).name : null); GameObject dropPrefab2 = allItem.m_dropPrefab; if (!NearbyStorageSort.SharesIdentifierWord(left, (dropPrefab2 != null) ? ((Object)dropPrefab2).name : null)) { StatusEffect consumeStatusEffect = selected.m_shared.m_consumeStatusEffect; string left2 = ((consumeStatusEffect != null) ? ((Object)consumeStatusEffect).name : null); StatusEffect consumeStatusEffect2 = allItem.m_shared.m_consumeStatusEffect; if (!NearbyStorageSort.SharesIdentifierWord(left2, (consumeStatusEffect2 != null) ? ((Object)consumeStatusEffect2).name : null) && !NearbyStorageRecipeFamily.SameStationFamily(selected, allItem) && !NearbyStorageProductionFamily.SameMachine(selected, allItem)) { goto IL_00ff; } } family += allItem.m_stack; } goto IL_012d; IL_012d: if (num == selectedCategory) { category += allItem.m_stack; } continue; IL_00ff: if (num == selectedCategory && NearbyStorageSort.Similar(name, Localization.instance.Localize(allItem.m_shared.m_name))) { similar += allItem.m_stack; } goto IL_012d; } } } internal sealed class NearbyStorageItem { internal string Key; internal string Name; internal ItemData Sample; internal int Count; internal readonly List<NearbyStorageSource> Sources = new List<NearbyStorageSource>(); } internal static class NearbyStorageItemKey { internal static string For(ItemData item) { if (!((Object)(object)item?.m_dropPrefab == (Object)null)) { return ((Object)item.m_dropPrefab).name + "|" + item.m_quality; } return null; } internal static string For(ItemData item, Container chest) { string text = For(item); if (text == null || item.m_shared.m_maxStackSize > 1) { return text; } return text + "|" + ((Object)chest).GetInstanceID() + "|" + item.m_gridPos.x + "," + item.m_gridPos.y; } } internal static class NearbyStorageProductionFamily { private static readonly Dictionary<string, HashSet<string>> Machines = new Dictionary<string, HashSet<string>>(StringComparer.Ordinal); private static ZNetScene _scene; private static int _prefabCount = -1; internal static bool SameMachine(ItemData left, ItemData right) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (left?.m_shared == null || right?.m_shared == null || left.m_shared.m_itemType != right.m_shared.m_itemType) { return false; } HashSet<string> hashSet = MachinesFor(left); HashSet<string> hashSet2 = MachinesFor(right); if (hashSet == null || hashSet2 == null) { return false; } foreach (string item in hashSet) { if (hashSet2.Contains(item)) { return true; } } return false; } private static HashSet<string> MachinesFor(ItemData item) { if (item?.m_shared == null || (Object)(object)ZNetScene.instance == (Object)null) { return null; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)_scene != (Object)(object)instance || _prefabCount != instance.m_prefabs.Count) { Refresh(instance); } if (!Machines.TryGetValue(item.m_shared.m_name, out var value)) { return null; } return value; } private static void Refresh(ZNetScene scene) { Machines.Clear(); foreach (GameObject prefab in scene.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Smelter component = prefab.GetComponent<Smelter>(); if ((Object)(object)component != (Object)null) { foreach (ItemConversion item in component.m_conversion) { Add(((Object)prefab).name, item?.m_to); } } CookingStation component2 = prefab.GetComponent<CookingStation>(); if ((Object)(object)component2 != (Object)null) { foreach (ItemConversion item2 in component2.m_conversion) { Add(((Object)prefab).name, item2?.m_to); } } Fermenter component3 = prefab.GetComponent<Fermenter>(); if (!((Object)(object)component3 != (Object)null)) { continue; } foreach (ItemConversion item3 in component3.m_conversion) { Add(((Object)prefab).name, item3?.m_to); } } _scene = scene; _prefabCount = scene.m_prefabs.Count; } private static void Add(string machine, ItemDrop output) { string text = output?.m_itemData?.m_shared?.m_name; if (!string.IsNullOrEmpty(text)) { if (!Machines.TryGetValue(text, out var value)) { value = new HashSet<string>(StringComparer.Ordinal); Machines.Add(text, value); } value.Add(machine); } } } internal static class NearbyStorageRecipeFamily { private static readonly Dictionary<string, HashSet<string>> Stations = new Dictionary<string, HashSet<string>>(StringComparer.Ordinal); private static ObjectDB _database; private static int _recipeCount = -1; internal static bool SameStationFamily(ItemData left, ItemData right) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (left?.m_shared == null || right?.m_shared == null || left.m_shared.m_itemType != right.m_shared.m_itemType) { return false; } HashSet<string> hashSet = StationsFor(left); HashSet<string> hashSet2 = StationsFor(right); if (hashSet == null || hashSet2 == null) { return false; } foreach (string item in hashSet) { if (hashSet2.Contains(item)) { return true; } } return false; } private static HashSet<string> StationsFor(ItemData item) { if (item?.m_shared == null || (Object)(object)ObjectDB.instance == (Object)null) { return null; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)_database != (Object)(object)instance || _recipeCount != instance.m_recipes.Count) { Refresh(instance); } if (!Stations.TryGetValue(item.m_shared.m_name, out var value)) { return null; } return value; } private static void Refresh(ObjectDB database) { Stations.Clear(); foreach (Recipe recipe in database.m_recipes) { string text = recipe?.m_item?.m_itemData?.m_shared?.m_name; string text2 = recipe?.m_craftingStation?.m_name; if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2)) { if (!Stations.TryGetValue(text, out var value)) { value = new HashSet<string>(StringComparer.Ordinal); Stations.Add(text, value); } value.Add(text2); } } _database = database; _recipeCount = database.m_recipes.Count; } } internal static class NearbyStorageSort { private static readonly Regex IdentifierWordPattern = new Regex("[A-Z][a-z0-9]*|[a-z0-9]+", RegexOptions.Compiled); internal static bool Similar(string left, string right) { HashSet<string> hashSet = new HashSet<string>(Words(left)); foreach (string item in Words(right)) { if (hashSet.Contains(item)) { return true; } } return false; } internal static bool SharesIdentifierWord(string left, string right) { if (string.IsNullOrEmpty(left) || string.IsNullOrEmpty(right)) { return false; } HashSet<string> hashSet = new HashSet<string>(IdentifierWords(left)); foreach (string item in IdentifierWords(right)) { if (hashSet.Contains(item)) { return true; } } return false; } private static IEnumerable<string> IdentifierWords(string identifier) { foreach (Match item in IdentifierWordPattern.Matches(identifier ?? "")) { string text = Normalize(item.Value.ToLowerInvariant()); if (text.Length >= 4) { yield return text; } } } internal static int ClosestIndex(List<NearbyStorageItem> items, string name) { if (items.Count == 0) { return -1; } HashSet<string> hashSet = new HashSet<string>(Words(name)); int result = 0; int num = -1; for (int i = 0; i < items.Count; i++) { int num2 = 0; foreach (string item in Words(items[i].Name)) { if (hashSet.Contains(item)) { num2 += 100; } } int j; for (j = 0; j < name.Length && j < items[i].Name.Length && char.ToLowerInvariant(name[j]) == char.ToLowerInvariant(items[i].Name[j]); j++) { } num2 += j; if (num2 > num) { num = num2; result = i; } } if (num <= 0) { return -1; } return result; } internal static void Sort(List<NearbyStorageItem> items) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (NearbyStorageItem item in items) { foreach (string item2 in Words(item.Name)) { dictionary[item2] = ((!dictionary.TryGetValue(item2, out var value)) ? 1 : (value + 1)); } } Dictionary<string, string> groups = new Dictionary<string, string>(); foreach (NearbyStorageItem item3 in items) { groups[item3.Key] = GroupKey(item3.Name, dictionary); } items.Sort((NearbyStorageItem a, NearbyStorageItem b) => Compare(a, b, groups)); } private static int Compare(NearbyStorageItem a, NearbyStorageItem b, Dictionary<string, string> groups) { if (a.Key == b.Key) { return 0; } int num = string.Compare(groups[a.Key], groups[b.Key], StringComparison.CurrentCultureIgnoreCase); if (num != 0) { return num; } int num2 = string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase); if (num2 == 0) { return string.CompareOrdinal(a.Key, b.Key); } return num2; } private static string GroupKey(string name, Dictionary<string, int> frequency) { string text = null; int num = 1; foreach (string item in Words(name)) { int num2 = frequency[item]; if (num2 > num) { text = item; num = num2; } } return text ?? name.ToLowerInvariant(); } private static IEnumerable<string> Words(string name) { StringBuilder word = new StringBuilder(); HashSet<string> seen = new HashSet<string>(); foreach (char c in name) { if (char.IsLetterOrDigit(c)) { word.Append(char.ToLowerInvariant(c)); continue; } string text = Normalize(word.ToString()); if (text.Length >= 4 && seen.Add(text)) { yield return text; } word.Clear(); } string text2 = Normalize(word.ToString()); if (text2.Length >= 4 && seen.Add(text2)) { yield return text2; } } private static string Normalize(string word) { if (word.Length <= 4 || !word.EndsWith("s", StringComparison.Ordinal)) { return word; } return word.Substring(0, word.Length - 1); } } internal sealed class NearbyStorageSource { internal Container Chest; internal ItemData Item; internal int Count; } internal static class NearbyStorageTransfer { private static readonly MethodInfo SetupDrag = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", new Type[3] { typeof(ItemData), typeof(Inventory), typeof(int) }, (Type[])null); private static readonly MethodInfo ShowSplit = AccessTools.Method(typeof(InventoryGui), "ShowSplitDialog", new Type[2] { typeof(ItemData), typeof(Inventory) }, (Type[])null); private static readonly FieldInfo DragItem = AccessTools.Field(typeof(InventoryGui), "m_dragItem"); private static readonly FieldInfo DragAmount = AccessTools.Field(typeof(InventoryGui), "m_dragAmount"); private static readonly FieldInfo DragInventory = AccessTools.Field(typeof(InventoryGui), "m_dragInventory"); private static Inventory _trackedInventory; private static ItemData _trackedItem; private static Container _trackedChest; internal static string DraggedPlayerItemKey() { return NearbyStorageItemKey.For(DraggedPlayerItem()); } internal static ItemData DraggedPlayerItem() { InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || (object)/*isinst with value type is only supported in some contexts*/ != ((Humanoid)localPlayer).GetInventory()) { return null; } object? obj = DragItem?.GetValue(instance); return (ItemData)((obj is ItemData) ? obj : null); } internal static string DraggedNearbyItemKey() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || _trackedItem == null || (Object)(object)_trackedChest == (Object)null || DragItem?.GetValue(instance) != _trackedItem || DragInventory?.GetValue(instance) != _trackedInventory) { return null; } return NearbyStorageItemKey.For(_trackedItem, _trackedChest); } internal static void CancelNearbyDrag() { if (DraggedNearbyItemKey() != null && !(SetupDrag == null)) { SetupDrag.Invoke(InventoryGui.instance, new object[3] { null, null, 1 }); _trackedInventory = null; _trackedItem = null; _trackedChest = null; NearbyStorageDialog.RefreshSoon(); } } internal static bool TryDropInPanel() { Player localPlayer = Player.m_localPlayer; InventoryGui instance = InventoryGui.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null || ((Character)localPlayer).IsTeleporting() || NearbyStorageDeposit.Running || (Object)(object)Plugin.Instance == (Object)null || SetupDrag == null) { return false; } object? obj = DragItem?.GetValue(instance); ItemData val = (ItemData)((obj is ItemData) ? obj : null); object? obj2 = DragInventory?.GetValue(instance); Inventory val2 = (Inventory)((obj2 is Inventory) ? obj2 : null); if (val2 != ((Humanoid)localPlayer).GetInventory() || (Object)(object)val?.m_dropPrefab == (Object)null || !val2.ContainsItem(val)) { return false; } int amount = (int)(DragAmount?.GetValue(instance) ?? ((object)val.m_stack)); return NearbyStorageDeposit.TryStart(val, amount, clearDrag: true); } internal static void ClearPlayerDrag() { SetupDrag?.Invoke(InventoryGui.instance, new object[3] { null, null, 1 }); } internal static bool IsTracked(Inventory inventory, ItemData item) { if (inventory != null && inventory == _trackedInventory && item != null && item == _trackedItem && (Object)(object)_trackedChest != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Plugin.Instance != (Object)null) { return StorageLocator.Eligible(_trackedChest, Player.m_localPlayer, StorageLocator.CurrentContainer(), Plugin.Instance.Settings.Radius.Value); } return false; } internal static void Select(NearbyStorageItem entry) { Player localPlayer = Player.m_localPlayer; InventoryGui instance = InventoryGui.instance; if (entry != null && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)instance == (Object)null) && !((Character)localPlayer).IsTeleporting() && DragItem?.GetValue(instance) == null && !SelectStack(entry, localPlayer, instance, fullOnly: true)) { SelectStack(entry, localPlayer, instance, fullOnly: false); } } private static bool SelectStack(NearbyStorageItem entry, Player player, InventoryGui gui, bool fullOnly) { foreach (NearbyStorageSource source in entry.Sources) { if (!((Object)(object)source.Chest == (Object)null) && FindStack(source.Chest.GetInventory(), source.Chest, entry.Key, fullOnly) != null && StorageLocator.TryClaimAndLoad(source.Chest, player)) { Inventory inventory = source.Chest.GetInventory(); ItemData val = FindStack(inventory, source.Chest, entry.Key, fullOnly); if (val != null) { Act(gui, player, source.Chest, inventory, val); NearbyStorageDialog.RefreshSoon(); return true; } } } return false; } private static ItemData FindStack(Inventory inventory, Container chest, string key, bool fullOnly) { foreach (ItemData allItem in inventory.GetAllItems()) { if (NearbyStorageItemKey.For(allItem, chest) == key && allItem.m_stack > 0 && (!fullOnly || allItem.m_stack >= allItem.m_shared.m_maxStackSize)) { return allItem; } } return null; } private static void Act(InventoryGui gui, Player player, Container chest, Inventory inventory, ItemData item) { bool num = ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true); bool flag = ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true); if (num) { if (item.m_stack > 1) { _trackedInventory = inventory; _trackedItem = item; _trackedChest = chest; ShowSplit?.Invoke(gui, new object[2] { item, inventory }); } } else if (flag) { if (!item.m_shared.m_questItem) { ((Humanoid)player).GetInventory().MoveItemToThis(inventory, item); } } else { _trackedInventory = inventory; _trackedItem = item; _trackedChest = chest; SetupDrag?.Invoke(gui, new object[3] { item, inventory, item.m_stack }); } } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] internal static class StackItemPatch { private static readonly FieldInfo DragField = AccessTools.Field(typeof(InventoryGui), "m_dragGo"); private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Modifier mod) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 Player localPlayer = Player.m_localPlayer; bool flag = NearbyStorageDialog.IsOpen && (int)mod == 2 && (ZInput.GetKey((KeyCode)306, true) || ZInput.GetKey((KeyCode)305, true)); if (item?.m_shared == null || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting() || !InventoryGui.IsVisible() || !flag || grid.GetInventory() != ((Humanoid)localPlayer).GetInventory() || DragField.GetValue(__instance) != null) { return true; } NearbyStorageDeposit.TryStart(item, item.m_stack, clearDrag: false); return false; } } [HarmonyPatch(typeof(Container), "RPC_StackResponse")] internal static class StackResponsePatch { private static bool Prefix(Container __instance, bool granted) { return NearbyStorageDeposit.AllowResponse(__instance, granted); } } internal static class StorageLabel { private const float SignRangeSquared = 16f; internal static string ShortLabel(Container chest) { return SignLabel(chest) ?? Localization.instance.Localize(chest.GetHoverName()); } internal static string SignLabel(Container chest) { return ClosestSign(chest); } private static string ClosestSign(Container chest) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) Sign val = null; float num = 16f; Container[] containers = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); Sign[] array = Object.FindObjectsByType<Sign>((FindObjectsSortMode)0); foreach (Sign val2 in array) { if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = ((Component)val2).transform.position - ((Component)chest).transform.position; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (!(sqrMagnitude > num) && !string.IsNullOrWhiteSpace(SignText(val2)) && IsClosestContainer(val2, chest, containers, sqrMagnitude)) { val = val2; num = sqrMagnitude; } } } if (!((Object)(object)val == (Object)null)) { return SignText(val); } return null; } private static bool IsClosestContainer(Sign sign, Container chest, Container[] containers, float chestDistance) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) foreach (Container val in containers) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)chest) && !StorageLocator.IsExcluded(val)) { Vector3 val2 = ((Component)sign).transform.position - ((Component)val).transform.position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < chestDistance || (sqrMagnitude == chestDistance && ((Object)val).GetInstanceID() < ((Object)chest).GetInstanceID())) { return false; } } } return true; } private static string SignText(Sign sign) { string text = sign.GetText(); if (text == null) { return null; } return StringExtensionMethods.RemoveRichTextTags(text).Replace('\r', ' ').Replace('\n', ' ') .Trim(); } } internal sealed class NearbyStorageCard : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IPointerEnterHandler, IPointerExitHandler, IDropHandler { internal Color IdleColor; private static readonly Color HoverColor = new Color(0.42f, 0.36f, 0.32f, 0.96f); internal NearbyStorageItem Item; internal Image Background; public void OnPointerDown(PointerEventData eventData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if ((int)eventData.button == 0 && !NearbyStorageTransfer.TryDropInPanel()) { NearbyStorageTransfer.Select(Item); } } public void OnDrop(PointerEventData eventData) { if (NearbyStorageTransfer.TryDropInPanel()) { ((AbstractEventData)eventData).Use(); } } public void OnPointerEnter(PointerEventData eventData) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Background != (Object)null) { ((Graphic)Background).color = HoverColor; } NearbyStorageDialog.ScheduleTooltip(Item); } public void OnPointerExit(PointerEventData eventData) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Background != (Object)null) { ((Graphic)Background).color = IdleColor; } NearbyStorageDialog.HideTooltip(); } } internal sealed class NearbyStorageCategoryHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { internal int Index; public void OnPointerEnter(PointerEventData eventData) { NearbyStorageDialog.SetCategoryHover(Index, hovered: true); } public void OnPointerExit(PointerEventData eventData) { NearbyStorageDialog.SetCategoryHover(Index, hovered: false); } } internal static class NearbyStorageDialog { private static RectTransform _root; private static RectTransform _cards; private static RectTransform _categoryContent; private static RectTransform _tooltip; private static RectTransform _dragCancelOverlay; private static TMP_InputField _filter; private static InventoryGui _gui; private static float _nextRefresh; private static int _category; private static string _fingerprint; private static bool _dirtyView = true; private static bool _hasNearbyItems; private static string _dragKey; private static string _scrollToDragKey; private static string _scrollToSimilarName; private static bool _scrollCategoryToSelection; private static bool _selectFirstCategory = true; private static string _nearbyDragKey; private const float GridTopPadding = 6f; private const float GridLeftPadding = 6f; private const float HeaderHeight = 106f; private const float CategoryRowHeight = 23f; private static readonly FieldInfo SearchField = AccessTools.Field(typeof(BuildUi), "m_searchField"); private static readonly FieldInfo TagScroll = AccessTools.Field(typeof(BuildUi), "m_tagListScrollRect"); private const float TooltipWidth = 340f; private const float SourceRowHeight = 36f; private const float TooltipDelay = 1f; private static TextMeshProUGUI _tooltipTitle; private static TextMeshProUGUI _tooltipDescription; private static RectTransform _tooltipSources; private static NearbyStorageItem _hoverItem; private static float _hoverReadyAt; internal static bool FilterFocused { get { if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeInHierarchy && (Object)(object)_filter != (Object)null && ((Behaviour)_filter).isActiveAndEnabled) { return _filter.isFocused; } return false; } } internal static bool IsOpen { get { if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeInHierarchy) { return _hasNearbyItems; } return false; } } private static void DrawCards(List<NearbyStorageItem> items) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) foreach (Transform item in (Transform)_cards) { Object.Destroy((Object)(object)((Component)item).gameObject); } Rect rect = ((Component)((Transform)_cards).parent).GetComponent<RectTransform>().rect; float num = Mathf.Max(260f, ((Rect)(ref rect)).width - 6f); float num2 = SlotStep(); int num3 = Mathf.Max(5, Mathf.FloorToInt(num / num2)); for (int i = 0; i < items.Count; i++) { DrawCard(items[i], i % num3, i / num3, num2, items[i].Key == _nearbyDragKey); } int num4 = Mathf.Max(4, (items.Count + num3 - 1) / num3); for (int j = items.Count; j < num4 * num3; j++) { CreateCardBackground("Empty slot", j % num3, j / num3, num2); } _cards.sizeDelta = new Vector2(0f, 6f + (float)num4 * num2); ScrollToDraggedItem(items, num3, num2); } private static void ScrollToDraggedItem(List<NearbyStorageItem> items, int columns, float step) { //IL_009a: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if (_scrollToDragKey == null) { return; } int num = items.FindIndex((NearbyStorageItem item) => item.Key == _scrollToDragKey); if (num < 0) { string prefix = _scrollToDragKey + "|"; num = items.FindIndex((NearbyStorageItem item) => item.Key.StartsWith(prefix, StringComparison.Ordinal)); } if (num < 0 && _scrollToSimilarName != null) { num = NearbyStorageSort.ClosestIndex(items, _scrollToSimilarName); } _scrollToDragKey = null; _scrollToSimilarName = null; if (num >= 0) { Transform parent = ((Transform)_cards).parent; Rect rect = ((RectTransform)((parent is RectTransform) ? parent : null)).rect; float height = ((Rect)(ref rect)).height; float num2 = 6f + (float)(num / columns) * step; float num3 = num2 + SlotSize(); float num4 = _cards.anchoredPosition.y; if (num2 < num4) { num4 = num2; } if (num3 > num4 + height) { num4 = num3 - height; } rect = _cards.rect; float num5 = Mathf.Max(0f, ((Rect)(ref rect)).height - height); ScrollRect component = ((Component)_root).GetComponent<ScrollRect>(); if (component != null) { component.StopMovement(); } _cards.anchoredPosition = new Vector2(_cards.anchoredPosition.x, Mathf.Clamp(num4, 0f, num5)); } } private static RectTransform CreateCardBackground(string name, int column, int row, float step) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) float num = SlotSize(); RectTransform obj = Rect(name, (Transform)(object)_cards, new Vector2(num, num)); obj.anchoredPosition = new Vector2(6f + (float)column * step, -6f - (float)row * step); StyleSlot(((Component)obj).gameObject.AddComponent<Image>()); return obj; } private static void DrawCard(NearbyStorageItem item, int column, int row, float step, bool held) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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) RectTransform val = CreateCardBackground(item.Key, column, row, step); float num = SlotSize(); NearbyStorageCard nearbyStorageCard = ((Component)val).gameObject.AddComponent<NearbyStorageCard>(); nearbyStorageCard.Item = item; nearbyStorageCard.Background = ((Component)val).GetComponent<Image>(); nearbyStorageCard.IdleColor = ((Graphic)nearbyStorageCard.Background).color; RectTransform obj = Rect("Icon", (Transform)(object)val, Vector2.zero); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = Vector2.zero; obj.offsetMax = Vector2.zero; Image val2 = ((Component)obj).gameObject.AddComponent<Image>(); StyleIcon(val2); val2.sprite = item.Sample.GetIcon(); if (held) { ((Graphic)val2).color = new Color(0.65f, 0.65f, 0.65f, ((Graphic)val2).color.a); } ((Graphic)val2).raycastTarget = false; DrawItemMarkers(val, item.Sample); if (item.Sample.m_shared.m_maxStackSize > 1) { TextMeshProUGUI obj2 = Label("Quantity", (Transform)(object)val, item.Count.ToString("N0"), 15f, new Vector2(2f, 0f - (num - 19f)), new Vector2(num - 4f, 18f)); StyleCount(obj2); ((TMP_Text)obj2).alignment = (TextAlignmentOptions)1028; } } private static void DrawItemMarkers(RectTransform card, ItemData item) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Invalid comparison between Unknown and I4 //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) InventoryElement val = SlotElement(); Transform obj = ((val != null) ? ((Component)val).transform : null); RectTransform val2 = (RectTransform)(object)((obj is RectTransform) ? obj : null); if (!((Object)(object)val2 == (Object)null)) { TMP_Text quality = val.m_quality; if (item.m_shared.m_maxQuality > 1 && (Object)(object)quality != (Object)null) { TextMeshProUGUI val3 = Label("Quality", (Transform)(object)card, item.m_quality.ToString(), quality.fontSize, Vector2.zero, Vector2.zero); ((TMP_Text)val3).font = quality.font; ((TMP_Text)val3).fontSharedMaterial = quality.fontSharedMaterial; ((TMP_Text)val3).fontStyle = quality.fontStyle; ((Graphic)val3).color = ((Graphic)quality).color; ((TMP_Text)val3).alignment = quality.alignment; MatchIconRect(quality.rectTransform, ((TMP_Text)val3).rectTransform, val2); } if ((int)item.m_shared.m_itemType == 2 && (!(item.m_shared.m_food <= 0f) || !(item.m_shared.m_foodStamina <= 0f) || !(item.m_shared.m_foodEitr <= 0f)) && !((Object)(object)val.m_food == (Object)null)) { RectTransform val4 = Rect("Food", (Transform)(object)card, Vector2.zero); Image val5 = ((Component)val4).gameObject.AddComponent<Image>(); CopyImage(val.m_food, val5); MatchIconRect(((Graphic)val.m_food).rectTransform, val4, val2); ((Graphic)val5).color = FoodColor(item); ((Graphic)val5).raycastTarget = false; } } } private static Color FoodColor(ItemData item) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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) float food = item.m_shared.m_food; float foodStamina = item.m_shared.m_foodStamina; float foodEitr = item.m_shared.m_foodEitr; if (food < foodEitr / 2f && foodStamina < foodEitr / 2f) { return new Color(0.6f, 0.6f, 1f, 1f); } if (foodStamina < food / 2f) { return new Color(1f, 0.5f, 0.5f, 1f); } if (food < foodStamina / 2f) { return new Color(1f, 1f, 0.5f, 1f); } return Color.white; } private static void CreateCategories() { //IL_000a: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_016a: 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_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: 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_023a: Expected O, but got Unknown RectTransform val = Rect("Categories", (Transform)(object)_root, Vector2.zero); val.anchorMin = new Vector2(0f, 0f); val.anchorMax = new Vector2(0f, 1f); val.offsetMin = new Vector2(16f, 10f); val.offsetMax = new Vector2(196f, -106f); Image obj = ((Component)val).gameObject.AddComponent<Image>(); ((Graphic)obj).color = new Color(0f, 0f, 0f, 0.72f); ((Graphic)obj).raycastTarget = false; ((Component)val).gameObject.AddComponent<RectMask2D>(); _categoryContent = Rect("Category content", (Transform)(object)val, new Vector2(164f, (float)NearbyStorageCategory.French.Length * 23f)); ScrollRect val2 = ((Component)val).gameObject.AddComponent<ScrollRect>(); val2.viewport = val; val2.content = _categoryContent; val2.horizontal = false; val2.scrollSensitivity = 100f; val2.movementType = (MovementType)2; for (int i = 0; i < NearbyStorageCategory.French.Length; i++) { int index = i; RectTransform val3 = Rect("Category " + i, (Transform)(object)_categoryContent, new Vector2(164f, 23f)); val3.anchoredPosition = new Vector2(0f, (float)(-i) * 23f); ((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = Color.clear; RectTransform obj2 = Rect("Selected", (Transform)(object)val3, Vector2.zero); obj2.anchorMin = Vector2.zero; obj2.anchorMax = Vector2.one; Vector2 offsetMin = (obj2.offsetMax = Vector2.zero); obj2.offsetMin = offsetMin; StyleCategorySelection(((Component)obj2).gameObject.AddComponent<Image>()); StyleCategoryText(Label("Text", (Transform)(object)val3, NearbyStorageCategory.Label(i), 14f, new Vector2(5f, -3f), new Vector2(158f, 22f))); Button obj3 = ((Component)val3).gameObject.AddComponent<Button>(); ((Selectable)obj3).transition = (Transition)0; ((Component)val3).gameObject.AddComponent<NearbyStorageCategoryHover>().Index = index; ((UnityEvent)obj3.onClick).AddListener((UnityAction)delegate { SelectCategory((_category == index) ? (-1) : index); }); } CreateCategoryScrollbar(val2, val); SelectCategory(_category); } private static void CreateCategoryScrollbar(ScrollRect scroll, RectTransform list) { //IL_0006: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Rect("Categories scrollbar", (Transform)(object)list, Vector2.zero); val.anchorMin = new Vector2(1f, 0f); val.anchorMax = new Vector2(1f, 1f); val.offsetMin = new Vector2(-16f, 0f); val.offsetMax = Vector2.zero; Image obj = ((Component)val).gameObject.AddComponent<Image>(); ((Graphic)obj).color = new Color(0f, 0f, 0f, 0.4f); RectTransform val2 = Rect("Handle", (Transform)(object)val, Vector2.zero); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; Image val3 = ((Component)val2).gameObject.AddComponent<Image>(); ((Graphic)val3).color = new Color(1f, 0.65f, 0.2f, 0.9f); StyleScrollbar(obj, val3); Scrollbar val4 = ((Component)val).gameObject.AddComponent<Scrollbar>(); val4.handleRect = val2; ((Selectable)val4).targetGraphic = (Graphic)(object)val3; val4.direction = (Direction)2; scroll.verticalScrollbar = val4; scroll.verticalScrollbarVisibility = (ScrollbarVisibility)1; } private static void SelectCategory(int index, bool clearFilter = true) { if (clearFilter && index >= 0 && (Object)(object)_filter != (Object)null && !string.IsNullOrEmpty(_filter.text)) { _filter.SetTextWithoutNotify(""); } _category = index; _scrollCategoryToSelection = index >= 0; for (int i = 0; i < NearbyStorageCategory.French.Length; i++) { SetCategoryHover(i, hovered: false); } RefreshSoon(); } internal static void SetCategoryHover(int index, bool hovered) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) RectTransform categoryContent = _categoryContent; Transform val = ((categoryContent != null) ? ((Transform)categoryContent).Find("Category " + index) : null); if (!((Object)(object)val == (Object)null)) { Transform obj = val.Find("Selected"); if (obj != null) { ((Component)obj).gameObject.SetActive(index == _category); } ((Graphic)((Component)val).GetComponent<Image>()).color = (Color)((hovered && index != _category) ? new Color(0.45f, 0.44f, 0.44f, 0.9f) : Color.clear); } } private static void ScrollToSelectedCategory() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_00af: 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_0116: Unknown result type (might be due to invalid IL or missing references) if (!_scrollCategoryToSelection || _category < 0 || (Object)(object)_categoryContent == (Object)null) { return; } _scrollCategoryToSelection = false; Transform obj = ((Transform)_categoryContent).Find("Category " + _category); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); Transform parent = ((Transform)_categoryContent).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { float num = 0f - val.anchoredPosition.y; float num2 = _categoryContent.anchoredPosition.y; if (num < num2) { num2 = num; } float num3 = num + 23f; float num4 = num2; Rect rect = val2.rect; if (num3 > num4 + ((Rect)(ref rect)).height) { float num5 = num + 23f; rect = val2.rect; num2 = num5 - ((Rect)(ref rect)).height; } rect = _categoryContent.rect; float height = ((Rect)(ref rect)).height; rect = val2.rect; float num6 = Mathf.Max(0f, height - ((Rect)(ref rect)).height); ScrollRect component = ((Component)val2).GetComponent<ScrollRect>(); if (component != null) { component.StopMovement(); } _categoryContent.anchoredPosition = new Vector2(0f, Mathf.Clamp(num2, 0f, num6)); } } internal static void FocusInventoryItem(ItemData item) { if (item?.m_shared != null && !((Object)(object)_root == (Object)null)) { SelectCategory(NearbyStorageCategory.For(item)); _scrollToDragKey = NearbyStorageItemKey.For(item); _scrollToSimilarName = Localization.instance.Localize(item.m_shared.m_name); RefreshSoon(); } } internal static void Update() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || !InventoryGui.IsVisible() || (Object)(object)StorageLocator.CurrentContainer() != (Object)null) { if ((Object)(object)_root != (Object)null) { ((Component)_root).gameObject.SetActive(false); } HideTooltip(); _nextRefresh = 0f; return; } if ((Object)(object)_root == (Object)null || (Object)(object)_gui != (Object)(object)instance) { Dispose(); Create(instance); } if (!((Component)_root).gameObject.activeSelf && (Object)(object)_filter != (Object)null && !string.IsNullOrEmpty(_filter.text)) { _filter.SetTextWithoutNotify(""); RefreshSoon(); } Position(); UpdateDragFocus(); if (Time.unscaledTime >= _nextRefresh) { Refresh(); } ((Component)_root).gameObject.SetActive(_hasNearbyItems); if (_hasNearbyItems) { UpdateVisibleDialog(instanc