Decompiled source of RustyHeathensCraftTracker v0.1.4

plugins/RustyHeathensCraftTracker/RustyHeathensCraftTracker.dll

Decompiled 5 days 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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RustyHeathensCraftTracker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: AssemblyInformationalVersion("0.1.4")]
[assembly: AssemblyProduct("RustyHeathensCraftTracker")]
[assembly: AssemblyTitle("RustyHeathensCraftTracker")]
[assembly: AssemblyVersion("0.1.4.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 RustyHeathens.CraftTracker
{
	[BepInPlugin("com.rustyheathens.crafttracker", "Rusty Heathens Craft Tracker", "0.1.4")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class Row
		{
			public string Name;

			public int Have;

			public int Need;
		}

		internal sealed class CraftState
		{
			public Recipe Recipe;

			public Player Player;

			public int Before;
		}

		public const string Id = "com.rustyheathens.crafttracker";

		internal static Plugin Instance;

		private Harmony harmony;

		private ConfigEntry<float> top;

		private ConfigEntry<float> right;

		private ConfigEntry<float> scale;

		private Recipe tracked;

		private Player owner;

		private readonly List<Row> rows = new List<Row>();

		private float nextRefresh;

		private string notice;

		private float noticeUntil;

		private GUIStyle title;

		private GUIStyle line;

		private GUIStyle hint;

		private static readonly FieldInfo Available = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");

		private static readonly FieldInfo CraftRecipe = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe");

		private static readonly FieldInfo UpgradeItem = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem");

		private static readonly FieldInfo UpgraderResource = AccessTools.Field(typeof(Requirement), "m_upgraderResource");

		private static readonly FieldInfo OnlyOne = AccessTools.Field(typeof(Recipe), "m_requireOnlyOneIngredient");

		private bool EitherIngredient
		{
			get
			{
				if (Object.op_Implicit((Object)(object)tracked) && OnlyOne != null)
				{
					return (bool)OnlyOne.GetValue(tracked);
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			//IL_0179: Expected O, but got Unknown
			Instance = this;
			top = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "TopMargin", 270f, "Pixels below the top edge at 1080p; positions the checklist below the minimap.");
			if (Mathf.Approximately(top.Value, 210f))
			{
				top.Value = 270f;
			}
			right = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "RightMargin", 24f, "Distance from the right edge at 1080p.");
			scale = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Scale", 1f, new ConfigDescription("Tracker size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.65f, 1.8f), Array.Empty<object>()));
			harmony = new Harmony("com.rustyheathens.crafttracker");
			MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "DoCrafting", new Type[1] { typeof(Player) }, (Type[])null);
			if (Available == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Recipe selection unavailable: this game version has an unsupported recipe-list API.");
			}
			if (methodInfo == null || CraftRecipe == null || UpgradeItem == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Craft tracking unavailable: this game version has an unsupported crafting API.");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "BeforeCraft", (Type[])null), new HarmonyMethod(typeof(Plugin), "AfterCraft", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Craft Tracker loaded. Middle-click a recipe in a crafting table to track it.");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)(object)owner)
			{
				owner = localPlayer;
				tracked = null;
				rows.Clear();
			}
			if (Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead())
			{
				if (InventoryGui.IsVisible() && Input.GetMouseButtonDown(2))
				{
					TrackHoveredRecipe();
				}
				if (Object.op_Implicit((Object)(object)tracked) && Time.unscaledTime >= nextRefresh)
				{
					nextRefresh = Time.unscaledTime + 0.2f;
					Refresh(localPlayer);
				}
			}
		}

		private static object Member(object obj, string name)
		{
			if (obj == null)
			{
				return null;
			}
			Type type = obj.GetType();
			object obj2 = AccessTools.Property(type, name)?.GetValue(obj, null);
			if (obj2 == null)
			{
				FieldInfo fieldInfo = AccessTools.Field(type, name);
				if ((object)fieldInfo == null)
				{
					return null;
				}
				obj2 = fieldInfo.GetValue(obj);
			}
			return obj2;
		}

		private static bool UnderPointer(RectTransform rect)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)rect) || !((Component)rect).gameObject.activeInHierarchy)
			{
				return false;
			}
			Canvas componentInParent = ((Component)rect).GetComponentInParent<Canvas>();
			Camera val = ((Object.op_Implicit((Object)(object)componentInParent) && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
			if (!RectTransformUtility.RectangleContainsScreenPoint(rect, Vector2.op_Implicit(Input.mousePosition), val))
			{
				return false;
			}
			Transform parent = ((Transform)rect).parent;
			while ((Object)(object)parent != (Object)null)
			{
				Component[] components = ((Component)parent).GetComponents<Component>();
				foreach (Component val2 in components)
				{
					if (Object.op_Implicit((Object)(object)val2) && (((object)val2).GetType().Name == "RectMask2D" || ((object)val2).GetType().Name == "Mask") && !RectTransformUtility.RectangleContainsScreenPoint((RectTransform)(object)((parent is RectTransform) ? parent : null), Vector2.op_Implicit(Input.mousePosition), val))
					{
						return false;
					}
				}
				parent = parent.parent;
			}
			return true;
		}

		private void TrackHoveredRecipe()
		{
			InventoryGui instance = InventoryGui.instance;
			if (!Object.op_Implicit((Object)(object)instance) || !(Available?.GetValue(instance) is IEnumerable enumerable))
			{
				return;
			}
			foreach (object item in enumerable)
			{
				object obj = Member(item, "InterfaceElement");
				GameObject val = (GameObject)((obj is GameObject) ? obj : null);
				if (!Object.op_Implicit((Object)(object)val) || !UnderPointer((RectTransform)/*isinst with value type is only supported in some contexts*/))
				{
					continue;
				}
				object obj2 = Member(item, "Recipe");
				Recipe val2 = (Recipe)((obj2 is Recipe) ? obj2 : null);
				object obj3 = Member(item, "ItemData");
				ItemData val3 = (ItemData)((obj3 is ItemData) ? obj3 : null);
				if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.m_item))
				{
					if (val3 != null)
					{
						notice = "Choose a recipe in the Craft tab to track materials.";
						noticeUntil = Time.unscaledTime + 4f;
					}
					else if ((Object)(object)tracked == (Object)(object)val2)
					{
						tracked = null;
						rows.Clear();
					}
					else
					{
						tracked = val2;
						Refresh(owner);
					}
				}
				break;
			}
		}

		private static string Local(string token)
		{
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}

		private static string Name(Recipe recipe)
		{
			return Local(recipe.m_item.m_itemData.m_shared.m_name);
		}

		private void Refresh(Player player)
		{
			rows.Clear();
			Requirement[] resources = tracked.m_resources;
			foreach (Requirement val in resources)
			{
				if (val == null || !Object.op_Implicit((Object)(object)val.m_resItem) || (UpgraderResource != null && (bool)UpgraderResource.GetValue(val)))
				{
					continue;
				}
				int amount = val.GetAmount(1);
				if (amount > 0)
				{
					string token = val.m_resItem.m_itemData.m_shared.m_name;
					Row row = rows.FirstOrDefault((Row r) => r.Name == token);
					if (row != null)
					{
						row.Need += amount;
						continue;
					}
					rows.Add(new Row
					{
						Name = token,
						Need = amount,
						Have = ((Humanoid)player).GetInventory().CountItems(token, -1, true)
					});
				}
			}
		}

		private void Styles()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			if (title == null)
			{
				title = new GUIStyle(GUI.skin.label)
				{
					fontSize = 20,
					fontStyle = (FontStyle)1,
					wordWrap = true,
					richText = false
				};
				title.normal.textColor = new Color(0.25f, 0.7f, 1f);
				line = new GUIStyle(GUI.skin.label)
				{
					fontSize = 17,
					wordWrap = true,
					richText = false
				};
				hint = new GUIStyle(GUI.skin.label)
				{
					fontSize = 13,
					wordWrap = true,
					richText = false
				};
			}
		}

		private void OnGUI()
		{
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)owner) || ((Character)owner).IsDead() || (!Object.op_Implicit((Object)(object)tracked) && Time.unscaledTime >= noticeUntil))
			{
				return;
			}
			Styles();
			Matrix4x4 matrix = GUI.matrix;
			int depth = GUI.depth;
			float num = Mathf.Clamp((float)Screen.height / 1080f * scale.Value, 0.5f, 2.5f);
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
			GUI.depth = -100;
			try
			{
				float num2 = (float)Screen.width / num;
				float num3 = (float)Screen.height / num;
				if (Time.unscaledTime < noticeUntil)
				{
					GUI.Box(new Rect(Mathf.Max(10f, (num2 - 520f) / 2f), num3 * 0.2f, 520f, 55f), notice);
				}
				if (!Object.op_Implicit((Object)(object)tracked))
				{
					return;
				}
				float num4 = Mathf.Min(num3 - 20f, (float)(150 + rows.Count * 48));
				GUILayout.BeginArea(new Rect(Mathf.Max(10f, num2 - 230f - right.Value), Mathf.Clamp(top.Value, 10f, Mathf.Max(10f, num3 - num4 - 10f)), 230f, num4));
				GUILayout.Label("CRAFT: " + Name(tracked), title, Array.Empty<GUILayoutOption>());
				bool flag = (EitherIngredient ? rows.Any((Row r) => r.Have >= r.Need) : rows.All((Row r) => r.Have >= r.Need));
				GUILayout.Label(EitherIngredient ? "Use ONE of these ingredients:" : "Materials in your inventory:", hint, Array.Empty<GUILayoutOption>());
				foreach (Row row in rows)
				{
					line.normal.textColor = ((row.Have >= row.Need) ? new Color(0.35f, 1f, 0.4f) : new Color(1f, 0.3f, 0.3f));
					GUILayout.Label(Local(row.Name) + "  " + row.Have + "/" + row.Need, line, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Label(flag ? "Materials ready — craft at the required station." : "Collect the missing materials.", hint, Array.Empty<GUILayoutOption>());
				if (InventoryGui.IsVisible() && GUILayout.Button("Clear tracker", Array.Empty<GUILayoutOption>()))
				{
					tracked = null;
					rows.Clear();
				}
				GUILayout.EndArea();
			}
			finally
			{
				GUI.matrix = matrix;
				GUI.depth = depth;
			}
		}

		private static int OutputCount(Player player, Recipe recipe)
		{
			return ((Humanoid)player).GetInventory().CountItems(recipe.m_item.m_itemData.m_shared.m_name, -1, true);
		}

		private static void BeforeCraft(InventoryGui __instance, Player player, out CraftState __state)
		{
			__state = null;
			Plugin instance = Instance;
			if (Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)instance.tracked) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && UpgradeItem.GetValue(__instance) == null)
			{
				object? value = CraftRecipe.GetValue(__instance);
				Recipe val = (Recipe)((value is Recipe) ? value : null);
				if (!((Object)(object)val != (Object)(object)instance.tracked))
				{
					__state = new CraftState
					{
						Recipe = val,
						Player = player,
						Before = OutputCount(player, val)
					};
				}
			}
		}

		private static void AfterCraft(CraftState __state)
		{
			if (__state != null && Object.op_Implicit((Object)(object)Instance) && !((Object)(object)Instance.tracked != (Object)(object)__state.Recipe) && OutputCount(__state.Player, __state.Recipe) > __state.Before)
			{
				Instance.tracked = null;
				Instance.rows.Clear();
			}
		}
	}
}