Decompiled source of KuickStash v1.0.0

KuickStash.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
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(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("KuickStash")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("KuickStash")]
[assembly: AssemblyTitle("KuickStash")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace KuickStash
{
	[BepInPlugin("de.example.valheim.kuickstash", "KuickStash", "1.0.0")]
	public class KuickStashPlugin : BaseUnityPlugin
	{
		private ConfigEntry<KeyCode> _sortKey;

		private ConfigEntry<float> _range;

		private ConfigEntry<bool> _onlyMatching;

		private ConfigEntry<bool> _skipHotbar;

		private ConfigEntry<bool> _storeRawFood;

		private static readonly FieldInfo NviewField = AccessTools.Field(typeof(Container), "m_nview");

		private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);

		private static readonly MethodInfo ChangedMethod = (from m in typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
			where m.Name == "Changed"
			orderby m.GetParameters().Length
			select m).FirstOrDefault();

		private static readonly HashSet<ItemType> KeptTypes = new HashSet<ItemType>
		{
			(ItemType)2,
			(ItemType)9,
			(ItemType)23,
			(ItemType)19,
			(ItemType)15,
			(ItemType)3,
			(ItemType)14,
			(ItemType)22,
			(ItemType)20,
			(ItemType)4,
			(ItemType)5,
			(ItemType)6,
			(ItemType)7,
			(ItemType)11,
			(ItemType)12,
			(ItemType)17,
			(ItemType)18,
			(ItemType)24
		};

		private static HashSet<string> _cookedFoods;

		private static bool _errorLogged;

		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Inventory.Changed: " + (ChangedMethod?.ToString() ?? "NOT FOUND")));
			_sortKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "SortKey", (KeyCode)107, "Taste zum Einsortieren");
			_range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 20f, "Radius in Metern, in dem Kisten gesucht werden");
			_onlyMatching = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OnlyMatchingChests", true, "true = nur in Kisten, die das Item schon enthalten; false = in jede Kiste mit freiem Platz");
			_storeRawFood = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "StoreRawFood", true, "true = uncooked food (berries, mushrooms, honey, ...) is stashed, only cooked food and potions are kept; false = all food is kept");
			_skipHotbar = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SkipHotbar", true, "true = Items in der obersten Inventarreihe (Hotbar) nie verschieben");
		}

		private void Update()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && Input.GetKeyDown(_sortKey.Value) && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible() && !((Character)localPlayer).InCutscene())
			{
				int num = SortInventory(localPlayer);
				((Character)localPlayer).Message((MessageType)1, (num > 0) ? $"{num} Gegenstände einsortiert" : "Nichts einzusortieren", 0, (Sprite)null, false);
			}
		}

		private int SortInventory(Player player)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<Container> list = FindContainers(((Component)player).transform.position);
			int num = 0;
			foreach (ItemData item in inventory.GetAllItems().ToList())
			{
				if (item.m_equipped || item.m_shared.m_questItem || IsKept(item) || (_skipHotbar.Value && item.m_gridPos.y == 0))
				{
					continue;
				}
				int num2 = item.m_stack;
				foreach (Container item2 in list)
				{
					if (num2 <= 0)
					{
						break;
					}
					try
					{
						int num3 = MoveToContainer(inventory, item, item2, num2);
						num += num3;
						num2 -= num3;
					}
					catch (Exception ex)
					{
						if (!_errorLogged)
						{
							_errorLogged = true;
							((BaseUnityPlugin)this).Logger.LogError((object)("Error while moving items: " + ex));
						}
					}
				}
			}
			return num;
		}

		private bool IsKept(ItemData item)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			SharedData shared = item.m_shared;
			if ((int)shared.m_itemType != 2 || !_storeRawFood.Value)
			{
				return KeptTypes.Contains(shared.m_itemType);
			}
			bool flag = shared.m_food > 0f || shared.m_foodStamina > 0f || shared.m_foodEitr > 0f;
			HashSet<string> cookedFoods = GetCookedFoods();
			return !flag || cookedFoods == null || cookedFoods.Contains(shared.m_name);
		}

		private HashSet<string> GetCookedFoods()
		{
			if (_cookedFoods != null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return _cookedFoods;
			}
			try
			{
				IEnumerable<string> first = from conv in (from p in ZNetScene.instance.m_prefabs
						where (Object)(object)p != (Object)null
						select p.GetComponent<CookingStation>() into c
						where (Object)(object)c != (Object)null
						select c).SelectMany((CookingStation c) => c.m_conversion)
					where (Object)(object)conv.m_to != (Object)null
					select conv.m_to.m_itemData.m_shared.m_name;
				IEnumerable<string> second = from r in ObjectDB.instance.m_recipes
					where (Object)(object)r != (Object)null && (Object)(object)r.m_item != (Object)null && (Object)(object)r.m_craftingStation != (Object)null && r.m_craftingStation.m_name == "$piece_cauldron"
					select r.m_item.m_itemData.m_shared.m_name;
				_cookedFoods = new HashSet<string>(first.Concat(second));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not build the list of cooked foods: " + ex));
			}
			return _cookedFoods;
		}

		private int MoveToContainer(Inventory playerInv, ItemData item, Container container, int remaining)
		{
			Inventory inventory = container.GetInventory();
			object? value = NviewField.GetValue(container);
			ZNetView nview = (ZNetView)((value is ZNetView) ? value : null);
			if (inventory == null || (Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return 0;
			}
			if (_onlyMatching.Value && !inventory.HaveItem(item.m_shared.m_name, true))
			{
				return 0;
			}
			int moved = 0;
			bool claimed = false;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (remaining <= 0)
				{
					break;
				}
				int num = allItem.m_shared.m_maxStackSize - allItem.m_stack;
				if (!(allItem.m_shared.m_name != item.m_shared.m_name) && allItem.m_quality == item.m_quality && num > 0)
				{
					int num2 = Mathf.Min(remaining, num);
					Claim();
					allItem.m_stack += num2;
					TakeFromPlayer(num2);
				}
			}
			if (remaining > 0)
			{
				ItemData val = item.Clone();
				val.m_stack = remaining;
				if (inventory.CanAddItem(val, -1))
				{
					Claim();
					if (inventory.AddItem(val))
					{
						TakeFromPlayer(remaining);
					}
				}
			}
			if (claimed)
			{
				NotifyChanged(inventory);
			}
			return moved;
			void Claim()
			{
				if (!claimed)
				{
					nview.ClaimOwnership();
					claimed = true;
				}
			}
			void TakeFromPlayer(int n)
			{
				if (n >= item.m_stack)
				{
					playerInv.RemoveItem(item);
				}
				else
				{
					playerInv.RemoveItem(item, n);
				}
				remaining -= n;
				moved += n;
			}
		}

		private static void NotifyChanged(Inventory inv)
		{
			object[] parameters = (from p in ChangedMethod?.GetParameters()
				select p.HasDefaultValue ? p.DefaultValue : (p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null)).ToArray();
			ChangedMethod?.Invoke(inv, parameters);
		}

		private static bool HasAccess(Container c, long playerId)
		{
			return (bool)(CheckAccessMethod?.Invoke(c, new object[1] { playerId }) ?? ((object)false));
		}

		private List<Container> FindContainers(Vector3 center)
		{
			//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_001f: Unknown result type (might be due to invalid IL or missing references)
			long playerId = Player.m_localPlayer.GetPlayerID();
			return (from c in (from col in Physics.OverlapSphere(center, _range.Value)
					select ((Component)col).GetComponentInParent<Container>() into c
					where (Object)(object)c != (Object)null
					select c).Distinct()
				where !c.IsInUse() && HasAccess(c, playerId) && PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false)
				select c).OrderBy(delegate(Container c)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = ((Component)c).transform.position - center;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).ToList();
		}
	}
}