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 SpiritStorage v0.10.3
plugins/SpiritStorage.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; 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: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SpiritStorage { [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class CraftHaveRequirementsPatch { private static void Postfix(Player __instance, Recipe recipe, bool discover, int qualityLevel, int amount, ref bool __result) { if (!__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)recipe == (Object)null) && recipe.m_resources != null && !CraftFromStorageHelper.StorageSuppressed && !discover && !recipe.m_requireOnlyOneIngredient && __instance.RequiredCraftingStation(recipe, qualityLevel, true) && (recipe.m_item.m_itemData.m_shared.m_dlc.Length <= 0 || DLCMan.instance.IsDLCInstalled(recipe.m_item.m_itemData.m_shared.m_dlc))) { __result = CraftFromStorageHelper.HaveEnoughIncludingStorage(__instance, recipe.m_resources, qualityLevel, Mathf.Max(1, amount), out var _); } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class BuildHaveRequirementsPatch { 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) if (!__result && (int)mode == 0 && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)piece == (Object)null) && piece.m_resources != null && !CraftFromStorageHelper.StorageSuppressed) { __result = CraftFromStorageHelper.HaveEnoughIncludingStorage(__instance, piece.m_resources, 1, 1, out var _); } } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] [HarmonyAfter(new string[] { "Nosferatu.NoVikingLeftBehind", "com.morda.storeandcraft" })] internal static class RequirementDisplayPatch { [HarmonyPriority(0)] private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, bool __result) { //IL_0129: Unknown result type (might be due to invalid IL or missing references) if (!__result || req == null || (Object)(object)req.m_resItem == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return; } Transform obj = elementRoot.Find("res_amount"); TMP_Text val = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null); if ((Object)(object)val == (Object)null) { return; } int num = CraftFromStorageHelper.CountInNearbyStorage(player, ((Object)((Component)req.m_resItem).gameObject).name); if (num <= 0) { return; } string text = val.text ?? ""; int num2 = text.IndexOf('/'); int result3; int num3; if (num2 >= 0 && int.TryParse(text.Substring(0, num2).Trim(), out var result) && int.TryParse(text.Substring(num2 + 1).Trim(), out var result2)) { num3 = result; result3 = result2; } else { num3 = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true); if (!int.TryParse(text.Trim(), out result3)) { result3 = req.GetAmount(quality) * craftMultiplier; } } num3 += num; val.text = $"{FormatCount(num3)}/{result3}"; if (num3 >= result3) { ((Graphic)val).color = Color.white; } } private static string FormatCount(int count) { if (count < 10000) { return count.ToString(); } return $"{count / 1000}k"; } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class CraftFetchPatch { private static readonly FieldRef<InventoryGui, Recipe> s_recipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe"); private static readonly FieldRef<InventoryGui, ItemData> s_upgradeItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem"); private static readonly FieldRef<InventoryGui, bool> s_multiCrafting = AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting"); private static readonly MethodInfo s_doCrafting = AccessTools.Method(typeof(InventoryGui), "DoCrafting", (Type[])null, (Type[])null); private static CraftFromStorageHelper.Fetch s_pending; private static bool Prefix(InventoryGui __instance, Player player, out bool __state) { __state = false; if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || CraftFromStorageHelper.StorageSuppressed) { return true; } if (s_pending != null && !s_pending.Completed) { return false; } Recipe recipe = s_recipe.Invoke(__instance); if ((Object)(object)recipe == (Object)null || recipe.m_resources == null || recipe.m_requireOnlyOneIngredient || CraftFromStorageHelper.IsFree(player, craft: true)) { return true; } ItemData val = s_upgradeItem.Invoke(__instance); int qualityLevel = ((val == null) ? 1 : (val.m_quality + 1)); int multiplier = ((!s_multiCrafting.Invoke(__instance)) ? 1 : __instance.m_multiCraftAmount); bool waiting = false; CraftFromStorageHelper.Fetch fetch = CraftFromStorageHelper.FetchShortfalls(player, recipe.m_resources, qualityLevel, multiplier, delegate(bool ok) { if (waiting && !((Object)(object)s_recipe.Invoke(__instance) != (Object)(object)recipe)) { if (!ok) { using (CraftFromStorageHelper.SuppressStorage()) { s_doCrafting.Invoke(__instance, new object[1] { player }); return; } } s_doCrafting.Invoke(__instance, new object[1] { player }); } }); if (!fetch.Completed) { waiting = true; s_pending = fetch; return false; } if (!fetch.Ok) { CraftFromStorageHelper.BeginSuppress(); __state = true; } return true; } private static void Finalizer(bool __state) { if (__state) { CraftFromStorageHelper.EndSuppress(); } } } [HarmonyPatch(typeof(Player), "Update")] internal static class BuildPrefetchPatch { internal static CraftFromStorageHelper.Fetch s_pending; private static float s_nextCheck; private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !((Character)__instance).InPlaceMode() || Time.time < s_nextCheck) { return; } s_nextCheck = Time.time + 0.25f; if (s_pending == null || s_pending.Completed) { Piece selectedPiece = __instance.GetSelectedPiece(); if (!((Object)(object)selectedPiece == (Object)null) && selectedPiece.m_resources != null && !selectedPiece.m_repairPiece && !selectedPiece.m_removePiece && !CraftFromStorageHelper.IsFree(__instance, craft: false, selectedPiece)) { s_pending = CraftFromStorageHelper.FetchShortfalls(__instance, selectedPiece.m_resources, 1, 1, null); } } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class BuildWaitPatch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null || piece.m_resources == null || CraftFromStorageHelper.IsFree(__instance, craft: false, piece)) { return true; } CraftFromStorageHelper.Fetch fetch = BuildPrefetchPatch.s_pending; if (fetch == null || fetch.Completed) { fetch = (BuildPrefetchPatch.s_pending = CraftFromStorageHelper.FetchShortfalls(__instance, piece.m_resources, 1, 1, null)); } if (fetch.Completed) { if (fetch.Ok) { return true; } bool flag; using (CraftFromStorageHelper.SuppressStorage()) { flag = __instance.HaveRequirements(piece, (RequirementMode)0); } if (flag) { return true; } ((Character)__instance).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); __result = false; return false; } ((Character)__instance).Message((MessageType)2, "Summoning materials from Spirit Storage...", 0, (Sprite)null, false); __result = false; return false; } } [HarmonyPatch(typeof(Player), "ConsumeResources")] internal static class CraftConsumeResourcesPatch { private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int multiplier) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && requirements != null) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { CraftFromStorageHelper.FetchShortfalls(__instance, requirements, Mathf.Max(1, qualityLevel), Mathf.Max(1, multiplier), null); } else if (CraftFromStorageHelper.Shortfalls(__instance, requirements, Mathf.Max(1, qualityLevel), Mathf.Max(1, multiplier)).Count > 0) { SpiritStorageContainer.LogVerbose("resources consumed with materials still missing from the inventory (a flow Spirit Storage doesn't prefetch for)."); } } } } internal static class CraftFromStorageHelper { private sealed class SuppressScope : IDisposable { private bool m_disposed; public void Dispose() { if (!m_disposed) { m_disposed = true; EndSuppress(); } } } internal class Fetch { public bool Completed; public bool Ok = true; } private static int s_suppressDepth; private static float Range => SpiritStoragePlugin.ConfigCraftRange.Value; public static bool StorageSuppressed => s_suppressDepth > 0; public static void BeginSuppress() { s_suppressDepth++; } public static void EndSuppress() { s_suppressDepth = Mathf.Max(0, s_suppressDepth - 1); } public static IDisposable SuppressStorage() { BeginSuppress(); return new SuppressScope(); } public static bool IsFree(Player player, bool craft, Piece piece = null) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (player.NoCostCheat() || (Object)(object)ZoneSystem.instance == (Object)null) { return true; } if (craft) { return ZoneSystem.instance.GetGlobalKey((GlobalKeys)25); } if ((Object)(object)piece != (Object)null) { return ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()); } return false; } private static IEnumerable<Requirement> RealRequirements(Player player, Requirement[] requirements) { CraftingStation station = player.GetCurrentCraftingStation(); return requirements.Where((Requirement r) => r != null && (Object)(object)r.m_resItem != (Object)null && ((!((Object)(object)station != (Object)null)) ? (!r.m_upgraderResource) : (station.m_upgrader == r.m_upgraderResource))); } private static int InventoryCount(Player player, Requirement req) { return ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true); } public static bool HaveEnoughIncludingStorage(Player player, Requirement[] requirements, int qualityLevel, int multiplier, out string debug) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) List<SpiritStorageContainer> list = SpiritStorageContainer.FindNearby(((Component)player).transform.position, Range).ToList(); debug = $"range={Range} nearbyStorages={list.Count}"; if (list.Count == 0) { return false; } foreach (Requirement item in RealRequirements(player, requirements)) { int num = item.GetAmount(qualityLevel) * multiplier; string prefabName = ((Object)((Component)item.m_resItem).gameObject).name; if (InventoryCount(player, item) + list.Sum((SpiritStorageContainer s) => s.CountItemsByName(prefabName)) < num) { return false; } } return true; } public static int CountInNearbyStorage(Player player, string prefabName) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) return SpiritStorageContainer.FindNearby(((Component)player).transform.position, Range).Sum((SpiritStorageContainer s) => s.CountItemsByName(prefabName)); } public static Dictionary<string, int> Shortfalls(Player player, Requirement[] requirements, int qualityLevel, int multiplier) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (Requirement item in RealRequirements(player, requirements)) { int num = item.GetAmount(qualityLevel) * multiplier - InventoryCount(player, item); if (num > 0) { string name = ((Object)((Component)item.m_resItem).gameObject).name; dictionary[name] = (dictionary.TryGetValue(name, out var value) ? value : 0) + num; } } return dictionary; } public static Fetch FetchShortfalls(Player player, Requirement[] requirements, int qualityLevel, int multiplier, Action<bool> onDone) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) Fetch fetch = new Fetch(); Dictionary<string, int> dictionary = Shortfalls(player, requirements, qualityLevel, multiplier); if (dictionary.Count == 0) { fetch.Completed = true; onDone?.Invoke(obj: true); return fetch; } Dictionary<SpiritStorageContainer, List<KeyValuePair<string, int>>> dictionary2 = new Dictionary<SpiritStorageContainer, List<KeyValuePair<string, int>>>(); foreach (SpiritStorageContainer item in SpiritStorageContainer.FindNearby(((Component)player).transform.position, Range)) { foreach (string item2 in dictionary.Keys.ToList()) { int num = Mathf.Min(dictionary[item2], item.CountItemsByName(item2)); if (num > 0) { if (!dictionary2.TryGetValue(item, out var value)) { value = (dictionary2[item] = new List<KeyValuePair<string, int>>()); } value.Add(new KeyValuePair<string, int>(item2, num)); dictionary[item2] -= num; } } } bool ok = dictionary.Values.All((int v) => v <= 0); if (dictionary2.Count == 0) { fetch.Completed = true; fetch.Ok = false; onDone?.Invoke(obj: false); return fetch; } fetch.Ok = ok; int outstanding = dictionary2.Count; foreach (KeyValuePair<SpiritStorageContainer, List<KeyValuePair<string, int>>> item3 in dictionary2) { SpiritStorageContainer.LogVerbose("fetching " + string.Join(", ", item3.Value.Select((KeyValuePair<string, int> v) => v.Key + " x" + v.Value)) + " from storage for crafting/building."); item3.Key.RequestPrefabs(item3.Value, player, delegate(bool flag) { fetch.Ok &= flag; if (--outstanding == 0) { fetch.Completed = true; onDone?.Invoke(fetch.Ok); } }); } return fetch; } } [HarmonyPatch(typeof(InventoryGrid), "DropItem", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(Vector2i) })] internal static class GridDropRedirectPatch { private static bool Prefix(ItemData item, int amount, ref bool __result) { SpiritStorageContainer spiritStorageContainer = SpiritStoragePanel.Instance?.CurrentTarget; Player localPlayer = Player.m_localPlayer; if ((Object)(object)spiritStorageContainer == (Object)null || (Object)(object)localPlayer == (Object)null) { if ((Object)(object)SpiritStoragePanel.Instance == (Object)null) { SpiritStorageContainer.LogVerbose($"grid drop of '{item?.m_shared?.m_name}' x{amount} not redirected - storage panel doesn't exist."); } return true; } SpiritStorageContainer.LogVerbose($"grid drop (Ctrl+click/drag out) of '{item?.m_shared?.m_name}' x{amount} -> redirecting to storage."); bool flag = spiritStorageContainer.DepositAmount(item, amount, localPlayer); if (!flag) { Logger.LogWarning((object)$"SpiritStorage: grid drop-redirect could not deposit '{item?.m_shared?.m_name}' x{amount} - see the lines above for why."); } __result = flag; SpiritStoragePanel.Instance.RefreshNow(); return false; } } [HarmonyPatch(typeof(Humanoid), "DropItem", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int) })] internal static class HumanoidDropRedirectPatch { private static bool Prefix(Humanoid __instance, ItemData item, int amount, ref bool __result) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } SpiritStorageContainer spiritStorageContainer = SpiritStoragePanel.Instance?.CurrentTarget; if ((Object)(object)spiritStorageContainer == (Object)null) { return true; } SpiritStorageContainer.LogVerbose($"drop (fallback path) of '{item?.m_shared?.m_name}' x{amount} -> redirecting to storage."); bool flag = spiritStorageContainer.DepositAmount(item, amount, (Player)__instance); if (!flag) { Logger.LogWarning((object)$"SpiritStorage: drop-redirect could not deposit '{item?.m_shared?.m_name}' x{amount} - see the lines above for why."); } __result = flag; SpiritStoragePanel.Instance.RefreshNow(); return false; } } internal static class EpicLootCompat { private const string ProviderId = "SpiritStorage"; public static void Init(Harmony harmony) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown Type type = AccessTools.TypeByName("EpicLoot.API"); Type type2 = AccessTools.TypeByName("EpicLoot_UnityLib.InventoryManagement"); if (type == null || type2 == null) { return; } MethodInfo methodInfo = AccessTools.Method(type, "RegisterInventoryProvider", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(type2, "RemoveItem", new Type[2] { typeof(string), typeof(int) }, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Logger.LogWarning((object)"SpiritStorage: found EpicLoot, but not its inventory-provider API - the enchanting table won't see Spirit Storage."); return; } try { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(EpicLootCompat), "RemoveItemPrefix", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); methodInfo.Invoke(null, new object[5] { "SpiritStorage", new Func<List<ItemData>>(GetItems), new Func<string, int>(CountItem), new Func<string, int, int>(RemoveItem), new Func<ItemData, int, int>(RemoveExactItem) }); Logger.LogInfo((object)"SpiritStorage: EpicLoot's enchanting table can now use materials in nearby Spirit Storage."); } catch (Exception ex) { Logger.LogWarning((object)("SpiritStorage: couldn't hook into EpicLoot's enchanting table: " + ex.Message)); } } private static IEnumerable<SpiritStorageContainer> Nearby() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { return SpiritStorageContainer.FindNearby(((Component)localPlayer).transform.position, SpiritStoragePlugin.ConfigCraftRange.Value); } return Enumerable.Empty<SpiritStorageContainer>(); } private static List<ItemData> GetItems() { return Nearby().SelectMany((SpiritStorageContainer s) => s.GetStackableDisplayItems()).ToList(); } private static int CountItem(string token) { return Nearby().Sum((SpiritStorageContainer s) => s.CountItemsByToken(token)); } private static int RemoveItem(string token, int amount) { return 0; } private static int RemoveExactItem(ItemData item, int amount) { int num = 0; foreach (SpiritStorageContainer item2 in Nearby()) { num += item2.ConsumeExact(item, amount - num); if (num >= amount) { break; } } return num; } private static bool RemoveItemPrefix(string item, ref int amount) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || amount <= 0 || string.IsNullOrEmpty(item)) { return true; } int num = amount - ((Humanoid)localPlayer).GetInventory().CountItems(item, -1, true); int num2 = 0; foreach (SpiritStorageContainer item2 in Nearby()) { if (num2 >= num) { break; } num2 += item2.ConsumeByToken(item, num - num2); } if (num2 <= 0) { return true; } SpiritStorageContainer.LogVerbose($"enchanting table: paid {num2} x '{item}' from Spirit Storage."); amount -= num2; return amount > 0; } } internal static class ExternalStackSize { private static bool s_resolved; private static object s_multiplierConfig; private static object s_enabledConfig; private static PropertyInfo s_multiplierValueProp; private static PropertyInfo s_enabledValueProp; private static void Resolve() { if (s_resolved) { return; } s_resolved = true; try { Type type = AppDomain.CurrentDomain.GetAssemblies().SelectMany(SafeGetTypes).FirstOrDefault((Type t) => t.FullName == "DropMoreLoot.DropMoreLootMain"); if (!(type == null)) { FieldInfo field = type.GetField("itemStackMultiplier", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = type.GetField("enableStacking", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null || field2 == null) { Logger.LogWarning((object)"SpiritStorage: found DropMoreLoot but not its expected config fields - stack sizes will use each item's own live max stack instead."); return; } s_multiplierConfig = field.GetValue(null); s_enabledConfig = field2.GetValue(null); s_multiplierValueProp = s_multiplierConfig?.GetType().GetProperty("Value"); s_enabledValueProp = s_enabledConfig?.GetType().GetProperty("Value"); Logger.LogInfo((object)"SpiritStorage: found DropMoreLoot - storage max stack sizes will follow its 'Item Stack Multiplier' setting uniformly."); } } catch (Exception ex) { Logger.LogWarning((object)("SpiritStorage: failed to resolve DropMoreLoot's stack multiplier config - falling back to each item's own live max stack. " + ex.Message)); } } private static Type[] SafeGetTypes(Assembly a) { try { return a.GetTypes(); } catch { return Array.Empty<Type>(); } } public static int GetMultiplier() { Resolve(); if (s_multiplierConfig == null || s_enabledConfig == null || s_multiplierValueProp == null || s_enabledValueProp == null) { return 1; } try { if (!(bool)s_enabledValueProp.GetValue(s_enabledConfig)) { return 1; } return Mathf.Max(1, (int)s_multiplierValueProp.GetValue(s_multiplierConfig)); } catch { return 1; } } } internal static class ExtraSlotsCompat { private static bool s_initialized; private static MethodInfo s_isItemInSlot; public static bool IsInExtraSlot(ItemData item) { EnsureInitialized(); if (s_isItemInSlot == null || item == null) { return false; } try { object obj = s_isItemInSlot.Invoke(null, new object[1] { item }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } private static void EnsureInitialized() { if (s_initialized) { return; } s_initialized = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("ExtraSlots.API"); if (!(type == null)) { s_isItemInSlot = type.GetMethod("IsItemInSlot", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null); if (s_isItemInSlot != null) { Logger.LogInfo((object)"SpiritStorage: found ExtraSlots - Deposit All will skip items in its extra slots."); } break; } } } } internal static class ItemNaming { private static bool s_initialized; private static MethodInfo s_getDisplayName; private static MethodInfo s_hasRarity; private static MethodInfo s_getRarityColor; public static string GetDisplayName(ItemData item) { EnsureInitialized(); if (s_getDisplayName != null) { try { if (s_getDisplayName.Invoke(null, new object[1] { item }) is string text && !string.IsNullOrEmpty(text)) { return text; } } catch { } } return LocalizationManager.Instance.TryTranslate(item.m_shared.m_name); } public static bool TryGetRarityColor(ItemData item, out Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) EnsureInitialized(); color = default(Color); if (s_hasRarity == null || s_getRarityColor == null) { return false; } try { object obj = s_hasRarity.Invoke(null, new object[1] { item }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { color = (Color)s_getRarityColor.Invoke(null, new object[1] { item }); return true; } } catch { } return false; } private static void EnsureInitialized() { if (s_initialized) { return; } s_initialized = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("EpicLoot.ItemDataExtensions"); if (!(type == null)) { s_getDisplayName = type.GetMethod("GetDisplayName", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null); s_hasRarity = type.GetMethod("HasRarity", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null); s_getRarityColor = type.GetMethod("GetRarityColor", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null); break; } } } } public class StorageGroup { public string Key; public string DisplayName; public Sprite Icon; public int TotalCount; public int Quality; public float DurabilityPercent = -1f; public readonly List<ItemData> BackingItems = new List<ItemData>(); public readonly List<long> BackingIds = new List<long>(); public readonly List<int> BackingStacks = new List<int>(); } public class SpiritStorageContainer : MonoBehaviour, Hoverable, Interactable { private static readonly List<SpiritStorageContainer> s_active = new List<SpiritStorageContainer>(); private ZNetView m_nview; private StorageLedger m_ledger; private uint m_ledgerRevision; private bool m_ledgerLoaded; private readonly Dictionary<long, ItemData> m_displayItems = new Dictionary<long, ItemData>(); public GameObject OpenVisual; public GameObject ClosedVisual; private static readonly ConditionalWeakTable<ItemData, string> s_prefabNameCache = new ConditionalWeakTable<ItemData, string>(); private static readonly FieldInfo[] s_sharedDataFields = typeof(SharedData).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private bool IsValid { get { if ((Object)(object)m_nview != (Object)null) { return m_nview.IsValid(); } return false; } } public ZDOID StorageId => m_nview.GetZDO().m_uid; public uint Revision { get { if (!IsValid) { return 0u; } return m_nview.GetZDO().DataRevision; } } private static int MaxTypes => SpiritStoragePlugin.ConfigMaxItemTypes.Value; public int Capacity => MaxTypes; public int CurrentCount => GetLedger()?.TypeKeys().Count ?? 0; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); } private void OnEnable() { s_active.Add(this); } private void OnDisable() { s_active.Remove(this); } public static IEnumerable<SpiritStorageContainer> FindNearby(Vector3 position, float range) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) float rangeSq = range * range; return s_active.Where(delegate(SpiritStorageContainer s) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s != (Object)null && s.IsValid) { Vector3 val = ((Component)s).transform.position - position; return ((Vector3)(ref val)).sqrMagnitude <= rangeSq; } return false; }).OrderBy(delegate(SpiritStorageContainer s) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)s).transform.position - position; return ((Vector3)(ref val)).sqrMagnitude; }).ToList(); } private StorageLedger GetLedger() { if (!IsValid) { return null; } ZDO zDO = m_nview.GetZDO(); if (!m_ledgerLoaded || zDO.DataRevision != m_ledgerRevision) { m_ledger = StorageLedger.Read(zDO); m_ledgerRevision = zDO.DataRevision; m_ledgerLoaded = true; m_displayItems.Clear(); } return m_ledger; } public string GetHoverName() { return LocalizationManager.Instance.TryTranslate("$piece_spiritstorage"); } public string GetHoverText() { return LocalizationManager.Instance.TryTranslate("$piece_spiritstorage") + "\n[<color=yellow><b>$KEY_Use</b></color>] $piece_spiritstorage_open"; } public float GetHoverOffset() { return 0.5f; } public bool UseItem(Humanoid user, ItemData item) { return false; } public bool Interact(Humanoid character, bool hold, bool alt) { if (hold || !IsValid) { return false; } if (GetLedger() == null) { ((Character)character).Message((MessageType)2, "This Spirit Storage needs a newer version of the mod.", 0, (Sprite)null, false); return true; } SetOpenVisual(open: true); InventoryGui.instance.Show((Container)null, 0); SpiritStoragePanel.Instance?.Open(this, (Player)(object)((character is Player) ? character : null)); return true; } public void OnPanelClosed() { SetOpenVisual(open: false); InventoryGui.instance.Hide(); } internal static void LogVerbose(string message) { if (SpiritStoragePlugin.ConfigVerboseLogging.Value) { Logger.LogInfo((object)("SpiritStorage: " + message)); } } private static string Describe(ItemData item) { if (item != null) { return $"'{item.m_shared?.m_name}' x{item.m_stack}"; } return "<null item>"; } private void SetOpenVisual(bool open) { if ((Object)(object)OpenVisual != (Object)null) { OpenVisual.SetActive(open); } if ((Object)(object)ClosedVisual != (Object)null) { ClosedVisual.SetActive(!open); } } internal static ItemData ToItemData(StorageRecord record) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(record.PrefabName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { return null; } ItemData obj = val.m_itemData.Clone(); obj.m_dropPrefab = itemPrefab; obj.m_stack = record.Stack; obj.m_durability = record.Durability; obj.m_quality = record.Quality; obj.m_variant = record.Variant; obj.m_crafterID = record.CrafterID; obj.m_crafterName = record.CrafterName; obj.m_worldLevel = record.WorldLevel; obj.m_pickedUp = record.PickedUp; obj.m_customData = new Dictionary<string, string>(record.CustomData); obj.m_equipped = false; RememberPrefabName(obj, record.PrefabName); return obj; } internal static StorageRecord FromItemData(ItemData item, int stack) { string prefabName = ResolvePrefabName(item); return new StorageRecord { PrefabName = prefabName, Stack = stack, Durability = item.m_durability, Quality = item.m_quality, Variant = item.m_variant, CrafterID = item.m_crafterID, CrafterName = (item.m_crafterName ?? ""), WorldLevel = item.m_worldLevel, PickedUp = item.m_pickedUp, Stackable = (StorageRecord.IsStackablePrefab(prefabName) ?? (item.m_shared.m_maxStackSize > 1)), CustomData = ((item.m_customData != null) ? new Dictionary<string, string>(item.m_customData) : new Dictionary<string, string>()) }; } private ItemData GetDisplayItem(StorageRecord record) { if (!m_displayItems.TryGetValue(record.Id, out var value)) { value = ToItemData(record); m_displayItems[record.Id] = value; } return value; } internal static string ResolvePrefabName(ItemData item) { return s_prefabNameCache.GetValue(item, ResolvePrefabNameUncached); } private static void RememberPrefabName(ItemData item, string name) { s_prefabNameCache.Remove(item); s_prefabNameCache.Add(item, name); } private static string ResolvePrefabNameUncached(ItemData item) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.m_shared); if ((Object)(object)itemPrefab != (Object)null) { return ((Object)itemPrefab).name; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name; } foreach (GameObject item2 in ObjectDB.instance.m_items) { ItemDrop val = (((Object)(object)item2 != (Object)null) ? item2.GetComponent<ItemDrop>() : null); if ((Object)(object)val != (Object)null && val.m_itemData?.m_shared?.m_name == item.m_shared.m_name) { return ((Object)item2).name; } } Logger.LogWarning((object)("SpiritStorage: could not resolve a prefab name for '" + item.m_shared.m_name + "' - falling back to its display token, which likely won't reload correctly.")); return item.m_shared.m_name; } internal static int EffectiveMaxStack(ItemData item) { int maxStackSize = item.m_shared.m_maxStackSize; GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(ResolvePrefabName(item)); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val != (Object)null && val.m_itemData?.m_shared != null) { maxStackSize = val.m_itemData.m_shared.m_maxStackSize; } if (maxStackSize <= 1) { return 1; } return Mathf.Max(1, maxStackSize * ExternalStackSize.GetMultiplier()); } private static SharedData CloneShared(SharedData src) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown SharedData val = new SharedData(); FieldInfo[] array = s_sharedDataFields; foreach (FieldInfo fieldInfo in array) { fieldInfo.SetValue(val, fieldInfo.GetValue(src)); } return val; } public List<StorageGroup> GetGroupedView() { List<StorageGroup> list = new List<StorageGroup>(); StorageLedger ledger = GetLedger(); if (ledger == null) { return list; } Dictionary<string, StorageGroup> dictionary = new Dictionary<string, StorageGroup>(); foreach (StorageRecord record in ledger.Records) { ItemData displayItem = GetDisplayItem(record); if (displayItem == null) { continue; } StorageGroup value; if (record.Stackable) { string key = "type#" + record.PrefabName; if (!dictionary.TryGetValue(key, out value)) { value = (dictionary[key] = new StorageGroup { Key = key, DisplayName = ItemNaming.GetDisplayName(displayItem), Icon = displayItem.GetIcon() }); list.Add(value); } } else { value = new StorageGroup { Key = "item#" + record.Id, DisplayName = ItemNaming.GetDisplayName(displayItem), Icon = displayItem.GetIcon(), Quality = displayItem.m_quality, DurabilityPercent = (displayItem.m_shared.m_useDurability ? displayItem.GetDurabilityPercentage() : (-1f)) }; list.Add(value); } value.TotalCount += record.Stack; value.BackingItems.Add(displayItem); value.BackingIds.Add(record.Id); value.BackingStacks.Add(record.Stack); } return list.OrderBy((StorageGroup g) => g.DisplayName).ToList(); } public int CountItemsByName(string prefabName) { return GetLedger()?.Records.Where((StorageRecord r) => r.PrefabName == prefabName).Sum((StorageRecord r) => r.Stack) ?? 0; } public int CountItemsByToken(string token) { return GetLedger()?.Records.Where((StorageRecord r) => GetDisplayItem(r)?.m_shared.m_name == token).Sum((StorageRecord r) => r.Stack) ?? 0; } public List<ItemData> GetStackableDisplayItems() { StorageLedger ledger = GetLedger(); List<ItemData> list = new List<ItemData>(); if (ledger == null) { return list; } foreach (StorageRecord item in ledger.Records.Where((StorageRecord r) => r.Stackable)) { ItemData displayItem = GetDisplayItem(item); if (displayItem != null) { list.Add(displayItem); } } return list; } internal int ConsumeByToken(string token, int amount) { StorageLedger ledger = GetLedger(); if (ledger == null || amount <= 0) { return 0; } List<KeyValuePair<string, int>> plan = new List<KeyValuePair<string, int>>(); int num = amount; foreach (IGrouping<string, StorageRecord> item in from r in ledger.Records where GetDisplayItem(r)?.m_shared.m_name == token group r by r.PrefabName) { int num2 = Mathf.Min(num, item.Sum((StorageRecord r) => r.Stack)); if (num2 > 0) { plan.Add(new KeyValuePair<string, int>(item.Key, num2)); num -= num2; } if (num <= 0) { break; } } if (plan.Count != 0) { return SendConsume(StorageNetwork.Op.WithdrawPrefabs, delegate(ZPackage pkg) { pkg.Write(plan.Count); foreach (KeyValuePair<string, int> item2 in plan) { pkg.Write(item2.Key); pkg.Write(item2.Value); } }, plan.Sum((KeyValuePair<string, int> p) => p.Value), token); } return 0; } internal int ConsumeExact(ItemData displayItem, int amount) { GetLedger(); long id = m_displayItems.FirstOrDefault((KeyValuePair<long, ItemData> kvp) => kvp.Value == displayItem).Key; StorageRecord storageRecord = ((id == 0L) ? null : m_ledger?.FindById(id)); int take = ((storageRecord != null) ? Mathf.Min(amount, storageRecord.Stack) : 0); if (take <= 0) { return 0; } return SendConsume(StorageNetwork.Op.WithdrawIds, delegate(ZPackage pkg) { pkg.Write(1); pkg.Write(id); pkg.Write(take); }, take, displayItem.m_shared.m_name); } private int SendConsume(StorageNetwork.Op op, Action<ZPackage> body, int planned, string what) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) StorageNetwork.TxHandle txHandle = StorageNetwork.Send(StorageId, op, body, delegate(StorageNetwork.TxResult result) { if (!result.Ok) { Logger.LogWarning((object)$"SpiritStorage: server refused consuming {planned} x '{what}' ({result.Message})."); } }); if (!txHandle.Completed) { return planned; } if (!txHandle.Result.Ok) { return 0; } return txHandle.Result.Returned.Sum((StorageRecord r) => r.Stack); } public void DepositAll(Player player, Action<string> onDone, bool onlyExisting = false) { Inventory inventory = ((Humanoid)player).GetInventory(); List<ItemData> hotbar = inventory.GetHotbar(false); List<ItemData> list = new List<ItemData>(); int num = 0; HashSet<string> hashSet = null; if (onlyExisting) { hashSet = new HashSet<string>(GetLedger()?.Records.Select((StorageRecord r) => r.PrefabName) ?? Enumerable.Empty<string>()); } foreach (ItemData item in new List<ItemData>(inventory.GetAllItems())) { if (item.m_equipped || hotbar.Contains(item) || ExtraSlotsCompat.IsInExtraSlot(item)) { num++; } else if (hashSet == null || hashSet.Contains(ResolvePrefabName(item))) { list.Add(item); } } if (list.Count == 0) { onDone?.Invoke(onlyExisting ? "Nothing matches what's already stored." : "Nothing to store."); return; } List<StorageRecord> records = list.Select((ItemData i) => FromItemData(i, i.m_stack)).ToList(); foreach (ItemData item2 in list) { inventory.RemoveItem(item2); } int units = list.Sum((ItemData i) => i.m_stack); LogVerbose(string.Format("{0}: sending {1} stacks ({2} units); skipped {3} hotbar/equipped/extra-slot.", onlyExisting ? "Deposit Fill" : "Deposit All", list.Count, units, num)); SendDeposit(records, list, player, delegate(int rejected) { onDone?.Invoke((rejected == 0) ? $"Stored {units} items." : $"Storage full - {rejected} stack(s) kept."); }); } public bool DepositAmount(ItemData item, int amount, Player player) { if (item == null || amount <= 0 || !IsValid) { LogVerbose($"deposit rejected - {Describe(item)}, amount={amount}."); return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (!inventory.ContainsItem(item)) { LogVerbose("deposit of " + Describe(item) + " failed - item isn't in the player's inventory (already moved?)."); return false; } if (item.m_equipped) { ((Humanoid)player).UnequipItem(item, false); } ItemData val; if (amount >= item.m_stack) { inventory.RemoveItem(item); val = item; } else { val = item.Clone(); RememberPrefabName(val, ResolvePrefabName(item)); val.m_stack = amount; item.m_stack -= amount; } SendDeposit(new List<StorageRecord> { FromItemData(val, val.m_stack) }, new List<ItemData> { val }, player, delegate(int rejected) { if (rejected > 0) { ((Character)player).Message((MessageType)2, "Spirit Storage is full.", 0, (Sprite)null, false); } }); return true; } private void SendDeposit(List<StorageRecord> records, List<ItemData> items, Player player, Action<int> onDone) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) StorageNetwork.Send(StorageId, StorageNetwork.Op.Deposit, delegate(ZPackage pkg) { pkg.Write(records.Count); foreach (StorageRecord record in records) { record.Write(pkg); } }, delegate(StorageNetwork.TxResult result) { IEnumerable<int> enumerable; if (!result.Ok) { enumerable = Enumerable.Range(0, items.Count); } else { IEnumerable<int> rejected = result.Rejected; enumerable = rejected; } int num = 0; foreach (int item in enumerable) { if (item >= 0 && item < items.Count) { GiveItem(player, items[item]); num++; } } if (!result.Ok) { Logger.LogWarning((object)$"SpiritStorage: deposit failed ({result.Message}) - {num} stack(s) returned to the player."); } onDone?.Invoke(num); }); } public void Withdraw(StorageGroup group, int amount, Player player, Action<string> onDone) { //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (group == null || group.BackingIds.Count == 0 || amount <= 0 || !IsValid) { return; } ItemData sample = group.BackingItems[0]; int num = RoomFor(((Humanoid)player).GetInventory(), sample); int wanted = Mathf.Min(new int[3] { amount, group.TotalCount, num }); if (wanted <= 0) { onDone?.Invoke("Your inventory is full."); return; } List<KeyValuePair<long, int>> picks = new List<KeyValuePair<long, int>>(); int num2 = wanted; for (int i = 0; i < group.BackingIds.Count; i++) { if (num2 <= 0) { break; } int num3 = Mathf.Min(num2, group.BackingStacks[i]); picks.Add(new KeyValuePair<long, int>(group.BackingIds[i], num3)); num2 -= num3; } StorageNetwork.Send(StorageId, StorageNetwork.Op.WithdrawIds, delegate(ZPackage pkg) { pkg.Write(picks.Count); foreach (KeyValuePair<long, int> item in picks) { pkg.Write(item.Key); pkg.Write(item.Value); } }, delegate(StorageNetwork.TxResult result) { int num4 = GiveRecords(player, result.Returned); LogVerbose($"withdraw '{group.DisplayName}': asked {wanted}, got {num4}."); if (!result.Ok) { onDone?.Invoke("Someone else already took that."); } else { onDone?.Invoke((wanted < Mathf.Min(amount, group.TotalCount)) ? "Your inventory is full." : null); } }); } internal StorageNetwork.TxHandle RequestPrefabs(List<KeyValuePair<string, int>> wanted, Player player, Action<bool> onDone) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) return StorageNetwork.Send(StorageId, StorageNetwork.Op.WithdrawPrefabs, delegate(ZPackage pkg) { pkg.Write(wanted.Count); foreach (KeyValuePair<string, int> item in wanted) { pkg.Write(item.Key); pkg.Write(item.Value); } }, delegate(StorageNetwork.TxResult result) { GiveRecords(player, result.Returned); if (!result.Ok) { LogVerbose("material request refused: " + result.Message + "."); } onDone?.Invoke(result.Ok); }); } private static int RoomFor(Inventory inv, ItemData sample) { int num = EffectiveMaxStack(sample); long num2 = (long)inv.GetEmptySlots() * (long)num; if (num > 1) { foreach (ItemData allItem in inv.GetAllItems()) { if (allItem.m_shared.m_name == sample.m_shared.m_name && allItem.m_quality == sample.m_quality) { num2 += Mathf.Max(0, allItem.m_shared.m_maxStackSize - allItem.m_stack); } } } return (int)Math.Min(num2, 2147483647L); } private static int GiveRecords(Player player, List<StorageRecord> records) { int num = 0; foreach (StorageRecord record in records) { ItemData val = ToItemData(record); if (val == null) { Logger.LogError((object)$"SpiritStorage: withdrew '{record.PrefabName}' x{record.Stack} but that item no longer exists in the game (removed mod?) - it can't be given back."); continue; } int num2 = EffectiveMaxStack(val); int num3 = val.m_stack; while (num3 > 0) { int num4 = Mathf.Min(num3, num2); ItemData val2 = ((num3 == val.m_stack && num4 == num3) ? val : val.Clone()); RememberPrefabName(val2, record.PrefabName); val2.m_stack = num4; val2.m_shared = CloneShared(val2.m_shared); val2.m_shared.m_maxStackSize = num2; GiveItem(player, val2); num3 -= num4; num += num4; } } return num; } private static void GiveItem(Player player, ItemData item) { //IL_0041: 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) //IL_004c: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) Inventory val = (((Object)(object)player != (Object)null) ? ((Humanoid)player).GetInventory() : null); if (val != null && val.CanAddItem(item, -1)) { val.AddItem(item); } else if ((Object)(object)player != (Object)null) { Transform transform = ((Component)player).transform; ItemDrop.DropItem(item, item.m_stack, transform.position + transform.forward + Vector3.up, transform.rotation); LogVerbose("inventory full - dropped " + Describe(item) + " at the player's feet."); } } } public class SpiritStoragePanel : MonoBehaviour { public static SpiritStoragePanel Instance; private const float CellSize = 56f; private const float CellSpacing = 6f; private const float PanelWidth = 860f; private const float PanelHeight = 440f; private const float GridSideMargin = 16f; private const float ScrollbarWidth = 8f; private const float GridPadding = 6f; private const int FilterColumns = 2; private const float FilterButtonWidth = 104f; private const float FilterButtonHeight = 28f; private const float FilterButtonSpacing = 4f; private const float FilterColumnWidth = 212f; private static readonly Color FilterOnTint = new Color(1f, 0.75f, 0.35f, 1f); private static readonly Color FilterOffTint = new Color(0.55f, 0.55f, 0.55f, 1f); private static readonly string[] SortLabels = new string[5] { "A-Z", "Z-A", "Most", "Least", "Type" }; private GameObject m_root; private RectTransform m_rootRt; private Text m_capacityText; private Text m_statusText; private InputField m_searchField; private readonly List<Button> m_filterButtons = new List<Button>(); private Text m_sortButtonText; private RectTransform m_storageContent; private GameObject m_tooltipPrefab; private GameObject m_tooltipGo; private SpiritStorageCell m_hoverCell; private float m_hoverTime; private const float TooltipDelay = 0.35f; private GameObject m_elementPrefab; private GameObject m_splitOverlay; private Text m_splitTitleText; private InputField m_splitInput; private StorageGroup m_splitGroup; private readonly Dictionary<string, GameObject> m_activeCells = new Dictionary<string, GameObject>(); private readonly Stack<GameObject> m_freeCells = new Stack<GameObject>(); private SpiritStorageContainer m_target; private Player m_player; private string m_searchFilter = ""; private int m_typeMask; private int m_sortMode; private bool m_inventoryWasVisible; private uint m_shownRevision; public SpiritStorageContainer CurrentTarget => m_target; public static void Create() { //IL_0049: 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) if ((Object)(object)Instance != (Object)null) { Object.Destroy((Object)(object)((Component)Instance).gameObject); Instance = null; } if (!((Object)(object)GUIManager.CustomGUIFront == (Object)null)) { GameObject val = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 860f, 440f, true); val.SetActive(false); Instance = val.AddComponent<SpiritStoragePanel>(); Instance.BuildContents(val); } } private void BuildContents(GameObject root) { //IL_006c: 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_008a: 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_009d: 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_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Expected O, but got Unknown //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Expected O, but got Unknown //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Expected O, but got Unknown //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_041c: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Expected O, but got Unknown //IL_0562: Unknown result type (might be due to invalid IL or missing references) //IL_056d: Unknown result type (might be due to invalid IL or missing references) m_root = root; m_rootRt = root.GetComponent<RectTransform>(); Font averiaSerifBold = GUIManager.Instance.AveriaSerifBold; m_typeMask = ItemTypeFilters.ParseMask(SpiritStoragePlugin.ConfigPanelTypeFilters.Value); m_sortMode = Mathf.Clamp(SpiritStoragePlugin.ConfigPanelSortMode.Value, 0, SortLabels.Length - 1); GUIManager.Instance.CreateText("Spirit Storage", root.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(130f, -26f), averiaSerifBold, 22, GUIManager.Instance.ValheimOrange, true, Color.black, 220f, 32f, false).GetComponent<Text>().alignment = (TextAnchor)3; m_statusText = GUIManager.Instance.CreateText("", root.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(350f, -26f), averiaSerifBold, 14, Color.yellow, true, Color.black, 200f, 24f, false).GetComponent<Text>(); m_statusText.alignment = (TextAnchor)4; m_capacityText = GUIManager.Instance.CreateText("0 / 0 types", root.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-338f, -26f), averiaSerifBold, 14, Color.white, true, Color.black, 120f, 24f, false).GetComponent<Text>(); m_capacityText.alignment = (TextAnchor)5; ((UnityEvent)GUIManager.Instance.CreateButton("Deposit All", root.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-80f, -26f), 120f, 28f).GetComponent<Button>().onClick).AddListener(new UnityAction(OnDepositAll)); ((UnityEvent)GUIManager.Instance.CreateButton("Deposit Fill", root.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-208f, -26f), 120f, 28f).GetComponent<Button>().onClick).AddListener(new UnityAction(OnDepositFill)); float num = -238f; float num2 = -122f; GameObject val = GUIManager.Instance.CreateInputField(root.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(150f, -66f), (ContentType)0, "Search", 16, 260f, 30f); m_searchField = val.GetComponent<InputField>(); ((UnityEvent<string>)(object)m_searchField.onValueChanged).AddListener((UnityAction<string>)OnSearchChanged); GUIManager.Instance.CreateText("Order", root.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(num - 60f - 6f - 22f, -66f), averiaSerifBold, 16, Color.white, true, Color.black, 44f, 30f, false).GetComponent<Text>().alignment = (TextAnchor)5; GameObject val2 = GUIManager.Instance.CreateButton(SortLabels[m_sortMode], root.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(num - 30f, -66f), 60f, 30f); ((UnityEvent)val2.GetComponent<Button>().onClick).AddListener(new UnityAction(OnSortClicked)); m_sortButtonText = val2.GetComponentInChildren<Text>(); GUIManager.Instance.CreateText("Types Filter", root.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(num2, -66f), averiaSerifBold, 16, Color.white, true, Color.black, 212f, 30f, false).GetComponent<Text>().alignment = (TextAnchor)4; float num3 = num2 - 106f + 52f; Vector2 val3 = default(Vector2); for (int i = 0; i < ItemTypeFilters.Labels.Length; i++) { int bit = 1 << i; int num4 = i / 2; int num5 = i % 2; ((Vector2)(ref val3))..ctor(num3 + (float)num5 * 108f, -102f - (float)num4 * 32f); GameObject obj = GUIManager.Instance.CreateButton(ItemTypeFilters.Labels[i], root.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), val3, 104f, 28f); Button component = obj.GetComponent<Button>(); ((UnityEvent)component.onClick).AddListener((UnityAction)delegate { OnTypeFilterToggled(bit); }); m_filterButtons.Add(component); Text componentInChildren = obj.GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.fontSize = 14; } } UpdateFilterButtons(); m_storageContent = BuildGridScrollView(root.transform, new Vector2(16f, 16f), new Vector2(num, -88f)); BuildSplitOverlay(root, averiaSerifBold); root.AddComponent<SpiritStoragePanelDragSaver>().Panel = this; } private RectTransform BuildGridScrollView(Transform parent, Vector2 offsetMin, Vector2 offsetMax) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Expected O, but got Unknown float num = 860f + offsetMax.x - offsetMin.x; float num2 = 440f + offsetMax.y - offsetMin.y; GameObject obj = GUIManager.Instance.CreateScrollView(parent, false, true, 8f, 2f, ColorBlock.defaultColorBlock, new Color(0f, 0f, 0f, 0.3f), num, num2); RectTransform component = obj.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 0f); component.anchorMax = new Vector2(1f, 1f); component.offsetMin = offsetMin; component.offsetMax = offsetMax; ScrollRect componentInChildren = obj.GetComponentInChildren<ScrollRect>(); RectTransform content = componentInChildren.content; GraphicRaycaster component2 = ((Component)content).GetComponent<GraphicRaycaster>(); if ((Object)(object)component2 != (Object)null) { Object.DestroyImmediate((Object)(object)component2); } Canvas component3 = ((Component)content).GetComponent<Canvas>(); if ((Object)(object)component3 != (Object)null) { Object.DestroyImmediate((Object)(object)component3); } RectTransform viewport = componentInChildren.viewport; if ((Object)(object)viewport != (Object)null) { viewport.anchorMin = Vector2.zero; viewport.anchorMax = Vector2.one; viewport.offsetMin = Vector2.zero; viewport.offsetMax = Vector2.zero; if ((Object)(object)((Component)viewport).GetComponent<RectMask2D>() == (Object)null && (Object)(object)((Component)viewport).GetComponent<Mask>() == (Object)null) { ((Component)viewport).gameObject.AddComponent<RectMask2D>(); } } VerticalLayoutGroup component4 = ((Component)content).gameObject.GetComponent<VerticalLayoutGroup>(); if ((Object)(object)component4 != (Object)null) { Object.DestroyImmediate((Object)(object)component4); } GridLayoutGroup obj2 = ((Component)content).gameObject.AddComponent<GridLayoutGroup>(); obj2.cellSize = new Vector2(56f, 56f); obj2.spacing = new Vector2(6f, 6f); int num3 = Mathf.RoundToInt(6f); ((LayoutGroup)obj2).padding = new RectOffset(num3, num3, num3, num3); obj2.constraint = (Constraint)1; float num4 = num - 8f - 12f + 6f; obj2.constraintCount = Mathf.Max(1, Mathf.FloorToInt(num4 / 62f)); ((LayoutGroup)obj2).childAlignment = (TextAnchor)0; (((Component)content).gameObject.GetComponent<ContentSizeFitter>() ?? ((Component)content).gameObject.AddComponent<ContentSizeFitter>()).verticalFit = (FitMode)2; return content; } private void BuildSplitOverlay(GameObject root, Font font) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Expected O, but got Unknown //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Expected O, but got Unknown //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Expected O, but got Unknown m_splitOverlay = new GameObject("SplitOverlay", new Type[2] { typeof(RectTransform), typeof(Image) }); m_splitOverlay.transform.SetParent(root.transform, false); RectTransform component = m_splitOverlay.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; ((Graphic)m_splitOverlay.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.6f); GameObject val = GUIManager.Instance.CreateWoodpanel(m_splitOverlay.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 320f, 220f, false); m_splitTitleText = GUIManager.Instance.CreateText("Item", val.transform, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, -30f), font, 18, Color.white, true, Color.black, 280f, 30f, false).GetComponent<Text>(); GameObject val2 = GUIManager.Instance.CreateInputField(val.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -80f), (ContentType)2, "Amount", 16, 140f, 30f); m_splitInput = val2.GetComponent<InputField>(); ((UnityEvent)GUIManager.Instance.CreateButton("Max", val.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(90f, -80f), 70f, 30f).GetComponent<Button>().onClick).AddListener(new UnityAction(OnSplitMax)); ((UnityEvent)GUIManager.Instance.CreateButton("Take", val.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(-80f, 30f), 120f, 34f).GetComponent<Button>().onClick).AddListener(new UnityAction(OnSplitConfirm)); ((UnityEvent)GUIManager.Instance.CreateButton("Cancel", val.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(80f, 30f), 120f, 34f).GetComponent<Button>().onClick).AddListener(new UnityAction(CloseSplitPanel)); m_splitOverlay.SetActive(false); } private void Update() { if ((Object)(object)m_target == (Object)null) { return; } if (Input.GetKeyDown((KeyCode)27)) { if (m_splitOverlay.activeSelf) { CloseSplitPanel(); } else { Close(); } return; } bool flag = InventoryGui.IsVisible(); if (m_inventoryWasVisible && !flag) { Close(); return; } m_inventoryWasVisible = flag; if (m_target.Revision != m_shownRevision) { Refresh(); } UpdateTooltip(); } internal void OnCellHoverEnter(SpiritStorageCell cell) { HideTooltip(); m_hoverCell = cell; m_hoverTime = 0f; } internal void OnCellHoverExit(SpiritStorageCell cell) { if ((Object)(object)m_hoverCell == (Object)(object)cell) { m_hoverCell = null; HideTooltip(); } } private void UpdateTooltip() { if ((Object)(object)m_hoverCell == (Object)null || !((Behaviour)m_hoverCell).isActiveAndEnabled || m_splitOverlay.activeSelf) { HideTooltip(); return; } if ((Object)(object)m_tooltipGo == (Object)null) { m_hoverTime += Time.unscaledDeltaTime; if (m_hoverTime < 0.35f) { return; } ShowTooltip(); } else { SetTooltipTexts(); } PositionTooltip(); } private void ShowTooltip() { Canvas componentInParent = m_root.GetComponentInParent<Canvas>(); Canvas val = ((componentInParent != null) ? componentInParent.rootCanvas : null); if (!((Object)(object)m_tooltipPrefab == (Object)null) && !((Object)(object)val == (Object)null)) { m_tooltipGo = Object.Instantiate<GameObject>(m_tooltipPrefab, ((Component)val).transform, false); ((Object)m_tooltipGo).name = "SpiritStorageTooltip"; m_tooltipGo.transform.SetAsLastSibling(); CanvasGroup obj = m_tooltipGo.GetComponent<CanvasGroup>() ?? m_tooltipGo.AddComponent<CanvasGroup>(); obj.blocksRaycasts = false; obj.interactable = false; SetTooltipTexts(); m_tooltipGo.SetActive(true); } } private void SetTooltipTexts() { if (!((Object)(object)m_tooltipGo == (Object)null) && !((Object)(object)m_hoverCell == (Object)null)) { Transform val = Utils.FindChild(m_tooltipGo.transform, "Topic", (IterativeSearchType)0); if ((Object)(object)val != (Object)null) { ((Component)val).GetComponent<TMP_Text>().text = Localization.instance.Localize(m_hoverCell.TooltipTopic ?? ""); } Transform val2 = Utils.FindChild(m_tooltipGo.transform, "Text", (IterativeSearchType)0); if ((Object)(object)val2 != (Object)null) { ((Component)val2).GetComponent<TMP_Text>().text = Localization.instance.Localize(m_hoverCell.TooltipText ?? ""); } } } private void PositionTooltip() { //IL_0064: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_tooltipGo == (Object)null) { return; } Canvas componentInParent = m_tooltipGo.GetComponentInParent<Canvas>(); Canvas val = ((componentInParent != null) ? componentInParent.rootCanvas : null); RectTransform val2 = (RectTransform)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); Transform transform = m_tooltipGo.transform; RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { return; } Camera val4 = (((int)val.renderMode == 0) ? null : val.worldCamera); Vector2 val5 = default(Vector2); if (RectTransformUtility.ScreenPointToLocalPointInRectangle(val2, Vector2.op_Implicit(Input.mousePosition), val4, ref val5)) { ((Transform)val3).localPosition = new Vector3(val5.x + 16f, val5.y - 16f, 0f); object obj = ((((Transform)val3).childCount > 0) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)val3)); LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)obj); Vector3[] array = (Vector3[])(object)new Vector3[4]; ((RectTransform)obj).GetWorldCorners(array); Vector2 val6 = Vector2.op_Implicit(((Transform)val2).InverseTransformPoint(array[0])); Vector2 val7 = Vector2.op_Implicit(((Transform)val2).InverseTransformPoint(array[2])); Rect rect = val2.rect; Vector2 zero = Vector2.zero; if (val7.x > ((Rect)(ref rect)).xMax) { zero.x = ((Rect)(ref rect)).xMax - val7.x; } if (val6.x + zero.x < ((Rect)(ref rect)).xMin) { zero.x = ((Rect)(ref rect)).xMin - val6.x; } if (val6.y < ((Rect)(ref rect)).yMin) { zero.y = ((Rect)(ref rect)).yMin - val6.y; } if (val7.y + zero.y > ((Rect)(ref rect)).yMax) { zero.y = ((Rect)(ref rect)).yMax - val7.y; } ((Transform)val3).localPosition = ((Transform)val3).localPosition + Vector2.op_Implicit(zero); } } private void HideTooltip() { if ((Object)(object)m_tooltipGo != (Object)null) { Object.Destroy((Object)(object)m_tooltipGo); m_tooltipGo = null; } m_hoverTime = 0f; } public void Open(SpiritStorageContainer target, Player player) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null) && !((Object)(object)player == (Object)null)) { m_target = target; m_player = player; m_inventoryWasVisible = false; m_searchFilter = ""; if ((Object)(object)m_searchField != (Object)null) { m_searchField.SetTextWithoutNotify(string.Empty); } SpiritStorageContainer.LogVerbose($"panel opened on storage at {((Component)target).transform.position}."); m_root.SetActive(true); RestorePosition(); GUIManager.BlockInput(true); SetStatus(null); Refresh(); } } public void Close() { m_hoverCell = null; HideTooltip(); SpiritStorageContainer.LogVerbose("panel closed."); SavePosition(); SpiritStorageContainer target = m_target; m_target = null; m_player = null; m_splitOverlay.SetActive(false); m_root.SetActive(false); GUIManager.BlockInput(false); if ((Object)(object)target != (Object)null) { target.OnPanelClosed(); } } private void RestorePosition() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) float value = SpiritStoragePlugin.ConfigPanelScale.Value; ((Transform)m_rootRt).localScale = new Vector3(value, value, 1f); m_rootRt.anchoredPosition = ClampOnScreen(SpiritStoragePlugin.ConfigPanelPosition.Value); } internal void SavePosition() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_rootRt == (Object)null)) { Vector2 val = ClampOnScreen(m_rootRt.anchoredPosition); m_rootRt.anchoredPosition = val; if (SpiritStoragePlugin.ConfigPanelPosition.Value != val) { SpiritStoragePlugin.ConfigPanelPosition.Value = val; } } } private Vector2 ClampOnScreen(Vector2 pos) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_008e: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Transform)m_rootRt).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val == (Object)null) { return pos; } Rect rect = m_rootRt.rect; Vector2 val2 = Vector2.Scale(((Rect)(ref rect)).size, Vector2.op_Implicit(((Transform)m_rootRt).localScale)); rect = val.rect; Vector2 val3 = (((Rect)(ref rect)).size - val2) * 0.5f; val3 = Vector2.Max(val3, Vector2.zero); return new Vector2(Mathf.Clamp(pos.x, 0f - val3.x, val3.x), Mathf.Clamp(pos.y, 0f - val3.y, val3.y)); } private void OnSearchChanged(string value) { m_searchFilter = value ?? ""; Refresh(); } private void OnTypeFilterToggled(int bit) { m_typeMask ^= bit; SpiritStoragePlugin.ConfigPanelTypeFilters.Value = ItemTypeFilters.FormatMask(m_typeMask); UpdateFilterButtons(); Refresh(); } private void UpdateFilterButtons() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < m_filterButtons.Count; i++) { bool flag = (m_typeMask & (1 << i)) != 0; bool flag2 = m_typeMask == 0 || flag; Image component = ((Component)m_filterButtons[i]).GetComponent<Image>(); if ((Object)(object)component != (Object)null) { ((Graphic)component).color = (flag ? FilterOnTint : (flag2 ? Color.white : FilterOffTint)); } Text componentInChildren = ((Component)m_filterButtons[i]).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { ((Graphic)componentInChildren).color = (Color)(flag ? GUIManager.Instance.ValheimOrange : (flag2 ? Color.white : new Color(0.7f, 0.7f, 0.7f, 1f))); } } } private void OnSortClicked() { m_sortMode = (m_sortMode + 1) % SortLabels.Length; SpiritStoragePlugin.ConfigPanelSortMode.Value = m_sortMode; if ((Object)(object)m_sortButtonText != (Object)null) { m_sortButtonText.text = SortLabels[m_sortMode]; } Refresh(); } private void OnDepositAll() { if (!((Object)(object)m_target == (Object)null) && !((Object)(object)m_player == (Object)null)) { m_target.DepositAll(m_player, SetStatus); } } private void OnDepositFill() { if (!((Object)(object)m_target == (Object)null) && !((Object)(object)m_player == (Object)null)) { m_target.DepositAll(m_player, SetStatus, onlyExisting: true); } } public void RequestTake(StorageGroup group) { if (!((Object)(object)m_target == (Object)null) && !((Object)(object)m_player == (Object)null) && group.BackingItems.Count != 0) { m_target.Withdraw(group, SpiritStorageContainer.EffectiveMaxStack(group.BackingItems[0]), m_player, SetStatus); } } public void RequestTakeAll(StorageGroup group) { if (!((Object)(object)m_target == (Object)null) && !((Object)(object)m_player == (Object)null)) { m_target.Withdraw(group, group.TotalCount, m_player, SetStatus); } } public void OpenSplitPanel(StorageGroup group) { if (group != null && group.BackingItems.Count != 0) { m_splitGroup = group; m_splitTitleText.text = group.DisplayName; m_splitInput.SetTextWithoutNotify("1"); m_splitOverlay.SetActive(true); } } private void CloseSplitPanel() { m_splitOverlay.SetActive(false); m_splitGroup = null; } private void OnSplitMax() { if (m_splitGroup != null) { m_splitInput.SetTextWithoutNotify(m_splitGroup.TotalCount.ToString()); } } private void OnSplitConfirm() { if (m_splitGroup == null || (Object)(object)m_target == (Object)null || (Object)(object)m_player == (Object)null) { CloseSplitPanel(); return; } if (!int.TryParse(m_splitInput.text, out var result) || result <= 0) { SetStatus("Enter a valid amount."); return; } m_target.Withdraw(m_splitGroup, result, m_player, SetStatus); CloseSplitPanel(); Refresh(); } private void SetStatus(string message) { if ((Object)(object)m_statusText != (Object)null) { m_statusText.text = message ?? ""; } } public void RefreshNow() { Refresh(); } private void Refresh() { if ((Object)(object)m_target == (Object)null) { return; } IEnumerable<StorageGroup> enumerable = m_target.GetGroupedView(); if (!string.IsNullOrEmpty(m_searchFilter)) { enumerable = enumerable.Where((StorageGroup g) => g.DisplayName.IndexOf(m_searchFilter, StringComparison.OrdinalIgnoreCase) >= 0); } if (m_typeMask != 0) { enumerable = enumerable.Where((StorageGroup g) => g.BackingItems.Count > 0 && ItemTypeFilters.Matches(m_typeMask, g.BackingItems[0])); } List<StorageGroup> list = Sort(enumerable).ToList(); m_shownRevision = m_target.Revision; HashSet<string> hashSet = new HashSet<string>(); for (int num = 0; num < list.Count; num++) { StorageGroup storageGroup = list[num]; hashSet.Add(storageGroup.Key); if (!m_activeCells.TryGetValue(storageGroup.Key, out var value)) { value = ((m_freeCells.Count > 0) ? m_freeCells.Pop() : CreateCell()); m_activeCells[storageGroup.Key] = value; value.SetActive(true); } value.transform.SetSiblingIndex(num); PopulateCell(value, storageGroup); } List<string> list2 = null; foreach (KeyValuePair<string, GameObject> activeCell in m_activeCells) { if (!hashSet.Contains(activeCell.Key)) { activeCell.Value.SetActive(false); m_freeCells.Push(activeCell.Value); (list2 ?? (list2 = new List<string>())).Add(activeCell.Key); } } if (list2 != null) { foreach (string item in list2) { m_activeCells.Remove(item); } } m_capacityText.text = $"{m_target.CurrentCount} / {m_target.Capacity} types"; } private IEnumerable<StorageGroup> Sort(IEnumerable<StorageGroup> groups) { return m_sortMode switch { 1 => groups.OrderByDescending<StorageGroup, string>((StorageGroup g) => g.DisplayName, StringComparer.OrdinalIgnoreCase), 2 => groups.OrderByDescending((StorageGroup g) => g.TotalCount).ThenBy<StorageGroup, string>((StorageGroup g) => g.DisplayName, StringComparer.OrdinalIgnoreCase), 3 => groups.OrderBy((StorageGroup g) => g.TotalCount).ThenBy<StorageGroup, string>((StorageGroup g) => g.DisplayName, StringComparer.OrdinalIgnoreCase), 4 => groups.OrderBy((StorageGroup g) => (g.BackingItems.Count > 0) ? ((int)g.BackingItems[0].m_shared.m_itemType) : int.MaxValue).ThenBy<StorageGroup, string>((StorageGroup g) => g.DisplayName, StringComparer.OrdinalIgnoreCase), _ => groups.OrderBy<StorageGroup, string>((StorageGroup g) => g.DisplayName, StringComparer.OrdinalIgnoreCase), }; } private GameObject GetElementPrefab() { if ((Object)(object)m_elementPrefab == (Object)null && (Object)(object)InventoryGui.instance != (Object)null && (Object)(object)InventoryGui.instance.m_playerGrid != (Object)null) { m_elementPrefab = InventoryGui.instance.m_playerGrid.m_elementPrefab; } return m_elementPrefab; } private GameObject CreateCell() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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) GameObject elementPrefab = GetElementPrefab(); GameObject val = (GameObject)(((Object)(object)elementPrefab != (Object)null) ? ((object)Object.Instantiate<GameObject>(elementPrefab, (Transform)(object)m_storageContent, false)) : ((object)new GameObject("SpiritStorageCell", new Type[1] { typeof(RectTransform) }))); ((Object)val).name = "SpiritStorageCell"; GameObject val2 = new GameObject("RarityTint", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform component = val2.GetComponent<RectTransform>(); val2.transform.SetParent(val.transform, false); ((Transform)component).SetAsFirstSibling(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; Image component2 = val2.GetComponent<Image>(); ((Graphic)component2).color = new Color(0f, 0f, 0f, 0.35f); ((Graphic)component2).raycastTarget = false; SpiritStorageCell spiritStorageCell = val.AddComponent<SpiritStorageCell>(); spiritStorageCell.Panel = this; spiritStorageCell.Element = val.GetComponent<InventoryElement>(); spiritStorageCell.RarityTint = component2; InventoryElement element = spiritStorageCell.Element; if ((Object)(object)element != (Object)null) { if ((Object)(object)element.m_equiped != (Object)null) { ((Behaviour)element.m_equiped).enabled = false; } if ((Object)(object)element.m_queued != (Object)null) { ((Behaviour)element.m_queued).enabled = false; } if ((Object)(object)element.m_noteleport != (Object)null) { ((Behaviour)element.m_noteleport).enabled = false; } if ((Object)(object)element.m_food != (Object)null) { ((Behaviour)element.m_food).enabled = false; } if ((Object)(object)element.m_dropFocus != (Object)null) { ((Behaviour)element.m_dropFocus).enabled = false; } if ((Object)(object)element.m_selected != (Object)null) { element.m_selected.SetActive(false); } if ((Object)(object)element.m_tooltip != (Object)null) { if ((Object)(object)m_tooltipPrefab == (Object)null) { m_tooltipPrefab = element.m_tooltip.m_tooltipPrefab; } ((Behaviour)element.m_tooltip).enabled = false; } } Transform val3 = val.transform.Find("binding"); if ((Object)(object)val3 != (Object)null) { ((Component)val3).gameObject.SetActive(false); } return val; } private void PopulateCell(GameObject cell, StorageGroup group) { //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) SpiritStorageCell component = cell.GetComponent<SpiritStorageCell>(); if ((Object)(object)component == (Object)null) { return; } component.Group = group; InventoryElement element = component.Element; if ((Object)(object)element != (Object)null) { if ((Object)(object)element.m_icon != (Object)null) { element.m_icon.sprite = group.Icon; ((Behaviour)element.m_icon).enabled = (Object)(object)group.Icon != (Object)null; } if ((Object)(object)element.m_amount != (Object)null) { element.m_amount.text = ((group.TotalCount > 1) ? group.TotalCount.ToString() : ""); } if ((Object)(object)element.m_quality != (Object)null) { element.m_quality.text = ((group.Quality > 1) ? group.Quality.ToString() : ""); } if ((Object)(object)element.m_durability != (Object)null) { if (group.DurabilityPercent >= 0f) { ((Component)element.m_durability).gameObject.SetActive(true); element.m_durability.SetMaxValue(1f); element.m_durability.SetValue(group.DurabilityPercent); element.m_durability.SetColor(Color.Lerp(Color.red, Color.green, Mathf.Clamp01(group.DurabilityPercent))); } else { ((Component)element.m_durability).gameObject.SetActive(false); } } if (group.BackingItems.Count > 0) { component.TooltipTopic = group.DisplayName; component.TooltipText = group.BackingItems[0].GetTooltip(group.TotalCount) + "\n\n<color=#a0a0a0>Click: take one stack\nCtrl+Click: take all\nShift+Click: choose amount</color>"; } } if ((Object)(object)component.RarityTint != (Object)null) { if (group.BackingItems.Count > 0 && ItemNaming.TryGetRarityColor(group.BackingItems[0], out var color)) { color.a = 0.55f; ((Graphic)component.RarityTint).color = color; } else { ((Graphic)component.RarityTint).color = new Color(0f, 0f, 0f, 0.35f); } } } } internal class SpiritStorageCell : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, IPointerEnterHandler, IPointerExitHandler { public SpiritStoragePanel Panel; public StorageGroup Group; public InventoryElement Element; public Image RarityTint; public string TooltipTopic; public string TooltipText; public void OnPointerEnter(PointerEventData eventData) { Panel?.OnCellHoverEnter(this); } public void OnPointerExit(PointerEventData eventData) { Panel?.OnCellHoverExit(this); } private void OnDisable() { Panel?.OnCellHoverExit(this); } public void OnPointerClick(PointerEventData eventData) { if (!((Object)(object)Panel == (Object)null) && Group != null) { bool num = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); bool flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); if (num) { Panel.OpenSplitPanel(Group); } else if (flag) { Panel.RequestTakeAll(Group); } else { Panel.RequestTake(Group); } } } } internal class SpiritStoragePanelDragSaver : MonoBehaviour, IEndDragHandler, IEventSystemHandler { public SpiritStoragePanel Panel; public void OnEndDrag(PointerEventData eventData) { Panel?.SavePosition(); } } internal static class ItemTypeFilters { public static readonly string[] Labels = new string[15] { "Food", "Potions", "Metals", "Woods", "Ingredients", "Valuables", "Weapons", "Ranged", "Ammo", "Armour", "Magic", "Tools", "Trophies", "Misc", "Mods" }; private static readonly int Food = Bit("Food"); private static readonly int Potions = Bit("Potions"); private static readonly int Metals = Bit("Metals"); private static readonly int Woods = Bit("Woods"); private static readonly int Ingredients = Bit("Ingredients"); private static readonly int Valuables = Bit("Valuables"); private static readonly int Weapons = Bit("Weapons"); private static readonly int Ranged = Bit("Ranged"); private static readonly int Ammo = Bit("Ammo"); private static readonly int Armour = Bit("Armour"); private static readonly int Magic = Bit("Magic"); private static readonly int Tools = Bit("Tools"); private static readonly int Trophies = Bit("Trophies"); private static readonly int Misc = Bit("Misc"); private static readonly int Mods = Bit("Mods"); private static readonly string[] MetalHints = new string[11] { "Ore", "Scrap", "Metal", "Copper", "Tin", "Bronze", "Iron", "Silver", "Flametal", "Nails", "Chain" }; private static readonly string[] WoodHints = new string[3] { "Wood", "Log", "Bark" }; private static int Bit(string label) { return 1 << Array.IndexOf(Labels, label); } public static int ParseMask(string saved) { int num = 0; string[] array = (saved ?? "").Split(new char[1] { ',' }); foreach (string text in array) { int num2 = Array.IndexOf(Labels, text.Trim()); if (num2 >= 0) { num |= 1 << num2; } } return num; } public static string FormatMask(int mask) { return string.Join(",", Labels.Where((string _, int i) => (mask & (1 << i)) != 0)); } public static bool Matches(int mask, ItemData item) { if (mask != 0) { return (mask & Categorize(item)) != 0; } return true; } private static int Categorize(ItemData item) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected I4, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_0142: Expected I4, but got Unknown //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Invalid comparison between Unknown and I4 //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Invalid comparison between Unknown and I4 SharedData shared = item.m_shared; string text = SpiritStorageContainer.ResolvePrefabName(item) ?? ""; int num = 0; ItemType itemType = shared.m_itemType; switch (itemType - 1) { case 1: num |= ((shared.m_food > 0f || shared.m_foodStamina > 0f || shared.m_foodEitr > 0f) ? Food : Potions); break; case 0: if (ContainsAny(text, MetalHints)) { num |= Metals; } else if (ContainsAny(text, WoodHints)) { num |= Woods; } else if (shared.m_value <= 0) { num |= Ingredients; } break; case 2: case 3: case 13: case 21: { SkillType skillType = shared.m_skillType; switch (skillType - 8) { default: if ((int)skillType == 104) { goto case 4; } goto case 3; case 0: case 6: num |= Ranged; break; case 1: case 2: num |= Ranged | Magic; break; case 4: num |= Tools; break; case 3: case 5: num |= (((int)shared.m_itemType == 4) ? Ranged : Weapons); break; } break; } case 8: case 22: num |= Ammo; break; case 4: case 5: case 6: case 10: case 11: case 16: case 17: case 23: num |= Armour; break; case 14: case 18: num |= Tools; break; case 12: num |= Trophies; break; } if (shared.m_value > 0) { num |= Valuables; } if (ItemNaming.TryGetRarityColor(item, out var _)) { num |= Magic; } if (IsModded(text)) { num |= Mods; } if ((num & ~Mods) == 0) { num |= Misc; } return num; } private static bool ContainsAny(string text, string[] hints) { foreach (string value in hints) { if (text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static bool IsModded(string prefabName) { try { return ModQuery.GetPrefab(prefabName) != null; } catch (Exception) { return false; } } } [BepInPlugin("com.codex.valheim.spiritstorage", "Spirit Storage", "0.10.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class SpiritStoragePlugin : BaseUnityPlugin { public const string ModGuid = "com.codex.valheim.spiritstorage"; public const string ModName = "Spirit Storage"; public const string ModVersion = "0.10.3"; private const string PrefabName = "SpiritStorage"; private const string PieceToken = "$piece_spiritstorage"; private const string PieceDescriptionTok