Decompiled source of SmartStorage v0.2.0

plugins/SmartStorage.dll

Decompiled 2 months ago
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<bool>? ModEnabled;

		internal static ConfigEntry<float>? ScanRadius;

		internal static ConfigEntry<bool>? ShowNotifications;

		internal static ConfigEntry<bool>? RequireOwnedContainers;

		internal static ConfigEntry<bool>? 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<bool>("1. General", "Enabled", true, "Enable or disable the Smart Storage mod entirely.");
			ScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("2. Detection", "ScanRadius", 10f, new ConfigDescription("Search radius (in meters) around the player to find matching containers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			ShowNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("3. UI", "ShowNotifications", true, "Show a HUD message when an item is auto-sorted.");
			RequireOwnedContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Multiplayer", "RequireOwnedContainers", true, "Only target containers you own (recommended in multiplayer to avoid issues).");
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("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<bool>? 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<bool>? 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<bool>? 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<Container>((FindObjectsSortMode)0);
				_cacheTimestamp = time;
				_cachePosition = playerPosition;
			}
			return _cachedContainers;
		}
	}
}