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 OdinStorage v0.9.2
OdinStorage.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using MultiUserChest; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("OdinStorage")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.9.2.0")] [assembly: AssemblyInformationalVersion("0.9.2+7e44c6754e1e9574d28153a423cd57c5ba95fc8d")] [assembly: AssemblyProduct("OdinStorage")] [assembly: AssemblyTitle("OdinStorage")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.9.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 OdinStorage { public static class DevTools { private static readonly (string Prefab, int Amount)[] Loadout = new(string, int)[25] { ("BlackMetal", 300), ("Flax", 200), ("LinenThread", 200), ("Needle", 100), ("Tar", 200), ("ArrowNeedle", 200), ("ArrowFrost", 200), ("Barley", 100), ("BarleyFlour", 100), ("Cloudberry", 100), ("LoxMeat", 80), ("CookedLoxMeat", 80), ("LoxPie", 40), ("BloodPudding", 40), ("FishWraps", 40), ("Bread", 40), ("MeadHealthMedium", 30), ("MeadStaminaMedium", 30), ("MeadStaminaLingering", 30), ("DustEpic", 500), ("EssenceEpic", 500), ("ReagentEpic", 500), ("ShardEpic", 999), ("RunestoneEpic", 200), ("Coins", 9999) }; private static readonly (string Prefab, string[] Effects)[] MagicGear = new(string, string[])[7] { ("AxeBlackMetal", new string[6] { "Executioner", "LifeSteal", "ChainLightning", "ModifyPhysicalDamage", "ModifyStaggerDamage", "ModifyAttackSpeed" }), ("BowDraugrFang", new string[6] { "Executioner", "TripleBowShot", "ChainLightning", "ModifyPhysicalDamage", "LifeSteal", "ExplosiveArrows" }), ("ShieldBlackmetal", new string[6] { "ModifyBlockPower", "ModifyBlockForce", "ModifyParry", "ModifyParryWindow", "Immovable", "AvoidDamageTaken" }), ("ArmorPaddedCuirass", new string[6] { "ModifyArmor", "BulkUp", "IncreaseHealth", "ReflectDamage", "AvoidDamageTaken", "AddPhysicalResistancePercentage" }), ("ArmorPaddedGreaves", new string[6] { "ModifyArmor", "BulkUp", "ModifyMovementSpeed", "ModifySprintStaminaUse", "ModifyDodgeStaminaUse", "DoubleJump" }), ("HelmetPadded", new string[6] { "ModifyArmor", "ModifyHealthRegen", "AddElementalResistancePercentage", "AddPhysicalResistancePercentage", "QuickLearner", "ModifyDiscoveryRadius" }), ("CapeLox", new string[6] { "ModifyArmor", "AddCarryWeight", "IncreaseHealth", "ModifyHealthRegen", "ModifyEitrRegen", "AddElementalResistancePercentage" }) }; private static readonly Vector2i AutoSlot = new Vector2i(-1, -1); private static readonly List<GameObject> Spawned = new List<GameObject>(); public static void SpawnTestStorage() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0089: 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_008f: 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_0095: 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_009e: 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_00a5: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00e2: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_0107: 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_010c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { Plugin.Log.LogWarning((object)"Dev: ZNetScene not ready yet."); return; } GameObject prefab = instance.GetPrefab("piece_chest_wood"); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)"Dev: prefab 'piece_chest_wood' not found."); return; } Transform transform = ((Component)localPlayer).transform; Vector3 val = transform.forward; val.y = 0f; val = ((((Vector3)(ref val)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val)).normalized : Vector3.forward); Vector3 val2 = Vector3.Cross(Vector3.up, val); Vector3 normalized = ((Vector3)(ref val2)).normalized; Vector3 val3 = transform.position + val * 2f; Quaternion val4 = Quaternion.LookRotation(val); List<Container> list = new List<Container>(); int num = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 2; j++) { Vector3 val5 = val3 + val * ((float)i * 1.2f) + normalized * (((float)j - 0.5f) * 1.2f); GameObject val6 = Object.Instantiate<GameObject>(prefab, val5, val4); Spawned.Add(val6); Container component = val6.GetComponent<Container>(); if ((Object)(object)component != (Object)null) { list.Add(component); } num++; } } int num2 = FillLoadout(list); int num3 = FillMagicGear(list); Plugin.Log.LogInfo((object)$"Dev: spawned {num} chests, filled with {num2} loadout item types, {num3} test gear pieces"); } private static int FillLoadout(List<Container> containers) { if ((Object)(object)ObjectDB.instance == (Object)null || containers.Count == 0) { return 0; } int num = 0; int num2 = 0; (string, int)[] loadout = Loadout; for (int i = 0; i < loadout.Length; i++) { (string, int) tuple = loadout[i]; string item = tuple.Item1; int item2 = tuple.Item2; GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { continue; } int num3 = Mathf.Max(1, item2); int maxStack = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize); bool flag = false; while (num3 > 0 && num < containers.Count) { Inventory val2 = (((Object)(object)containers[num] != (Object)null) ? containers[num].GetInventory() : null); int num4 = ((val2 != null) ? FitAmount(val2, val, maxStack, num3) : 0); if (num4 <= 0) { num++; continue; } val2.AddItem(itemPrefab, num4); num3 -= num4; flag = true; } if (flag) { num2++; } if (num3 > 0) { Plugin.Log.LogWarning((object)$"Dev: ran out of chest space, {num3} of {item} not placed."); } } return num2; } private static int FitAmount(Inventory inv, ItemDrop drop, int maxStack, int want) { string name = drop.m_itemData.m_shared.m_name; List<ItemData> allItems = inv.GetAllItems(); int num = 0; foreach (ItemData item in allItems) { if (item?.m_shared != null && item.m_shared.m_name == name && item.m_stack < maxStack) { num += maxStack - item.m_stack; } } int num2 = inv.GetWidth() * inv.GetHeight(); int num3 = Mathf.Max(0, num2 - allItems.Count); num += num3 * maxStack; return Mathf.Min(want, num); } private static int FillMagicGear(List<Container> containers) { //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01b6: 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) if (!EpicLootMagic.Available) { Plugin.Log.LogInfo((object)"Dev: EpicLoot not present — skipping magic test gear."); return 0; } if ((Object)(object)ObjectDB.instance == (Object)null || containers.Count == 0) { return 0; } int num = 0; List<string> list = new List<string>(); (string, string[])[] magicGear = MagicGear; for (int i = 0; i < magicGear.Length; i++) { (string, string[]) tuple = magicGear[i]; string item = tuple.Item1; string[] item2 = tuple.Item2; GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("Dev: gear prefab '" + item + "' unknown in this version — skipped.")); continue; } ItemData val2 = val.m_itemData.Clone(); val2.m_stack = 1; val2.m_quality = val2.m_shared.m_maxQuality; val2.m_durability = val2.GetMaxDurability(); val2.m_crafterName = "Dev"; if (!EpicLootMagic.TryForceEffects(val2, item2, out string rarityName, out List<string> skipped)) { Plugin.Log.LogWarning((object)("Dev: could not build test gear '" + item + "', skipped.")); continue; } foreach (string item3 in skipped) { list.Add(item + ": " + item3); } bool flag = false; foreach (Container container in containers) { Inventory val3 = (((Object)(object)container != (Object)null) ? container.GetInventory() : null); if (val3 != null && val3.CanAddItem(val2, 1)) { Inventory val4 = new Inventory("dev_gear", (Sprite)null, 1, 1); val4.AddItem(val2); ContainerHandler.AddItemToChest(container, val2, val4, AutoSlot, ZDOID.None, val2.m_stack); flag = true; num++; break; } } if (flag) { int num2 = item2.Length - skipped.Count; Plugin.Log.LogInfo((object)$"Dev: placed {rarityName} test gear '{item}' ({num2}/{item2.Length} effects)."); } else { Plugin.Log.LogWarning((object)("Dev: no chest space for test gear '" + item + "'.")); } } if (list.Count > 0) { Plugin.Log.LogWarning((object)string.Format("Dev: {0} effect(s) skipped (not allowed for slot): {1}", list.Count, string.Join(", ", list))); } return num; } public static void ClearTestStorage() { ZNetScene instance = ZNetScene.instance; int num = 0; foreach (GameObject item in Spawned) { if ((Object)(object)item == (Object)null) { continue; } ZNetView component = item.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.ClaimOwnership(); if ((Object)(object)instance != (Object)null) { instance.Destroy(item); num++; continue; } } Object.Destroy((Object)(object)item); num++; } Spawned.Clear(); Plugin.Log.LogInfo((object)$"Dev: removed {num} test chests"); } } public static class EpicLootMagic { private static bool _probed; private static bool _available; private static ConstructorInfo? _magicItemCtor; private static ConstructorInfo? _effectCtor; private static FieldInfo? _rarityField; private static FieldInfo? _effectsField; private static MethodInfo? _saveMagicItem; private static MethodInfo? _getDefinition; private static MethodInfo? _getAvailableEffects; private static FieldInfo? _valuesPerRarityField; private static Type? _valuesPerRarityType; private static FieldInfo? _valueDefMaxField; private static PropertyInfo? _definitionTypeProp; private static object? _rarityMythic; private static object? _rarityLegendary; private static bool _useMythicResolved; private static bool _useMythic; public static bool Available { get { Probe(); return _available; } } private static void Probe() { if (_probed) { return; } _probed = true; try { Type type = FindType("EpicLoot.MagicItem"); Type type2 = FindType("EpicLoot.MagicItemEffect"); Type type3 = FindType("EpicLoot.ItemRarity"); Type type4 = FindType("EpicLoot.ItemDataExtensions"); Type type5 = FindType("EpicLoot.MagicItemEffectDefinition"); Type type6 = FindType("EpicLoot.MagicItemEffectDefinitions"); if (type == null || type2 == null || type3 == null || type4 == null || type5 == null || type6 == null) { Plugin.Log.LogInfo((object)"EpicLoot not detected — magic test gear disabled."); return; } _magicItemCtor = type.GetConstructor(Type.EmptyTypes); _effectCtor = type2.GetConstructor(new Type[2] { typeof(string), typeof(float) }); _rarityField = type.GetField("Rarity", BindingFlags.Instance | BindingFlags.Public); _effectsField = type.GetField("Effects", BindingFlags.Instance | BindingFlags.Public); _saveMagicItem = type4.GetMethod("SaveMagicItem", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(ItemData), type }, null); _getDefinition = type6.GetMethod("Get", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); _getAvailableEffects = type6.GetMethod("GetAvailableEffects", BindingFlags.Static | BindingFlags.Public, null, new Type[6] { typeof(ItemData), type, typeof(int), typeof(bool), typeof(bool), typeof(bool) }, null); _valuesPerRarityField = type5.GetField("ValuesPerRarity", BindingFlags.Instance | BindingFlags.Public); _valuesPerRarityType = _valuesPerRarityField?.FieldType; _valueDefMaxField = (_valuesPerRarityType?.GetField("Mythic", BindingFlags.Instance | BindingFlags.Public)?.FieldType)?.GetField("MaxValue", BindingFlags.Instance | BindingFlags.Public); _definitionTypeProp = type5.GetProperty("Type", BindingFlags.Instance | BindingFlags.Public); _rarityMythic = Enum.ToObject(type3, 4); _rarityLegendary = Enum.ToObject(type3, 3); _available = _magicItemCtor != null && _effectCtor != null && _rarityField != null && _effectsField != null && _saveMagicItem != null && _getDefinition != null && _valuesPerRarityField != null && _valuesPerRarityType != null && _valueDefMaxField != null; if (!_available) { Plugin.Log.LogWarning((object)"EpicLoot present but API shape unexpected — magic test gear disabled."); } } catch (Exception ex) { _available = false; Plugin.Log.LogWarning((object)("EpicLoot probe failed — magic test gear disabled (" + ex.Message + ").")); } } public static bool TryForceEffects(ItemData item, IList<string> effectTypes, out string rarityName, out List<string> skipped) { rarityName = string.Empty; skipped = new List<string>(); Probe(); if (!_available || item == null || effectTypes == null) { return false; } try { bool flag = UseMythic(); object value = (flag ? _rarityMythic : _rarityLegendary); rarityName = (flag ? "Mythic" : "Legendary"); object obj = _magicItemCtor.Invoke(null); _rarityField.SetValue(obj, value); IList list = (IList)_effectsField.GetValue(obj); list.Clear(); HashSet<string> allowedEffectTypes = GetAllowedEffectTypes(item, obj); foreach (string effectType in effectTypes) { if (allowedEffectTypes.Count > 0 && !allowedEffectTypes.Contains(effectType)) { Plugin.Log.LogWarning((object)("Dev: effect '" + effectType + "' not allowed for this item slot — skipped.")); skipped.Add(effectType); continue; } float num = MaxValueFor(effectType, rarityName); object value2 = _effectCtor.Invoke(new object[2] { effectType, num }); list.Add(value2); } if (list.Count == 0) { rarityName = string.Empty; return false; } _saveMagicItem.Invoke(null, new object[2] { item, obj }); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("EpicLoot force-effects failed (" + ex.Message + ").")); rarityName = string.Empty; return false; } } private static bool UseMythic() { if (_useMythicResolved) { return _useMythic; } _useMythicResolved = true; _useMythic = false; try { FieldInfo fieldInfo = _valuesPerRarityType?.GetField("Mythic", BindingFlags.Instance | BindingFlags.Public); string[] array = new string[3] { "ModifyArmor", "ModifyDurability", "ModifyPhysicalDamage" }; foreach (string text in array) { object obj = _getDefinition.Invoke(null, new object[1] { text }); if (obj != null) { object value = _valuesPerRarityField.GetValue(obj); if (value != null) { _useMythic = fieldInfo?.GetValue(value) != null; break; } } } } catch (Exception ex) { Plugin.Log.LogInfo((object)("EpicLoot mythic probe failed, using Legendary (" + ex.Message + ").")); _useMythic = false; } return _useMythic; } private static float MaxValueFor(string effectType, string rarityName) { try { object obj = _getDefinition.Invoke(null, new object[1] { effectType }); if (obj == null) { return 0f; } object value = _valuesPerRarityField.GetValue(obj); if (value == null) { return 0f; } object obj2 = _valuesPerRarityType.GetField(rarityName, BindingFlags.Instance | BindingFlags.Public)?.GetValue(value); if (obj2 == null) { obj2 = _valuesPerRarityType.GetField("Legendary", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value); if (obj2 == null) { return 0f; } } return (_valueDefMaxField.GetValue(obj2) is float num) ? num : 0f; } catch (Exception ex) { Plugin.Log.LogInfo((object)("EpicLoot value lookup for '" + effectType + "' failed (" + ex.Message + ").")); return 0f; } } private static HashSet<string> GetAllowedEffectTypes(ItemData item, object magic) { HashSet<string> hashSet = new HashSet<string>(); if (_getAvailableEffects == null || _definitionTypeProp == null) { return hashSet; } try { if (_getAvailableEffects.Invoke(null, new object[6] { item, magic, -1, true, false, false }) is IEnumerable enumerable) { foreach (object item3 in enumerable) { if (_definitionTypeProp.GetValue(item3) is string item2) { hashSet.Add(item2); } } } } catch (Exception ex) { Plugin.Log.LogInfo((object)("EpicLoot availability check unavailable (" + ex.Message + "); no slot-filter applied.")); hashSet.Clear(); } return hashSet; } private static Type? FindType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(fullName, throwOnError: false); if (type != null) { return type; } } return null; } } [BepInPlugin("com.nicolai.odinstorage", "OdinStorage", "0.9.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string MucGuid = "com.maxsch.valheim.MultiUserChest"; public const string QssGuid = "goldenrevolver.quick_stack_store"; public const string PluginGuid = "com.nicolai.odinstorage"; public const string PluginName = "OdinStorage"; public const string PluginVersion = "0.9.2"; private readonly Harmony _harmony = new Harmony("com.nicolai.odinstorage"); internal static ManualLogSource Log; internal static Plugin Instance; internal static ConfigEntry<KeyboardShortcut> Hotkey; internal static ConfigEntry<float> Radius; internal static ConfigEntry<bool> VerboseLogging; internal static ConfigEntry<bool> DevTools; internal static ConfigEntry<KeyboardShortcut> SpawnKey; internal static ConfigEntry<KeyboardShortcut> ClearKey; internal static ConfigEntry<bool> MarkerEnabled; internal static ConfigEntry<float> MarkerDuration; private void Awake() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Instance = this; Hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Hotkey", new KeyboardShortcut((KeyCode)111, Array.Empty<KeyCode>()), "Key that triggers the chest scan."); Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 20f, "Range in meters."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "If enabled, logs every Container.Awake (very verbose)."); DevTools = ((BaseUnityPlugin)this).Config.Bind<bool>("Dev", "DevTools", false, "Enables the developer keys (spawn/clear test chests)."); SpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Dev", "SpawnKey", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Spawn and fill test chests (only when DevTools is enabled)."); ClearKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Dev", "ClearKey", new KeyboardShortcut((KeyCode)108, Array.Empty<KeyCode>()), "Remove spawned test chests (only when DevTools is enabled)."); MarkerEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Marker", "MarkerEnabled", true, "\"Find item\": marks chests in the world (local visual aid)."); MarkerDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Marker", "MarkerDuration", 30f, "How long the find marker stays visible after closing the terminal (seconds)."); Log.LogInfo((object)"OdinStorage 0.9.2 loaded."); PrefabManager.OnVanillaPrefabsAvailable += TerminalPiece.Register; GUIManager.OnCustomGUIAvailable += StorageTerminalUI.Create; _harmony.PatchAll(); } private void Update() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } KeyboardShortcut value = Hotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { StorageScanner.Scan(); } if (StorageTerminalUI.IsOpen && Input.GetKeyDown((KeyCode)27)) { StorageTerminalUI.Close(); } if (DevTools.Value) { value = SpawnKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { OdinStorage.DevTools.SpawnTestStorage(); } value = ClearKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { OdinStorage.DevTools.ClearTestStorage(); } } } internal void StartCleanup(Vector3 center) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((MonoBehaviour)this).StartCoroutine(StorageCleanup.Run(center, Radius.Value)); } internal void RefreshSoon() { ((MonoBehaviour)this).StartCoroutine(RefreshSoonCo()); } private static IEnumerator RefreshSoonCo() { yield return (object)new WaitForSeconds(0.2f); StorageTerminalUI.Refresh(); } } public static class QssFavorites { private static bool _resolved; private static bool _available; private static MethodInfo? _getPlayerConfig; private static MethodInfo? _isFavorited; public static bool Available { get { Resolve(); return _available; } } private static void Resolve() { if (_resolved) { return; } _resolved = true; try { Type type = AppDomain.CurrentDomain.GetAssemblies().Select(delegate(Assembly a) { try { return a.GetType("QuickStackStore.UserConfig", throwOnError: false); } catch { return (Type)null; } }).FirstOrDefault((Type t) => t != null); if (type == null) { Plugin.Log.LogInfo((object)"QSS not found — favorite protection uses fallback (equipment + hotbar)."); return; } _getPlayerConfig = type.GetMethod("GetPlayerConfig", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(long) }, null); _isFavorited = type.GetMethod("IsItemNameOrSlotFavorited", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null); _available = _getPlayerConfig != null && _isFavorited != null; if (_available) { Plugin.Log.LogInfo((object)"QSS detected — favorites are protected when depositing."); } else { Plugin.Log.LogWarning((object)"QSS found, but favorites API not readable — fallback active."); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("QSS reflection failed (" + ex.Message + ") — fallback active.")); _available = false; } } public static object? GetLocalConfig() { Resolve(); if (!_available) { return null; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } try { return _getPlayerConfig.Invoke(null, new object[1] { localPlayer.GetPlayerID() }); } catch (Exception ex) { Plugin.Log.LogWarning((object)("QSS GetPlayerConfig failed (" + ex.Message + ").")); return null; } } public static bool IsFavorited(object? config, ItemData item) { if (config == null || _isFavorited == null || item == null) { return false; } try { return (bool)_isFavorited.Invoke(config, new object[1] { item }); } catch { return false; } } } public static class StorageCleanup { private static readonly Vector2i AutoSlot = new Vector2i(-1, -1); private const int MoveCap = 5000; private const int PerTokenGuard = 1000; private const int BatchYield = 4; private const int ArriveWaitFrames = 60; private static bool _busy; private static bool _moved; public static bool Busy => _busy; public static int EstimateMoves(Vector3 center, float radius) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, int> dictionary = new Dictionary<string, int>(); Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); foreach (Container item in StorageScanner.NearbyChests(center, radius)) { Inventory inventory = item.GetInventory(); List<ItemData> list = ((inventory != null) ? inventory.GetAllItems() : null); if (list == null) { continue; } Dictionary<string, int> dictionary3 = new Dictionary<string, int>(); foreach (ItemData item2 in list) { if (item2?.m_shared != null) { string name = item2.m_shared.m_name; dictionary3.TryGetValue(name, out var value); dictionary3[name] = value + item2.m_stack; dictionary.TryGetValue(name, out var value2); dictionary[name] = value2 + item2.m_stack; } } foreach (KeyValuePair<string, int> item3 in dictionary3) { dictionary2.TryGetValue(item3.Key, out var value3); if (item3.Value > value3) { dictionary2[item3.Key] = item3.Value; } } } int num = 0; foreach (KeyValuePair<string, int> item4 in dictionary) { dictionary2.TryGetValue(item4.Key, out var value4); num += item4.Value - value4; } return num; } public static IEnumerator Run(Vector3 center, float radius) { //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) if (_busy) { yield break; } _busy = true; List<Container> chests = StorageScanner.NearbyChests(center, radius).ToList(); if (chests.Count < 2) { Plugin.Log.LogInfo((object)"Consolidate: fewer than two chests within range — nothing to do."); _busy = false; StorageTerminalUI.Refresh(); yield break; } Dictionary<string, int> before = CountByToken(chests); LogSlotUsage(chests); Inventory transit = new Inventory("odin_cleanup_transit", (Sprite)null, 8, 6); int moves = 0; foreach (string token in before.Keys.ToList()) { int guard = 0; while (moves < 5000 && guard++ < 1000) { List<Container> list = (from c in chests where IsValid(c) && CountInChest(c, token) > 0 orderby CountInChest(c, token) descending select c).ToList(); if (list.Count <= 1) { break; } Container source = list[list.Count - 1]; ItemData item = FirstItemOfToken(source, token); if (item == null) { break; } Container val = ((IEnumerable<Container>)list).FirstOrDefault((Func<Container, bool>)((Container h) => (Object)(object)h != (Object)(object)source && CapacityFor(h, item) > 0)); if ((Object)(object)val == (Object)null) { val = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)((Container c) => (Object)(object)c != (Object)(object)source && IsValid(c) && CapacityFor(c, item) > 0)); } if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)source) { break; } int num = Mathf.Min(item.m_stack, CapacityFor(val, item)); if (num <= 0) { break; } _moved = false; yield return MoveViaTransit(source, val, token, item, num, transit); if (!_moved) { break; } moves++; if (moves % 4 == 0) { yield return null; } } } yield return FlushTransit(transit, chests); Dictionary<string, int> after = CountByToken(chests); bool flag = Verify(before, after, transit, moves); _busy = false; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, flag ? $"Storage consolidated ({moves} moves)" : "Consolidate: WARNING — item count mismatch!", 0, (Sprite)null); } StorageTerminalUI.Refresh(); } private static IEnumerator MoveViaTransit(Container source, Container sink, string token, ItemData item, int amt, Inventory transit) { if (!IsValid(source) || !IsValid(sink)) { yield break; } int transitBefore = TotalStacks(transit); try { ContainerHandler.RemoveItemFromChest(source, item, transit, AutoSlot, ZDOID.None, amt, (ItemData)null); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Consolidate: removing from chest failed (" + ex.Message + ").")); yield break; } int waited = 0; while (TotalStacks(transit) <= transitBefore && waited < 60) { waited++; yield return null; } ItemData val = ((IEnumerable<ItemData>)transit.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i?.m_shared != null && i.m_shared.m_name == token)); if (val != null) { try { ContainerHandler.AddItemToChest(sink, val, transit, AutoSlot, ZDOID.None, val.m_stack); _moved = true; } catch (Exception ex2) { Plugin.Log.LogWarning((object)("Consolidate: adding to chest failed (" + ex2.Message + ").")); } yield return null; } } private static IEnumerator FlushTransit(Inventory transit, List<Container> chests) { foreach (ItemData item in transit.GetAllItems().ToList()) { if (item?.m_shared == null) { continue; } Container val = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)((Container c) => IsValid(c) && CapacityFor(c, item) > 0)); if ((Object)(object)val != (Object)null) { try { ContainerHandler.AddItemToChest(val, item, transit, AutoSlot, ZDOID.None, item.m_stack); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Consolidate: flush to chest failed (" + ex.Message + ").")); } yield return null; } } Inventory val2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null); foreach (ItemData item2 in transit.GetAllItems().ToList()) { if (item2?.m_shared != null) { Plugin.Log.LogWarning((object)$"Consolidate: {item2.m_stack}x {item2.m_shared.m_name} found no chest space."); if (val2 != null) { val2.AddItem(item2); } } } } private static bool Verify(Dictionary<string, int> before, Dictionary<string, int> after, Inventory transit, int moves) { bool flag = true; foreach (string item in before.Keys.Union(after.Keys)) { before.TryGetValue(item, out var value); after.TryGetValue(item, out var value2); if (value2 != value) { flag = false; Plugin.Log.LogError((object)$"CONSOLIDATE SAFETY NET: '{item}' before {value}, after {value2} (diff {value2 - value})!"); } } int num = TotalStacks(transit); if (num > 0) { flag = false; Plugin.Log.LogError((object)$"CONSOLIDATE SAFETY NET: {num} item(s) stuck in transit!"); } if (flag) { Plugin.Log.LogInfo((object)$"Consolidate done: {moves} moves, item counts match."); } else { Plugin.Log.LogError((object)"Consolidate: item counts differ — please check storage! (diffs above)"); } return flag; } private static bool IsValid(Container c) { if ((Object)(object)c != (Object)null && (Object)(object)c.m_nview != (Object)null) { return c.m_nview.IsValid(); } return false; } private static void LogSlotUsage(List<Container> chests) { int num = 0; int num2 = 0; foreach (Container chest in chests) { if (IsValid(chest)) { Inventory inventory = chest.GetInventory(); if (inventory != null) { int num3 = inventory.GetWidth() * inventory.GetHeight(); num += num3; num2 += num3 - inventory.GetEmptySlots(); } } } Plugin.Log.LogInfo((object)$"Storage: {num2} / {num} slots used"); } private static Dictionary<string, int> CountByToken(List<Container> chests) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (Container chest in chests) { if (!IsValid(chest)) { continue; } Inventory inventory = chest.GetInventory(); List<ItemData> list = ((inventory != null) ? inventory.GetAllItems() : null); if (list == null) { continue; } foreach (ItemData item in list) { if (item?.m_shared != null) { dictionary.TryGetValue(item.m_shared.m_name, out var value); dictionary[item.m_shared.m_name] = value + item.m_stack; } } } return dictionary; } private static int CountInChest(Container chest, string token) { Inventory inventory = chest.GetInventory(); List<ItemData> list = ((inventory != null) ? inventory.GetAllItems() : null); if (list == null) { return 0; } int num = 0; foreach (ItemData item in list) { if (item?.m_shared != null && item.m_shared.m_name == token) { num += item.m_stack; } } return num; } private static ItemData? FirstItemOfToken(Container chest, string token) { Inventory inventory = chest.GetInventory(); return ((inventory != null) ? inventory.GetAllItems() : null)?.FirstOrDefault((Func<ItemData, bool>)((ItemData it) => it?.m_shared != null && it.m_shared.m_name == token && it.m_stack > 0)); } private static bool IsMergeable(ItemData item) { if (item?.m_shared != null && item.m_shared.m_maxStackSize > 1) { if (item.m_customData != null) { return item.m_customData.Count == 0; } return true; } return false; } private static bool CanMerge(ItemData a, ItemData b) { if (IsMergeable(a) && IsMergeable(b) && a.m_shared.m_name == b.m_shared.m_name && a.m_quality == b.m_quality) { return a.m_variant == b.m_variant; } return false; } private static int CapacityFor(Container chest, ItemData sample) { Inventory inventory = chest.GetInventory(); if (inventory == null) { return 0; } int emptySlots = inventory.GetEmptySlots(); if (!IsMergeable(sample)) { return emptySlots; } int num = Mathf.Max(1, sample.m_shared.m_maxStackSize); int num2 = 0; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem != null && CanMerge(allItem, sample)) { num2 += num - allItem.m_stack; } } return num2 + emptySlots * num; } private static int TotalStacks(Inventory inv) { int num = 0; foreach (ItemData allItem in inv.GetAllItems()) { if (allItem != null) { num += allItem.m_stack; } } return num; } } public static class StorageDeposit { private class ChestModel { public Container Chest; public HashSet<string> Tokens = new HashSet<string>(); public int EmptySlots; public Dictionary<string, int> PartialFree = new Dictionary<string, int>(); public int CapacityFor(string token, int maxStack) { PartialFree.TryGetValue(token, out var value); return value + EmptySlots * maxStack; } public void Reserve(string token, int amount, int maxStack) { PartialFree.TryGetValue(token, out var value); int num = Mathf.Min(amount, value); value -= num; int num2 = amount - num; if (num2 > 0 && EmptySlots > 0) { EmptySlots--; value += maxStack - num2; } PartialFree[token] = value; Tokens.Add(token); } } private static readonly Vector2i AutoSlot = new Vector2i(-1, -1); public static int Deposit(Vector3 center, float radius, out bool leftover) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) leftover = false; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return 0; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return 0; } object localConfig = QssFavorites.GetLocalConfig(); bool flag = localConfig != null; List<ChestModel> list = new List<ChestModel>(); foreach (Container item in StorageScanner.NearbyChests(center, radius)) { Inventory inventory2 = item.GetInventory(); if (inventory2 == null) { continue; } ChestModel chestModel = new ChestModel { Chest = item, EmptySlots = inventory2.GetEmptySlots() }; List<ItemData> allItems = inventory2.GetAllItems(); if (allItems != null) { foreach (ItemData item2 in allItems) { if (item2?.m_shared != null) { string name = item2.m_shared.m_name; chestModel.Tokens.Add(name); int num = Mathf.Max(1, item2.m_shared.m_maxStackSize) - item2.m_stack; if (num > 0) { chestModel.PartialFree.TryGetValue(name, out var value); chestModel.PartialFree[name] = value + num; } } } } list.Add(chestModel); } if (list.Count == 0) { return 0; } int deposited = 0; foreach (ItemData item3 in new List<ItemData>(inventory.GetAllItems())) { if (item3?.m_shared == null || item3.m_equipped) { continue; } if (flag) { if (QssFavorites.IsFavorited(localConfig, item3)) { continue; } } else if (item3.m_gridPos.y == 0) { continue; } string name2 = item3.m_shared.m_name; int maxStack = Mathf.Max(1, item3.m_shared.m_maxStackSize); int stack = item3.m_stack; stack -= DepositIntoChests(item3, name2, maxStack, stack, inventory, list, requireToken: true, ref deposited); if (stack > 0) { stack -= DepositIntoChests(item3, name2, maxStack, stack, inventory, list, requireToken: false, ref deposited); } if (stack > 0) { leftover = true; } } return deposited; } private static int DepositIntoChests(ItemData item, string token, int maxStack, int remaining, Inventory playerInv, List<ChestModel> models, bool requireToken, ref int deposited) { //IL_008d: 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) int num = 0; foreach (ChestModel model in models) { if (remaining - num <= 0) { break; } if (requireToken && !model.Tokens.Contains(token)) { continue; } Container chest = model.Chest; if ((Object)(object)chest == (Object)null || (Object)(object)chest.m_nview == (Object)null || !chest.m_nview.IsValid()) { continue; } int num2 = model.CapacityFor(token, maxStack); if (num2 <= 0) { continue; } int num3 = Mathf.Min(remaining - num, num2); if (num3 > 0) { try { ContainerHandler.AddItemToChest(chest, item, playerInv, AutoSlot, ZDOID.None, num3); model.Reserve(token, num3, maxStack); num += num3; deposited += num3; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Deposit: adding to chest failed (" + ex.Message + ").")); } } } return num; } } public static class StorageMarkers { private const float BeamHeight = 40f; private static readonly List<GameObject> _active = new List<GameObject>(); private static Material? _beamMat; private static readonly Color CyanCore = new Color(0.45f, 0.85f, 1f, 0.95f); private static readonly Color CyanTop = new Color(0.45f, 0.85f, 1f, 0.1f); public static void Show(List<Vector3> chestPositions, Sprite? icon, float duration) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0057: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) Clear(); if (chestPositions == null || chestPositions.Count == 0) { return; } Vector3 viewer = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero); foreach (Vector3 chestPosition in chestPositions) { GameObject val = new GameObject("OdinFindMarker"); val.transform.position = chestPosition; BuildBeam(val, chestPosition); BuildIcon(val, chestPosition, viewer, icon); val.AddComponent<MarkerLifetime>().Init(duration); _active.Add(val); } } public static void Clear() { foreach (GameObject item in _active) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } _active.Clear(); } public static void StartTimers() { foreach (GameObject item in _active) { if ((Object)(object)item != (Object)null) { item.GetComponent<MarkerLifetime>()?.Begin(); } } } internal static void Forget(GameObject go) { _active.Remove(go); } private static Material BeamMaterial() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown if ((Object)(object)_beamMat == (Object)null) { _beamMat = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Standard")) { renderQueue = 4000 }; } return _beamMat; } private static void BuildBeam(GameObject root, Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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) Vector3 a = pos + Vector3.up * 0.4f; Vector3 b = pos + Vector3.up * 40.4f; AddLine(root, "Halo", a, b, 1.4f, 0.5f, new Color(CyanCore.r, CyanCore.g, CyanCore.b, 0.22f), new Color(CyanTop.r, CyanTop.g, CyanTop.b, 0.03f)); AddLine(root, "Core", a, b, 0.55f, 0.12f, CyanCore, CyanTop); } private static void AddLine(GameObject parent, string name, Vector3 a, Vector3 b, float wBottom, float wTop, Color cBottom, Color cTop) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_006d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent.transform, false); LineRenderer obj = val.AddComponent<LineRenderer>(); obj.useWorldSpace = true; obj.positionCount = 2; obj.SetPosition(0, a); obj.SetPosition(1, b); obj.startWidth = wBottom; obj.endWidth = wTop; obj.numCapVertices = 4; obj.alignment = (LineAlignment)0; ((Renderer)obj).sharedMaterial = BeamMaterial(); obj.startColor = cBottom; obj.endColor = cTop; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj).receiveShadows = false; ((Renderer)obj).lightProbeUsage = (LightProbeUsage)0; } private static void BuildIcon(GameObject root, Vector3 chestPos, Vector3 viewer, Sprite? icon) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_00f3: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)icon == (Object)null)) { Vector3 val = viewer - chestPos; val.y = 0f; val = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.forward); Vector3 position = chestPos + val * 0.6f + Vector3.up * 0.35f; GameObject val2 = new GameObject("Icon"); val2.transform.SetParent(root.transform, false); val2.transform.position = position; SpriteRenderer val3 = val2.AddComponent<SpriteRenderer>(); val3.sprite = icon; val3.color = new Color(0.6f, 0.9f, 1f, 1f); ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; Bounds bounds = val3.sprite.bounds; float num = Mathf.Max(0.01f, ((Bounds)(ref bounds)).size.x); val2.transform.localScale = Vector3.one * (0.7f / num); val2.AddComponent<MarkerBillboard>(); } } } public class MarkerLifetime : MonoBehaviour { private float _duration = 30f; private float _remaining; private bool _running; public void Init(float seconds) { _duration = Mathf.Max(0.5f, seconds); } public void Begin() { _remaining = _duration; _running = true; } private void Update() { if (_running) { _remaining -= Time.deltaTime; if (_remaining <= 0f) { Object.Destroy((Object)(object)((Component)this).gameObject); } } } private void OnDestroy() { StorageMarkers.Forget(((Component)this).gameObject); } } public class MarkerBillboard : MonoBehaviour { private float _baseScale = 1f; private SpriteRenderer? _sr; private void Start() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) _baseScale = ((Component)this).transform.localScale.x; _sr = ((Component)this).GetComponent<SpriteRenderer>(); } private void LateUpdate() { //IL_0057: 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_002a: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) Camera val = Utils.GetMainCamera(); if ((Object)(object)val == (Object)null) { val = Camera.main; } if ((Object)(object)val != (Object)null) { ((Component)this).transform.rotation = ((Component)val).transform.rotation; } float num = 0.5f + 0.5f * Mathf.Sin(Time.time * 5f); ((Component)this).transform.localScale = Vector3.one * (_baseScale * (0.9f + 0.15f * num)); if ((Object)(object)_sr != (Object)null) { Color color = _sr.color; color.a = 0.7f + 0.3f * num; _sr.color = color; } } } public class StorageRowHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { private Image? _bg; private static readonly Color Normal = new Color(1f, 1f, 1f, 0f); private static readonly Color Hover = new Color(1f, 1f, 1f, 0.12f); private void Awake() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) _bg = ((Component)this).GetComponent<Image>(); if ((Object)(object)_bg != (Object)null) { ((Graphic)_bg).color = Normal; } } public void OnPointerEnter(PointerEventData eventData) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_bg != (Object)null) { ((Graphic)_bg).color = Hover; } } public void OnPointerExit(PointerEventData eventData) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_bg != (Object)null) { ((Graphic)_bg).color = Normal; } } } public class StorageEntry { public string Token = string.Empty; public string Name = string.Empty; public int Count; public Sprite? Icon; } public class StorageSnapshot { public List<StorageEntry> Entries = new List<StorageEntry>(); public int ChestCount; public int TotalItems; public int TotalSlots; public int UsedSlots; public int AlmostFullChests; } public static class StorageScanner { public static IEnumerable<Container> NearbyChests(Vector3 center, float radius) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) float radiusSqr = radius * radius; Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); Container[] array2 = array; foreach (Container val in array2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.m_nview == (Object)null) && val.m_nview.IsValid() && !(((Object)val).name ?? string.Empty).StartsWith("TreasureChest")) { Vector3 val2 = ((Component)val).transform.position - center; if (!(((Vector3)(ref val2)).sqrMagnitude > radiusSqr)) { yield return val; } } } } public static StorageSnapshot AggregateNearby(Vector3 center, float radius) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, StorageEntry> dictionary = new Dictionary<string, StorageEntry>(); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; foreach (Container item in NearbyChests(center, radius)) { Inventory inventory = item.GetInventory(); if (inventory == null) { continue; } List<ItemData> allItems = inventory.GetAllItems(); num++; int num5 = inventory.GetWidth() * inventory.GetHeight(); int emptySlots = inventory.GetEmptySlots(); num2 += num5; num3 += num5 - emptySlots; if (emptySlots <= 1) { num4++; } foreach (ItemData item2 in allItems) { if (item2?.m_shared == null) { continue; } string name = item2.m_shared.m_name; if (!dictionary.TryGetValue(name, out var value)) { string text = ((Localization.instance != null) ? Localization.instance.Localize(name) : name); if (string.IsNullOrEmpty(text)) { text = name; } Sprite icon = ((item2.m_shared.m_icons != null && item2.m_shared.m_icons.Length != 0) ? item2.m_shared.m_icons[0] : null); value = (dictionary[name] = new StorageEntry { Token = name, Name = text, Icon = icon }); } value.Count += item2.m_stack; } } List<StorageEntry> list = dictionary.Values.OrderByDescending((StorageEntry e) => e.Count).ToList(); int totalItems = list.Sum((StorageEntry e) => e.Count); return new StorageSnapshot { Entries = list, ChestCount = num, TotalItems = totalItems, TotalSlots = num2, UsedSlots = num3, AlmostFullChests = num4 }; } public static void Scan() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } float value = Plugin.Radius.Value; StorageSnapshot storageSnapshot = AggregateNearby(((Component)localPlayer).transform.position, value); Plugin.Log.LogInfo((object)$"=== Storage scan within {value:0.#} m ==="); foreach (StorageEntry entry in storageSnapshot.Entries) { Plugin.Log.LogInfo((object)$"{entry.Name}: {entry.Count}"); } Plugin.Log.LogInfo((object)$"=== {storageSnapshot.ChestCount} chests, {storageSnapshot.Entries.Count} item types, {storageSnapshot.TotalItems} items total ==="); } } public class StorageTerminal : MonoBehaviour, Interactable, Hoverable { public string GetHoverName() { return "Odin Terminal"; } public string GetHoverText() { if (Localization.instance == null) { return "[E] Open Storage"; } return Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] Open Storage"); } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } StorageTerminalUI.Open(((Component)this).transform.position); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } } public static class StorageTerminalUI { [CompilerGenerated] private static class <>O { public static UnityAction <0>__Close; public static UnityAction <1>__DoDeposit; public static UnityAction <2>__OnCleanupClicked; public static UnityAction<string> <3>__OnSearchChanged; public static UnityAction <4>__ConfirmCleanup; public static UnityAction <5>__CancelCleanup; } private const string CatAll = "all"; private const string CatOre = "ore"; private const string CatFood = "food"; private const string CatMaterial = "material"; private const float NameMinWidth = 40f; private const float CountColWidth = 52f; private const float NameCountGap = 10f; private static readonly List<(Text Label, string Full)> _nameLabels = new List<(Text, string)>(); private static GameObject? _panel; private static InputField? _search; private static Text? _header; private static Transform? _content; private static GameObject? _confirmPanel; private static Text? _confirmText; private static RectTransform? _fillRt; private static Image? _fillImg; private static readonly List<GameObject> _rows = new List<GameObject>(); private static readonly List<string> _order = new List<string>(); private static readonly Dictionary<string, StorageEntry> _entries = new Dictionary<string, StorageEntry>(); private static string _query = string.Empty; private static string _category = "all"; private static Vector3 _center; private static readonly string[] OreWords = new string[8] { "copper", "tin", "bronze", "iron", "silver", "blackmetal", "flametal", "ore" }; private static readonly string[] FoodWords = new string[18] { "carrot", "mushroom", "raspberr", "blueberr", "cloudberr", "honey", "meat", "fish", "cooked", "bread", "mead", "sausage", "stew", "soup", "turnip", "onion", "jam", "pie" }; public static bool IsOpen { get { if ((Object)(object)_panel != (Object)null) { return _panel.activeSelf; } return false; } } public static void Create() { //IL_0035: 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_0053: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_024a: 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_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Expected O, but got Unknown //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Expected O, but got Unknown //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_0403: 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_0441: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_panel != (Object)null) && GUIManager.Instance != null && !GUIManager.IsHeadless()) { _panel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 500f, 600f, true); _panel.SetActive(false); Text component = GUIManager.Instance.CreateText("Storage", _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -28f), GUIManager.Instance.AveriaSerifBold, 26, GUIManager.Instance.ValheimOrange, true, Color.black, 140f, 36f, false).GetComponent<Text>(); if ((Object)(object)component != (Object)null) { component.alignment = (TextAnchor)4; component.horizontalOverflow = (HorizontalWrapMode)1; } ButtonClickedEvent onClick = GUIManager.Instance.CreateButton("X", _panel.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-30f, -28f), 40f, 40f).GetComponent<Button>().onClick; object obj = <>O.<0>__Close; if (obj == null) { UnityAction val = Close; <>O.<0>__Close = val; obj = (object)val; } ((UnityEvent)onClick).AddListener((UnityAction)obj); GameObject obj2 = GUIManager.Instance.CreateButton("Deposit", _panel.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(65f, -28f), 110f, 32f); Text componentInChildren = obj2.GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.fontSize = 15; } ButtonClickedEvent onClick2 = obj2.GetComponent<Button>().onClick; object obj3 = <>O.<1>__DoDeposit; if (obj3 == null) { UnityAction val2 = DoDeposit; <>O.<1>__DoDeposit = val2; obj3 = (object)val2; } ((UnityEvent)onClick2).AddListener((UnityAction)obj3); GameObject obj4 = GUIManager.Instance.CreateButton("Consolidate", _panel.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-145f, -28f), 110f, 32f); Text componentInChildren2 = obj4.GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.fontSize = 13; } ButtonClickedEvent onClick3 = obj4.GetComponent<Button>().onClick; object obj5 = <>O.<2>__OnCleanupClicked; if (obj5 == null) { UnityAction val3 = OnCleanupClicked; <>O.<2>__OnCleanupClicked = val3; obj5 = (object)val3; } ((UnityEvent)onClick3).AddListener((UnityAction)obj5); BuildConfirmDialog(_panel.transform); _header = GUIManager.Instance.CreateText(string.Empty, _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -70f), GUIManager.Instance.AveriaSerifBold, 14, GUIManager.Instance.ValheimBeige, true, Color.black, 460f, 38f, false).GetComponent<Text>(); if ((Object)(object)_header != (Object)null) { _header.alignment = (TextAnchor)1; } BuildFillBar(_panel.transform); _search = GUIManager.Instance.CreateInputField(_panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -120f), (ContentType)0, "Search…", 16, 440f, 32f).GetComponent<InputField>(); ((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)OnSearchChanged); BuildFilterBar(_panel.transform); GameObject obj6 = GUIManager.Instance.CreateScrollView(_panel.transform, false, true, 0.6f, 0f, GUIManager.Instance.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.2f), 460f, 395f); RectTransform component2 = obj6.GetComponent<RectTransform>(); component2.anchorMin = new Vector2(0.5f, 0f); component2.anchorMax = new Vector2(0.5f, 0f); component2.pivot = new Vector2(0.5f, 0f); component2.anchoredPosition = new Vector2(0f, 20f); _content = (Transform?)(object)obj6.GetComponentInChildren<ScrollRect>().content; VerticalLayoutGroup val4 = ((Component)_content).gameObject.GetComponent<VerticalLayoutGroup>(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)_content).gameObject.AddComponent<VerticalLayoutGroup>(); } ((HorizontalOrVerticalLayoutGroup)val4).spacing = 4f; ((HorizontalOrVerticalLayoutGroup)val4).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val4).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val4).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val4).childForceExpandHeight = false; ContentSizeFitter val5 = ((Component)_content).gameObject.GetComponent<ContentSizeFitter>(); if ((Object)(object)val5 == (Object)null) { val5 = ((Component)_content).gameObject.AddComponent<ContentSizeFitter>(); } val5.verticalFit = (FitMode)2; ApplyUiScale(); } } private static void ApplyUiScale() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_panel == (Object)null)) { float num = Mathf.Clamp((float)Screen.height / 1080f, 0.8f, 2.5f); _panel.transform.localScale = new Vector3(num, num, 1f); } } private static void BuildFilterBar(Transform parent) { //IL_0018: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_007a: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("OdinFilterBar", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = new Vector2(0f, -156f); component.sizeDelta = new Vector2(460f, 30f); HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj).spacing = 6f; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = true; AddFilterButton(val.transform, "All", "all"); AddFilterButton(val.transform, "Ore/Metal", "ore"); AddFilterButton(val.transform, "Food", "food"); AddFilterButton(val.transform, "Materials", "material"); } private static void AddFilterButton(Transform parent, string label, string category) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown GameObject val = GUIManager.Instance.CreateButton(label, parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 100f, 28f); Text componentInChildren = val.GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.fontSize = 14; } LayoutElement val2 = val.GetComponent<LayoutElement>(); if ((Object)(object)val2 == (Object)null) { val2 = val.AddComponent<LayoutElement>(); } val2.flexibleWidth = 1f; ((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { SetCategory(category); }); } public static void Open(Vector3 center) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_panel == (Object)null) { return; } _center = center; StorageMarkers.Clear(); _query = string.Empty; _category = "all"; if ((Object)(object)_search != (Object)null) { _search.text = string.Empty; } StorageSnapshot storageSnapshot = StorageScanner.AggregateNearby(_center, Plugin.Radius.Value); _order.Clear(); _entries.Clear(); foreach (StorageEntry entry in storageSnapshot.Entries) { _order.Add(entry.Token); _entries[entry.Token] = entry; } UpdateHeader(storageSnapshot); ApplyUiScale(); _panel.SetActive(true); GUIManager.BlockInput(true); ApplyFilters(); } public static void Refresh() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (!IsOpen) { return; } StorageSnapshot storageSnapshot = StorageScanner.AggregateNearby(_center, Plugin.Radius.Value); Dictionary<string, StorageEntry> dictionary = new Dictionary<string, StorageEntry>(); foreach (StorageEntry entry in storageSnapshot.Entries) { dictionary[entry.Token] = entry; } foreach (string item in _order) { StorageEntry value2; if (dictionary.TryGetValue(item, out var value)) { _entries[item] = value; } else if (_entries.TryGetValue(item, out value2)) { value2.Count = 0; } } foreach (StorageEntry entry2 in storageSnapshot.Entries) { if (!_entries.ContainsKey(entry2.Token)) { _order.Add(entry2.Token); _entries[entry2.Token] = entry2; } } UpdateHeader(storageSnapshot); ApplyFilters(); } private static void BuildFillBar(Transform parent) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0049: 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_0073: 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_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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0106: 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_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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_019d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("OdinFillBarBg", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = new Vector2(0f, -96f); component.sizeDelta = new Vector2(440f, 6f); ((Graphic)val.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.5f); GameObject val2 = new GameObject("OdinFillBarFill", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(val.transform, false); _fillRt = val2.GetComponent<RectTransform>(); _fillRt.anchorMin = new Vector2(0f, 0f); _fillRt.anchorMax = new Vector2(0f, 1f); _fillRt.pivot = new Vector2(0f, 0.5f); _fillRt.offsetMin = Vector2.zero; _fillRt.offsetMax = Vector2.zero; _fillImg = val2.GetComponent<Image>(); ((Graphic)_fillImg).color = new Color(0.3f, 0.8f, 0.3f, 1f); } private static void UpdateHeader(StorageSnapshot snap) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) int totalSlots = snap.TotalSlots; int usedSlots = snap.UsedSlots; float num = ((totalSlots > 0) ? ((float)usedSlots / (float)totalSlots) : 0f); int num2 = Mathf.RoundToInt(num * 100f); if ((Object)(object)_header != (Object)null) { string text = $"{snap.ChestCount} chests · {snap.Entries.Count} types · {snap.TotalItems} items"; string text2 = $"{usedSlots} / {totalSlots} slots · {num2}%"; if (snap.AlmostFullChests == 1) { text2 += " · 1 chest nearly full"; } else if (snap.AlmostFullChests > 1) { text2 += $" · {snap.AlmostFullChests} chests nearly full"; } _header.text = text + "\n" + text2; } if ((Object)(object)_fillRt != (Object)null) { _fillRt.anchorMax = new Vector2(Mathf.Clamp01(num), 1f); _fillRt.offsetMin = Vector2.zero; _fillRt.offsetMax = Vector2.zero; } if ((Object)(object)_fillImg != (Object)null) { ((Graphic)_fillImg).color = ((num >= 0.9f) ? new Color(0.85f, 0.25f, 0.2f, 1f) : ((num >= 0.75f) ? new Color(0.9f, 0.8f, 0.2f, 1f) : new Color(0.3f, 0.8f, 0.3f, 1f))); } } public static void Close() { if (!((Object)(object)_panel == (Object)null)) { _panel.SetActive(false); GUIManager.BlockInput(false); StorageMarkers.StartTimers(); } } private static void OnSearchChanged(string query) { _query = query ?? string.Empty; ApplyFilters(); } private static void SetCategory(string category) { _category = category; ApplyFilters(); } private static void ApplyFilters() { List<StorageEntry> list = new List<StorageEntry>(); foreach (string item in _order) { if (_entries.TryGetValue(item, out StorageEntry value) && value.Count > 0) { list.Add(value); } } IEnumerable<StorageEntry> source = list; if (_category != "all") { source = source.Where((StorageEntry e) => Classify(e.Token) == _category); } if (!string.IsNullOrEmpty(_query)) { string q = _query.ToLowerInvariant(); source = source.Where((StorageEntry e) => e.Name.ToLowerInvariant().Contains(q)); } RebuildRows(source.ToList()); } private static string Classify(string token) { string t = token.ToLowerInvariant(); if (OreWords.Any((string w) => t.Contains(w))) { return "ore"; } if (FoodWords.Any((string w) => t.Contains(w))) { return "food"; } return "material"; } private static void RebuildRows(List<StorageEntry> entries) { if ((Object)(object)_content == (Object)null) { return; } foreach (GameObject row in _rows) { Object.Destroy((Object)(object)row); } _rows.Clear(); _nameLabels.Clear(); foreach (StorageEntry entry in entries) { _rows.Add(CreateRow(entry)); } FitNameLabels(); } private static void FitNameLabels() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //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_0068: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_content == (Object)null || _nameLabels.Count == 0) { return; } Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)_content); foreach (var (val, s) in _nameLabels) { if (!((Object)(object)val == (Object)null)) { Rect rect = ((RectTransform)((Component)val).transform).rect; float num = ((Rect)(ref rect)).width - 10f; if (!(num <= 1f)) { val.horizontalOverflow = (HorizontalWrapMode)1; val.text = TruncateToWidth(val, s, num); } } } } private static GameObject CreateRow(StorageEntry e) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("OdinRow", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(_content, false); Image obj = val.AddComponent<Image>(); ((Graphic)obj).color = new Color(1f, 1f, 1f, 0f); ((Graphic)obj).raycastTarget = true; HorizontalLayoutGroup obj2 = val.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 8f; ((LayoutGroup)obj2).childAlignment = (TextAnchor)3; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; LayoutElement obj3 = val.AddComponent<LayoutElement>(); obj3.minHeight = 34f; obj3.preferredHeight = 34f; GameObject val2 = new GameObject("Icon", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(val.transform, false); Image component = val2.GetComponent<Image>(); if ((Object)(object)e.Icon != (Object)null) { component.sprite = e.Icon; component.preserveAspect = true; } else { ((Behaviour)component).enabled = false; } LayoutElement obj4 = val2.AddComponent<LayoutElement>(); obj4.minWidth = 32f; obj4.preferredWidth = 32f; obj4.minHeight = 32f; obj4.preferredHeight = 32f; AddFindButton(val.transform, 56f, e.Token, e.Icon); GameObject val3 = GUIManager.Instance.CreateText(e.Name, val.transform, new Vector2(0f, 0.5f), new Vector2(1f, 0.5f), Vector2.zero, GUIManager.Instance.AveriaSerifBold, 18, Color.white, true, Color.black, 40f, 30f, false); Text component2 = val3.GetComponent<Text>(); if ((Object)(object)component2 != (Object)null) { component2.alignment = (TextAnchor)3; component2.horizontalOverflow = (HorizontalWrapMode)0; component2.verticalOverflow = (VerticalWrapMode)0; _nameLabels.Add((component2, e.Name)); } LayoutElement val4 = val3.GetComponent<LayoutElement>(); if ((Object)(object)val4 == (Object)null) { val4 = val3.AddComponent<LayoutElement>(); } val4.flexibleWidth = 1f; val4.minWidth = 40f; val4.preferredWidth = 40f; val4.minHeight = 30f; val4.preferredHeight = 30f; GameObject val5 = GUIManager.Instance.CreateText(e.Count.ToString(), val.transform, new Vector2(0f, 0.5f), new Vector2(1f, 0.5f), Vector2.zero, GUIManager.Instance.AveriaSerifBold, 18, Color.white, true, Color.black, 52f, 30f, false); Text component3 = val5.GetComponent<Text>(); if ((Object)(object)component3 != (Object)null) { component3.alignment = (TextAnchor)5; component3.horizontalOverflow = (HorizontalWrapMode)1; } LayoutElement val6 = val5.GetComponent<LayoutElement>(); if ((Object)(object)val6 == (Object)null) { val6 = val5.AddComponent<LayoutElement>(); } val6.flexibleWidth = 0f; val6.minWidth = 52f; val6.preferredWidth = 52f; val6.minHeight = 30f; val6.preferredHeight = 30f; AddRowButton(val.transform, "1", 30f, e.Token, WithdrawMode.One); AddRowButton(val.transform, "Stack", 52f, e.Token, WithdrawMode.Stack); AddRowButton(val.transform, "All", 46f, e.Token, WithdrawMode.All); val.AddComponent<StorageRowHover>(); return val; } private static string TruncateToWidth(Text txt, string s, float maxWidth) { if ((Object)(object)txt == (Object)null || string.IsNullOrEmpty(s)) { return s; } txt.text = s; if (txt.preferredWidth <= maxWidth) { return s; } for (int num = s.Length - 1; num >= 1; num--) { string result = (txt.text = s.Substring(0, num).TrimEnd(Array.Empty<char>()) + "…"); if (txt.preferredWidth <= maxWidth) { return result; } } return "…"; } private static void AddRowButton(Transform parent, string label, float width, string token, WithdrawMode mode) { //IL_0026: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown GameObject val = GUIManager.Instance.CreateButton(label, parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, width, 26f); Text componentInChildren = val.GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.fontSize = 13; } LayoutElement val2 = val.GetComponent<LayoutElement>(); if ((Object)(object)val2 == (Object)null) { val2 = val.AddComponent<LayoutElement>(); } val2.minWidth = width; val2.preferredWidth = width; val2.flexibleWidth = 0f; val2.minHeight = 26f; val2.preferredHeight = 26f; ((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { DoWithdraw(token, mode); }); } private static void AddFindButton(Transform parent, float width, string token, Sprite? icon) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown GameObject val = GUIManager.Instance.CreateButton("Find", parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, width, 26f); Text componentInChildren = val.GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.fontSize = 12; } LayoutElement val2 = val.GetComponent<LayoutElement>(); if ((Object)(object)val2 == (Object)null) { val2 = val.AddComponent<LayoutElement>(); } val2.minWidth = width; val2.preferredWidth = width; val2.flexibleWidth = 0f; val2.minHeight = 26f; val2.preferredHeight = 26f; ((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { DoFind(token, icon); }); } private static void DoFind(string token, Sprite? icon) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) StorageMarkers.Clear(); if (!Plugin.MarkerEnabled.Value) { return; } List<Vector3> list = new List<Vector3>(); foreach (Container item in StorageScanner.NearbyChests(_center, Plugin.Radius.Value)) { Inventory inventory = item.GetInventory(); List<ItemData> list2 = ((inventory != null) ? inventory.GetAllItems() : null); if (list2 != null && list2.Any((ItemData it) => it?.m_shared != null && it.m_shared.m_name == token)) { list.Add(((Component)item).transform.position); } } Player localPlayer = Player.m_localPlayer; if (list.Count == 0) { if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "No longer in storage", 0, (Sprite)null); } return; } StorageMarkers.Show(list, icon, Plugin.MarkerDuration.Value); if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, (list.Count == 1) ? "Marked 1 chest" : $"Marked {list.Count} chests", 0, (Sprite)null); } } private static void DoWithdraw(string token, WithdrawMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) bool limited; string itemName; int num = StorageWithdraw.Withdraw(_center, Plugin.Radius.Value, token, mode, out limited, out itemName); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { if (num <= 0 && limited) { ((Character)localPlayer).Message((MessageType)2, "Inventory full", 0, (Sprite)null); } else if (limited) { ((Character)localPlayer).Message((MessageType)2, $"{itemName}: only {num} (inventory full)", 0, (Sprite)null); } else if (num > 0) { ((Character)localPlayer).Message((MessageType)1, $"{itemName} x{num}", 0, (Sprite)null); } } Refresh(); Plugin.Instance?.RefreshSoon(); } private static void DoDeposit() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) bool leftover; int num = StorageDeposit.Deposit(_center, Plugin.Radius.Value, out leftover); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { if (num <= 0 && leftover) { ((Character)localPlayer).Message((MessageType)2, "No space in storage", 0, (Sprite)null); } else if (num <= 0) { ((Character)localPlayer).Message((MessageType)2, "Nothing to deposit", 0, (Sprite)null); } else if (leftover) { ((Character)localPlayer).Message((MessageType)2, $"Deposited {num}, rest didn't fit", 0, (Sprite)null); } else { ((Character)localPlayer).Message((MessageType)1, $"Deposited {num}", 0, (Sprite)null); } } Refresh(); Plugin.Instance?.RefreshSoon(); } private static void BuildConfirmDialog(Transform parent) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0261: 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_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown //IL_029e: 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_02a9: Expected O, but got Unknown GameObject val = new GameObject("OdinConfirmRoot", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; GameObject val2 = new GameObject("Blocker", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(val.transform, false); RectTransform component2 = val2.GetComponent<RectTransform>(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.one; component2.offsetMin = Vector2.zero; component2.offsetMax = Vector2.zero; Image component3 = val2.GetComponent<Image>(); ((Graphic)component3).color = new Color(0f, 0f, 0f, 0.6f); ((Graphic)component3).raycastTarget = true; GameObject val3 = GUIManager.Instance.CreateWoodpanel(val.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 380f, 170f, false); _confirmText = GUIManager.Instance.CreateText(string.Empty, val3.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -40f), GUIManager.Instance.AveriaSerifBold, 18, Color.white, true, Color.black, 340f, 70f, false).GetComponent<Text>(); if ((Object)(object)_confirmText != (Object)null) { _confirmText.alignment = (TextAnchor)1; } ButtonClickedEvent onClick = GUIManager.Instance.CreateButton("Yes, consolidate", val3.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(-90f, 35f), 150f, 36f).GetComponent<Button>().onClick; object obj = <>O.<4>__ConfirmCleanup; if (obj == null) { UnityAction val4 = ConfirmCleanup; <>O.<4>__ConfirmCleanup = val4; obj = (object)val4; } ((UnityEvent)onClick).AddListener((UnityAction)obj); ButtonClickedEvent onClick2 = GUIManager.Instance.CreateButton("Cancel", val3.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(90f, 35f), 150f, 36f).GetComponent<Button>().onClick; object obj2 = <>O.<5>__CancelCleanup; if (obj2 == null) { UnityAction val5 = CancelCleanup; <>O.<5>__CancelCleanup = val5; obj2 = (object)val5; } ((UnityEvent)onClick2).AddListener((UnityAction)obj2); _confirmPanel = val; _confirmPanel.SetActive(false); } private static void OnCleanupClicked() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_confirmPanel == (Object)null) && !StorageCleanup.Busy) { int num = StorageCleanup.EstimateMoves(_center, Plugin.Radius.Value); if ((Object)(object)_confirmText != (Object)null) { _confirmText.text = $"Consolidate storage?\nMoves up to {num} items."; } _confirmPanel.SetActive(true); _confirmPanel.transform.SetAsLastSibling(); } } private static void CancelCleanup() { if ((Object)(object)_confirmPanel != (Object)null) { _confirmPanel.SetActive(false); } } private static void ConfirmCleanup() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_confirmPanel != (Object)null) { _confirmPanel.SetActive(false); } Plugin.Instance?.StartCleanup(_center); } } public enum WithdrawMode { One, Stack, All } public static class StorageWithdraw { private static readonly Vector2i AutoSlot = new Vector2i(-1, -1); public static int Withdraw(Vector3 center, float radius, string token, WithdrawMode mode, out bool limited, out string itemName) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) limited = false; itemName = token; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return 0; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return 0; } List<(Container, ItemData)> list = new List<(Container, ItemData)>(); ItemData val = null; int num = 0; foreach (Container item in StorageScanner.NearbyChests(center, radius)) { Inventory inventory2 = item.GetInventory();