Decompiled source of HammerCraftingMaterials v1.1.3

plugins/HammerCraftingMaterials.dll

Decompiled a week 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.InteropServices;
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.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("HammerCraftingMaterials")]
[assembly: AssemblyDescription("Right-click any piece in the hammer build menu to pull its required materials from nearby chests directly into your inventory. Configurable search radius.")]
[assembly: AssemblyProduct("HammerCraftingMaterials")]
[assembly: AssemblyCompany("drummercraig")]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.1.3")]
[assembly: AssemblyVersion("1.1.3.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
}
namespace HammerCraftingMaterials
{
	[BepInPlugin("drummercraig.hammercraftingmaterials", "HammerCraftingMaterials", "1.1.3")]
	public class HammerCraftingMaterialsPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "drummercraig.hammercraftingmaterials";

		public const string PluginName = "HammerCraftingMaterials";

		public const string PluginVersion = "1.1.3";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> ChestSearchRadius;

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

		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.");
			Log.LogInfo((object)string.Format("{0} v{1} loaded! Search radius: {2}m", "HammerCraftingMaterials", "1.1.3", ChestSearchRadius.Value));
			ResilientPatcher.ApplyAll(_harmony, Assembly.GetExecutingAssembly(), Log);
		}

		private void Update()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_00a9: 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)
			try
			{
				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))
					{
						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;
					}
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[HCM] Update failed: {arg}");
			}
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
		}
	}
	public class PieceIconReference : MonoBehaviour
	{
		public Piece Piece;
	}
	public static class PullLogic
	{
		public static List<Container> GetNearbyContainers(Vector3 origin, float radius)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = new List<Container>();
			Collider[] array = Physics.OverlapSphere(origin, radius);
			for (int i = 0; i < array.Length; i++)
			{
				Container componentInParent = ((Component)array[i]).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_0041: 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 val3) => val3.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)
			{
				if (!forcePull)
				{
					return "Pulled: " + text2;
				}
				return "Force 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", new Type[]
	{
		typeof(Player),
		typeof(Vector2Int),
		typeof(PieceCategory),
		typeof(bool)
	})]
	public static class Hud_UpdatePieceList_Patch
	{
		private static readonly FieldInfo? _pieceIconsField = AccessTools.Field(typeof(Hud), "m_pieceIcons");

		private static FieldInfo? _goField;

		[HarmonyPostfix]
		private static void Postfix(Hud __instance)
		{
			try
			{
				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 = AccessTools.Field(obj.GetType(), "m_go");
					}
					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))
						{
							(val.GetComponent<PieceIconReference>() ?? val.AddComponent<PieceIconReference>()).Piece = val2;
						}
					}
				}
			}
			catch (Exception arg)
			{
				HammerCraftingMaterialsPlugin.Log.LogError((object)$"[HCM] UpdatePieceList postfix failed: {arg}");
			}
		}
	}
	internal static class ResilientPatcher
	{
		internal static void ApplyAll(Harmony harmony, Assembly assembly, ManualLogSource log)
		{
			if (harmony == null || assembly == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			List<string> list = null;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(assembly);
			foreach (Type type in typesFromAssembly)
			{
				try
				{
					List<MethodInfo> list2 = harmony.CreateClassProcessor(type).Patch();
					if (list2 != null && list2.Count > 0)
					{
						num++;
						if (log != null)
						{
							log.LogDebug((object)$"[HCM] patched {type.Name} ({list2.Count} method(s)).");
						}
					}
				}
				catch (Exception ex)
				{
					num2++;
					(list ?? (list = new List<string>())).Add(type.Name);
					if (log != null)
					{
						log.LogWarning((object)("[HCM] SKIP patch class " + type.Name + ": " + ex.Message));
					}
				}
			}
			if (num2 == 0)
			{
				if (log != null)
				{
					log.LogInfo((object)$"[HCM] patches: {num} applied, 0 skipped.");
				}
			}
			else if (log != null)
			{
				log.LogWarning((object)(string.Format("[HCM] patches: {0} applied, {1} skipped ({2}). ", num, num2, string.Join(", ", list)) + "A skipped patch usually means a Valheim update changed a hooked method; that feature is disabled but the mod is still running."));
			}
		}
	}
}