Decompiled source of HammerCraftingMaterials v1.1.0

plugins/HammerCraftingMaterials.dll

Decompiled 2 weeks ago
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 Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;

[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("HammerCraftingMaterials")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Right-click any piece in the hammer build menu to pull its required materials from nearby chests directly into your inventory.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c65c3abdffb53e6aca80026cce920f159a7f833d")]
[assembly: AssemblyProduct("HammerCraftingMaterials")]
[assembly: AssemblyTitle("HammerCraftingMaterials")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 HammerCraftingMaterials
{
	[BepInPlugin("com.hammercraftingmaterials.valheim", "HammerCraftingMaterials", "1.1.0")]
	[BepInProcess("valheim.exe")]
	[BepInProcess("Valheim.app")]
	public class HammerCraftingMaterialsPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.hammercraftingmaterials.valheim";

		public const string PluginName = "HammerCraftingMaterials";

		public const string PluginVersion = "1.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> ChestSearchRadius;

		private readonly Harmony _harmony = new Harmony("com.hammercraftingmaterials.valheim");

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			ChestSearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChestSearchRadius", 10f, "How far (meters) to search for nearby chests when pulling materials.");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)string.Format("{0} v{1} loaded! Search radius: {2}m", "HammerCraftingMaterials", "1.1.0", ChestSearchRadius.Value));
		}

		private void Update()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00c5: 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)
			if (!Input.GetMouseButtonDown(1))
			{
				return;
			}
			Hud instance = Hud.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			GameObject value = Traverse.Create((object)instance).Field("m_pieceSelectionWindow").GetValue<GameObject>();
			if ((Object)(object)value == (Object)null || !value.activeSelf)
			{
				return;
			}
			bool forcePull = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
			PointerEventData val = new PointerEventData(EventSystem.current)
			{
				position = Vector2.op_Implicit(Input.mousePosition)
			};
			List<RaycastResult> list = new List<RaycastResult>();
			EventSystem current = EventSystem.current;
			if (current != null)
			{
				current.RaycastAll(val, list);
			}
			foreach (RaycastResult item in list)
			{
				RaycastResult current2 = item;
				PieceIconReference componentInParent = ((RaycastResult)(ref current2)).gameObject.GetComponentInParent<PieceIconReference>();
				if ((Object)(object)componentInParent?.Piece == (Object)null)
				{
					continue;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					continue;
				}
				string text = PullLogic.PullMaterialsForPiece(componentInParent.Piece, localPlayer, forcePull);
				Log.LogInfo((object)("[HCM] " + text));
				MessageHud instance2 = MessageHud.instance;
				if (instance2 != null)
				{
					instance2.ShowMessage((MessageType)1, text, 0, (Sprite)null, false);
				}
				break;
			}
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
		}
	}
	public class PieceIconReference : MonoBehaviour
	{
		public Piece Piece = null;
	}
	public static class PullLogic
	{
		public static List<Container> GetNearbyContainers(Vector3 origin, float radius)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = new List<Container>();
			Collider[] array = Physics.OverlapSphere(origin, radius);
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				Container componentInParent = ((Component)val).GetComponentInParent<Container>();
				if (!((Object)(object)componentInParent == (Object)null) && !list.Contains(componentInParent) && !((Object)(object)((Component)componentInParent).GetComponent<Player>() != (Object)null) && Traverse.Create((object)componentInParent).Method("CheckAccess", new object[1] { Game.instance.GetPlayerProfile().GetPlayerID() }).GetValue<bool>())
				{
					list.Add(componentInParent);
				}
			}
			return list;
		}

		public static string PullMaterialsForPiece(Piece piece, Player player, bool forcePull = false)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)piece == (Object)null)
			{
				return "No piece selected.";
			}
			if (piece.m_resources == null || piece.m_resources.Length == 0)
			{
				return Localization.instance.Localize(piece.m_name) + " has no material requirements.";
			}
			List<Container> nearbyContainers = GetNearbyContainers(((Component)player).transform.position, HammerCraftingMaterialsPlugin.ChestSearchRadius.Value);
			if (nearbyContainers.Count == 0)
			{
				return "No accessible chests found nearby.";
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (!((Object)(object)val.m_resItem == (Object)null))
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					int num = ((Humanoid)player).GetInventory().CountItems(name, -1, true);
					int num2 = val.m_amount - num;
					if (num2 > 0 || forcePull)
					{
						dictionary[name] = (forcePull ? val.m_amount : num2);
					}
				}
			}
			if (dictionary.Count == 0)
			{
				return "You already have all required materials!";
			}
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
			Inventory inventory = ((Humanoid)player).GetInventory();
			foreach (Container item in nearbyContainers)
			{
				if (dictionary.Count == 0)
				{
					break;
				}
				Inventory inventory2 = item.GetInventory();
				bool flag = false;
				foreach (KeyValuePair<string, int> item2 in dictionary.ToList())
				{
					string itemName = item2.Key;
					int value = item2.Value;
					int num3 = inventory2.CountItems(itemName, -1, true);
					if (num3 <= 0)
					{
						continue;
					}
					int num4 = Mathf.Min(num3, value);
					ItemData val2 = ((IEnumerable<ItemData>)inventory2.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i.m_shared.m_name == itemName));
					if (val2 == null || (!inventory.HaveEmptySlot() && inventory.FindFreeStackSpace(itemName, 1f) <= 0))
					{
						continue;
					}
					inventory2.RemoveItem(itemName, num4, -1, true);
					flag = true;
					string text = (((Object)(object)val2.m_dropPrefab != (Object)null) ? ((Object)val2.m_dropPrefab).name : val2.m_shared.m_name);
					if (inventory.AddItem(text, num4, val2.m_quality, val2.m_variant, player.GetPlayerID(), player.GetPlayerName(), false) != null)
					{
						dictionary2.TryGetValue(itemName, out var value2);
						dictionary2[itemName] = value2 + num4;
						dictionary[itemName] -= num4;
						if (dictionary[itemName] <= 0)
						{
							dictionary.Remove(itemName);
						}
					}
					else
					{
						inventory2.AddItem(text, num4, val2.m_quality, val2.m_variant, 0L, "", false);
					}
				}
				if (flag)
				{
					Traverse.Create((object)item).Method("Save", Array.Empty<object>()).GetValue();
				}
			}
			if (dictionary2.Count == 0)
			{
				return "None of the required materials were found in nearby chests.";
			}
			string text2 = string.Join(", ", dictionary2.Select((KeyValuePair<string, int> kvp) => $"{kvp.Value}x {Localization.instance.Localize(kvp.Key)}"));
			if (dictionary.Count == 0)
			{
				return forcePull ? ("Force pulled: " + text2) : ("Pulled: " + text2);
			}
			string text3 = string.Join(", ", dictionary.Select((KeyValuePair<string, int> kvp) => $"{kvp.Value}x {Localization.instance.Localize(kvp.Key)}"));
			return "Pulled: " + text2 + " | Still missing: " + text3;
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdatePieceList")]
	public static class Hud_UpdatePieceList_Patch
	{
		private static readonly FieldInfo? _pieceIconsField = typeof(Hud).GetField("m_pieceIcons", BindingFlags.Instance | BindingFlags.NonPublic);

		private static FieldInfo? _goField;

		[HarmonyPostfix]
		private static void Postfix(Hud __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			PieceTable value = Traverse.Create((object)localPlayer).Field("m_buildPieces").GetValue<PieceTable>();
			if ((Object)(object)value == (Object)null)
			{
				return;
			}
			List<Piece> piecesInSelectedCategory = value.GetPiecesInSelectedCategory();
			if (piecesInSelectedCategory == null || piecesInSelectedCategory.Count == 0)
			{
				return;
			}
			if (!(_pieceIconsField?.GetValue(__instance) is IList list))
			{
				HammerCraftingMaterialsPlugin.Log.LogWarning((object)"[HCM] m_pieceIcons field not found on Hud");
				return;
			}
			for (int i = 0; i < list.Count && i < piecesInSelectedCategory.Count; i++)
			{
				object obj = list[i];
				if (obj == null)
				{
					continue;
				}
				if (_goField == null)
				{
					_goField = obj.GetType().GetField("m_go", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				object? obj2 = _goField?.GetValue(obj);
				GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if (val != null)
				{
					Piece val2 = piecesInSelectedCategory[i];
					if (!((Object)(object)val2 == (Object)null))
					{
						PieceIconReference pieceIconReference = val.GetComponent<PieceIconReference>() ?? val.AddComponent<PieceIconReference>();
						pieceIconReference.Piece = val2;
					}
				}
			}
		}
	}
}