using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SmartStorage.Core; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SmartStorage")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Smart Storage for Valheim - automatic item sorting into chests")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("SmartStorage")] [assembly: AssemblyTitle("SmartStorage")] [assembly: AssemblyVersion("0.1.0.0")] [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 SmartStorage { [BepInPlugin("com.macheon.smartstorage", "SmartStorage", "0.2.0")] public class SmartStoragePlugin : BaseUnityPlugin { public const string PluginGuid = "com.macheon.smartstorage"; public const string PluginName = "SmartStorage"; public const string PluginVersion = "0.2.0"; private Harmony? _harmony; internal static ManualLogSource? LogSource; internal static ConfigEntry? ModEnabled; internal static ConfigEntry? ScanRadius; internal static ConfigEntry? ShowNotifications; internal static ConfigEntry? RequireOwnedContainers; internal static ConfigEntry? VerboseLogging; private void Awake() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown LogSource = ((BaseUnityPlugin)this).Logger; ModEnabled = ((BaseUnityPlugin)this).Config.Bind("1. General", "Enabled", true, "Enable or disable the Smart Storage mod entirely."); ScanRadius = ((BaseUnityPlugin)this).Config.Bind("2. Detection", "ScanRadius", 10f, new ConfigDescription("Search radius (in meters) around the player to find matching containers.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); ShowNotifications = ((BaseUnityPlugin)this).Config.Bind("3. UI", "ShowNotifications", true, "Show a HUD message when an item is auto-sorted."); RequireOwnedContainers = ((BaseUnityPlugin)this).Config.Bind("4. Multiplayer", "RequireOwnedContainers", true, "Only target containers you own (recommended in multiplayer to avoid issues)."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind("5. Debug", "VerboseLogging", false, "Log every Smart Storage transfer to the BepInEx console."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"======================================"); ((BaseUnityPlugin)this).Logger.LogInfo((object)" SmartStorage v0.2.0 loaded!"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$" Scan radius: {ScanRadius.Value}m | Notifications: {ShowNotifications.Value}"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"======================================"); _harmony = new Harmony("com.macheon.smartstorage"); _harmony.PatchAll(); } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace SmartStorage.Patches { [HarmonyPatch] public static class InventoryPatches { private static string GetItemName(ItemData item) { return (Localization.instance != null) ? Localization.instance.Localize(item.m_shared.m_name) : item.m_shared.m_name; } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] [HarmonyPrefix] public static bool OnSelectedItem_Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) ConfigEntry? modEnabled = SmartStoragePlugin.ModEnabled; if (modEnabled != null && !modEnabled.Value) { return true; } if (item == null) { return true; } if ((int)mod != 2) { return true; } if (!__instance.IsContainerOpen()) { return true; } if (item.m_shared.m_questItem) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting()) { return true; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (grid.GetInventory() != inventory) { return true; } Container currentContainer = GetCurrentContainer(__instance); float radius = SmartStoragePlugin.ScanRadius?.Value ?? 10f; bool requireOwned = SmartStoragePlugin.RequireOwnedContainers?.Value ?? true; Container val = ContainerScanner.FindBestContainerForItem(item, ((Component)localPlayer).transform.position, currentContainer, radius, requireOwned); if ((Object)(object)val == (Object)null) { return true; } string itemName = GetItemName(item); int stack = item.m_stack; val.GetInventory().MoveItemToThis(inventory, item); ConfigEntry? showNotifications = SmartStoragePlugin.ShowNotifications; if (showNotifications != null && showNotifications.Value) { string text = $"\ud83d\udce6 {itemName} x{stack} → coffre intelligent"; MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false); } } ConfigEntry? verboseLogging = SmartStoragePlugin.VerboseLogging; if (verboseLogging != null && verboseLogging.Value) { ManualLogSource? logSource = SmartStoragePlugin.LogSource; if (logSource != null) { logSource.LogInfo((object)$"[SMART STORE] {itemName} x{stack} → {((Object)val).name} at {((Component)val).transform.position}"); } } return false; } private static Container? GetCurrentContainer(InventoryGui gui) { object? obj = typeof(InventoryGui).GetField("m_currentContainer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(gui); return (Container?)((obj is Container) ? obj : null); } } } namespace SmartStorage.Core { public static class ContainerScanner { public const float DefaultScanRadius = 10f; private const float CacheLifetimeSeconds = 2f; private static Container[]? _cachedContainers = null; private static float _cacheTimestamp = 0f; private static Vector3 _cachePosition = Vector3.zero; private const float CachePositionThreshold = 5f; public static Container? FindBestContainerForItem(ItemData item, Vector3 playerPosition, Container? excludeContainer = null, float radius = 10f, bool requireOwned = true) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (item == null) { return null; } string name = item.m_shared.m_name; float num = radius * radius; Container[] cachedOrFreshContainers = GetCachedOrFreshContainers(playerPosition); Container[] array = cachedOrFreshContainers; foreach (Container val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)excludeContainer) { continue; } Vector3 val2 = ((Component)val).transform.position - playerPosition; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude > num) && (!requireOwned || val.IsOwner())) { Inventory inventory = val.GetInventory(); if (inventory != null && inventory.HaveItem(name, false) && inventory.CanAddItem(item, item.m_stack)) { return val; } } } return null; } private static Container[] GetCachedOrFreshContainers(Vector3 playerPosition) { //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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; Vector3 val = playerPosition - _cachePosition; float magnitude = ((Vector3)(ref val)).magnitude; if (_cachedContainers == null || !(time - _cacheTimestamp < 2f) || !(magnitude < 5f)) { _cachedContainers = Object.FindObjectsByType((FindObjectsSortMode)0); _cacheTimestamp = time; _cachePosition = playerPosition; } return _cachedContainers; } } }