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.1.0")] [assembly: AssemblyInformationalVersion("0.9.1+edc40185618c27011aa3f32a774c917b660673b2")] [assembly: AssemblyProduct("OdinStorage")] [assembly: AssemblyTitle("OdinStorage")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.9.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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)[29] { ("Silver", 500), ("Obsidian", 200), ("Crystal", 100), ("FreezeGland", 100), ("WolfPelt", 200), ("WolfFang", 100), ("TrophyWolf", 20), ("Iron", 300), ("Bronze", 200), ("DragonTear", 50), ("DragonEgg", 3), ("ArrowFrost", 200), ("ArrowObsidian", 200), ("ArrowNeedle", 200), ("WolfMeatSkewer", 40), ("SerpentStew", 30), ("Eyescream", 40), ("Cloudberry", 100), ("Blueberries", 100), ("Onion", 80), ("MeadFrostResist", 30), ("MeadHealthMedium", 30), ("MeadStaminaMedium", 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] { ("AxeIron", new string[6] { "Executioner", "LifeSteal", "ChainLightning", "ModifyPhysicalDamage", "ModifyStaggerDamage", "ModifyAttackSpeed" }), ("BowDraugrFang", new string[6] { "Executioner", "TripleBowShot", "ChainLightning", "ModifyPhysicalDamage", "LifeSteal", "ExplosiveArrows" }), ("ShieldSerpentscale", new string[6] { "ModifyBlockPower", "ModifyBlockForce", "ModifyParry", "ModifyParryWindow", "Immovable", "AvoidDamageTaken" }), ("ArmorWolfChest", new string[6] { "ModifyArmor", "BulkUp", "IncreaseHealth", "ReflectDamage", "AvoidDamageTaken", "AddPhysicalResistancePercentage" }), ("ArmorWolfLegs", new string[6] { "ModifyArmor", "BulkUp", "ModifyMovementSpeed", "ModifySprintStaminaUse", "ModifyDodgeStaminaUse", "DoubleJump" }), ("HelmetDrake", new string[6] { "ModifyArmor", "ModifyHealthRegen", "AddElementalResistancePercentage", "AddPhysicalResistancePercentage", "QuickLearner", "ModifyDiscoveryRadius" }), ("CapeWolf", new string[6] { "ModifyArmor", "AddCarryWeight", "IncreaseHealth", "ModifyHealthRegen", "ModifyEitrRegen", "AddElementalResistancePercentage" }) }; private static readonly Vector2i AutoSlot = new Vector2i(-1, -1); private static readonly List Spawned = new List(); 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 list = new List(); 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(prefab, val5, val4); Spawned.Add(val6); Container component = val6.GetComponent(); 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 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() : 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 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 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 list = new List(); (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() : 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 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(); 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 effectTypes, out string rarityName, out List skipped) { rarityName = string.Empty; skipped = new List(); 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 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 GetAllowedEffectTypes(ItemData item, object magic) { HashSet hashSet = new HashSet(); 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.1")] [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 { [CompilerGenerated] private sealed class d__20 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; case 1: <>1__state = -1; StorageTerminalUI.Refresh(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } 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.1"; private readonly Harmony _harmony = new Harmony("com.nicolai.odinstorage"); internal static ManualLogSource Log; internal static Plugin Instance; internal static ConfigEntry Hotkey; internal static ConfigEntry Radius; internal static ConfigEntry VerboseLogging; internal static ConfigEntry DevTools; internal static ConfigEntry SpawnKey; internal static ConfigEntry ClearKey; internal static ConfigEntry MarkerEnabled; internal static ConfigEntry 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("General", "Hotkey", new KeyboardShortcut((KeyCode)111, Array.Empty()), "Key that triggers the chest scan."); Radius = ((BaseUnityPlugin)this).Config.Bind("General", "Radius", 20f, "Range in meters."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind("General", "VerboseLogging", false, "If enabled, logs every Container.Awake (very verbose)."); DevTools = ((BaseUnityPlugin)this).Config.Bind("Dev", "DevTools", false, "Enables the developer keys (spawn/clear test chests)."); SpawnKey = ((BaseUnityPlugin)this).Config.Bind("Dev", "SpawnKey", new KeyboardShortcut((KeyCode)112, Array.Empty()), "Spawn and fill test chests (only when DevTools is enabled)."); ClearKey = ((BaseUnityPlugin)this).Config.Bind("Dev", "ClearKey", new KeyboardShortcut((KeyCode)108, Array.Empty()), "Remove spawned test chests (only when DevTools is enabled)."); MarkerEnabled = ((BaseUnityPlugin)this).Config.Bind("Marker", "MarkerEnabled", true, "\"Find item\": marks chests in the world (local visual aid)."); MarkerDuration = ((BaseUnityPlugin)this).Config.Bind("Marker", "MarkerDuration", 30f, "How long the find marker stays visible after closing the terminal (seconds)."); Log.LogInfo((object)"OdinStorage 0.9.1 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()); } [IteratorStateMachine(typeof(d__20))] private static IEnumerator RefreshSoonCo() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__20(0); } } 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 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 { [CompilerGenerated] private sealed class <>c__DisplayClass10_0 { public string token; public Func <>9__0; public Func <>9__1; internal bool b__0(Container c) { if (IsValid(c)) { return CountInChest(c, token) > 0; } return false; } internal int b__1(Container c) { return CountInChest(c, token); } } [CompilerGenerated] private sealed class <>c__DisplayClass10_1 { public Container source; public ItemData item; internal bool b__2(Container h) { if ((Object)(object)h != (Object)(object)source) { return CapacityFor(h, item) > 0; } return false; } internal bool b__3(Container c) { if ((Object)(object)c != (Object)(object)source && IsValid(c)) { return CapacityFor(c, item) > 0; } return false; } } [CompilerGenerated] private sealed class <>c__DisplayClass11_0 { public string token; internal bool b__0(ItemData i) { if (i?.m_shared != null) { return i.m_shared.m_name == token; } return false; } } [CompilerGenerated] private sealed class <>c__DisplayClass12_0 { public ItemData item; internal bool b__0(Container c) { if (IsValid(c)) { return CapacityFor(c, item) > 0; } return false; } } [CompilerGenerated] private sealed class d__12 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Inventory transit; public List chests; private List.Enumerator <>7__wrap1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__12(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { //IL_00a6: 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) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = transit.GetAllItems().ToList().GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { <>c__DisplayClass12_0 CS$<>8__locals0 = new <>c__DisplayClass12_0 { item = <>7__wrap1.Current }; if (CS$<>8__locals0.item?.m_shared == null) { continue; } Container val = ((IEnumerable)chests).FirstOrDefault((Func)((Container c) => IsValid(c) && CapacityFor(c, CS$<>8__locals0.item) > 0)); if ((Object)(object)val != (Object)null) { try { ContainerHandler.AddItemToChest(val, CS$<>8__locals0.item, transit, AutoSlot, ZDOID.None, CS$<>8__locals0.item.m_stack); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Consolidate: flush to chest failed (" + ex.Message + ").")); } <>2__current = null; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = default(List.Enumerator); Inventory val2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null); foreach (ItemData item in transit.GetAllItems().ToList()) { if (item?.m_shared != null) { Plugin.Log.LogWarning((object)$"Consolidate: {item.m_stack}x {item.m_shared.m_name} found no chest space."); if (val2 != null) { val2.AddItem(item); } } } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__11 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string token; public Container source; public Container sink; public Inventory transit; public ItemData item; public int amt; private <>c__DisplayClass11_0 <>8__1; private int 5__2; private int 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__11(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) ItemData val; switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass11_0(); <>8__1.token = token; if (!IsValid(source) || !IsValid(sink)) { return false; } 5__2 = 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 + ").")); return false; } 5__3 = 0; goto IL_00ef; case 1: <>1__state = -1; goto IL_00ef; case 2: { <>1__state = -1; return false; } IL_00ef: if (TotalStacks(transit) <= 5__2 && 5__3 < 60) { 5__3++; <>2__current = null; <>1__state = 1; return true; } val = ((IEnumerable)transit.GetAllItems()).FirstOrDefault((Func)((ItemData i) => i?.m_shared != null && i.m_shared.m_name == <>8__1.token)); if (val == null) { return false; } 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 + ").")); } <>2__current = null; <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__10 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Vector3 center; public float radius; private <>c__DisplayClass10_0 <>8__1; private List 5__2; private Dictionary 5__3; private Inventory 5__4; private int 5__5; private List.Enumerator <>7__wrap5; private int 5__7; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <>8__1 = null; 5__2 = null; 5__3 = null; 5__4 = null; <>7__wrap5 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (_busy) { return false; } _busy = true; 5__2 = StorageScanner.NearbyChests(center, radius).ToList(); if (5__2.Count < 2) { Plugin.Log.LogInfo((object)"Consolidate: fewer than two chests within range — nothing to do."); _busy = false; StorageTerminalUI.Refresh(); return false; } 5__3 = CountByToken(5__2); LogSlotUsage(5__2); 5__4 = new Inventory("odin_cleanup_transit", (Sprite)null, 8, 6); 5__5 = 0; <>7__wrap5 = 5__3.Keys.ToList().GetEnumerator(); <>1__state = -3; goto IL_0320; case 1: <>1__state = -3; if (_moved) { 5__5++; if (5__5 % 4 == 0) { <>2__current = null; <>1__state = 2; return true; } goto IL_02ee; } goto IL_0319; case 2: <>1__state = -3; goto IL_02ee; case 3: { <>1__state = -1; Dictionary after = CountByToken(5__2); bool flag = Verify(5__3, after, 5__4, 5__5); _busy = false; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, flag ? $"Storage consolidated ({5__5} moves)" : "Consolidate: WARNING — item count mismatch!", 0, (Sprite)null); } StorageTerminalUI.Refresh(); return false; } IL_02ee: if (5__5 < 5000 && 5__7++ < 1000) { <>c__DisplayClass10_1 CS$<>8__locals0 = new <>c__DisplayClass10_1(); List list = (from c in 5__2 where IsValid(c) && CountInChest(c, <>8__1.token) > 0 orderby CountInChest(c, <>8__1.token) descending select c).ToList(); if (list.Count > 1) { CS$<>8__locals0.source = list[list.Count - 1]; CS$<>8__locals0.item = FirstItemOfToken(CS$<>8__locals0.source, <>8__1.token); if (CS$<>8__locals0.item != null) { Container val = ((IEnumerable)list).FirstOrDefault((Func)((Container h) => (Object)(object)h != (Object)(object)CS$<>8__locals0.source && CapacityFor(h, CS$<>8__locals0.item) > 0)); if ((Object)(object)val == (Object)null) { val = ((IEnumerable)5__2).FirstOrDefault((Func)((Container c) => (Object)(object)c != (Object)(object)CS$<>8__locals0.source && IsValid(c) && CapacityFor(c, CS$<>8__locals0.item) > 0)); } if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)CS$<>8__locals0.source)) { int num = Mathf.Min(CS$<>8__locals0.item.m_stack, CapacityFor(val, CS$<>8__locals0.item)); if (num > 0) { _moved = false; <>2__current = MoveViaTransit(CS$<>8__locals0.source, val, <>8__1.token, CS$<>8__locals0.item, num, 5__4); <>1__state = 1; return true; } } } } } goto IL_0319; IL_0320: if (<>7__wrap5.MoveNext()) { <>8__1 = new <>c__DisplayClass10_0(); <>8__1.token = <>7__wrap5.Current; 5__7 = 0; goto IL_02ee; } <>m__Finally1(); <>7__wrap5 = default(List.Enumerator); <>2__current = FlushTransit(5__4, 5__2); <>1__state = 3; return true; IL_0319: <>8__1 = null; goto IL_0320; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap5).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } 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 dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); foreach (Container item in StorageScanner.NearbyChests(center, radius)) { Inventory inventory = item.GetInventory(); List list = ((inventory != null) ? inventory.GetAllItems() : null); if (list == null) { continue; } Dictionary dictionary3 = new Dictionary(); 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 item3 in dictionary3) { dictionary2.TryGetValue(item3.Key, out var value3); if (item3.Value > value3) { dictionary2[item3.Key] = item3.Value; } } } int num = 0; foreach (KeyValuePair item4 in dictionary) { dictionary2.TryGetValue(item4.Key, out var value4); num += item4.Value - value4; } return num; } [IteratorStateMachine(typeof(d__10))] 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) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__10(0) { center = center, radius = radius }; } [IteratorStateMachine(typeof(d__11))] private static IEnumerator MoveViaTransit(Container source, Container sink, string token, ItemData item, int amt, Inventory transit) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__11(0) { source = source, sink = sink, token = token, item = item, amt = amt, transit = transit }; } [IteratorStateMachine(typeof(d__12))] private static IEnumerator FlushTransit(Inventory transit, List chests) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__12(0) { transit = transit, chests = chests }; } private static bool Verify(Dictionary before, Dictionary 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 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 CountByToken(List chests) { Dictionary dictionary = new Dictionary(); foreach (Container chest in chests) { if (!IsValid(chest)) { continue; } Inventory inventory = chest.GetInventory(); List 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 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) { string token2 = token; Inventory inventory = chest.GetInventory(); return ((inventory != null) ? inventory.GetAllItems() : null)?.FirstOrDefault((Func)((ItemData it) => it?.m_shared != null && it.m_shared.m_name == token2 && 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 Tokens = new HashSet(); public int EmptySlots; public Dictionary PartialFree = new Dictionary(); 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 list = new List(); 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 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(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 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 _active = new List(); 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 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().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()?.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(); 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(); 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(); } } } 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(); } 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(); 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 Entries = new List(); public int ChestCount; public int TotalItems; public int TotalSlots; public int UsedSlots; public int AlmostFullChests; } public static class StorageScanner { [CompilerGenerated] private sealed class d__0 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Container <>2__current; private int <>l__initialThreadId; private float radius; public float <>3__radius; private Vector3 center; public Vector3 <>3__center; private float 5__2; private Container[] <>7__wrap2; private int <>7__wrap3; Container IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { //IL_009a: 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_00aa: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_00d1; } <>1__state = -1; 5__2 = radius * radius; Container[] array = Object.FindObjectsByType((FindObjectsSortMode)0); <>7__wrap2 = array; <>7__wrap3 = 0; goto IL_00df; IL_00d1: <>7__wrap3++; goto IL_00df; IL_00df: if (<>7__wrap3 < <>7__wrap2.Length) { Container val = <>7__wrap2[<>7__wrap3]; 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 > 5__2)) { <>2__current = val; <>1__state = 1; return true; } } goto IL_00d1; } <>7__wrap2 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) d__0 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__0(0); } d__.center = <>3__center; d__.radius = <>3__radius; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0))] public static IEnumerable 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) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(-2) { <>3__center = center, <>3__radius = radius }; } public static StorageSnapshot AggregateNearby(Vector3 center, float radius) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); 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 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 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("[$KEY_Use] 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 <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 _rows = new List(); private static readonly List _order = new List(); private static readonly Dictionary _entries = new Dictionary(); 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(); 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