Decompiled source of WhatsMyWorkbenchMissing v0.1.0

BepInEx/plugins/WhatsMyWorkbenchMissing.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("WhatsMyWorkbenchMissing")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+d5a8ee4882e3122994c9bdaae89ebc5453618d37")]
[assembly: AssemblyProduct("WhatsMyWorkbenchMissing")]
[assembly: AssemblyTitle("WhatsMyWorkbenchMissing")]
[assembly: AssemblyVersion("0.1.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 WhatsMyWorkbenchMissing
{
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
	internal static class LevelTooltip
	{
		private const float RefreshInterval = 0.5f;

		private static UITooltip _tooltip;

		private static bool _warnedNoPrefab;

		private static CraftingStation _lastStation;

		private static int _lastLevel = -1;

		private static float _nextRefresh;

		private static void Postfix(InventoryGui __instance, Player player)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			RectTransform craftingStationLevelRoot = __instance.m_craftingStationLevelRoot;
			if ((Object)(object)craftingStationLevelRoot == (Object)null || (Object)(object)player == (Object)null)
			{
				return;
			}
			CraftingStation val = (WhatsMyWorkbenchMissingMod.ModEnabled.Value ? player.GetCurrentCraftingStation() : null);
			if ((Object)(object)val == (Object)null)
			{
				if ((Object)(object)_tooltip != (Object)null)
				{
					_tooltip.Set("", "", (RectTransform)null, default(Vector2));
				}
				_lastStation = null;
				_lastLevel = -1;
				return;
			}
			if ((Object)(object)_tooltip == (Object)null || (Object)(object)((Component)_tooltip).gameObject != (Object)(object)((Component)craftingStationLevelRoot).gameObject)
			{
				_tooltip = Attach(__instance, craftingStationLevelRoot);
			}
			if (!((Object)(object)_tooltip == (Object)null))
			{
				int level = val.GetLevel(true);
				if (!((Object)(object)val == (Object)(object)_lastStation) || level != _lastLevel || !(Time.unscaledTime < _nextRefresh))
				{
					_lastStation = val;
					_lastLevel = level;
					_nextRefresh = Time.unscaledTime + 0.5f;
					UpgradeReport.Build(val, player, out var topic, out var text);
					_tooltip.Set(topic, text, (RectTransform)null, default(Vector2));
				}
			}
		}

		private static UITooltip Attach(InventoryGui gui, RectTransform root)
		{
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			UITooltip component = ((Component)root).GetComponent<UITooltip>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			GameObject val = null;
			UITooltip val2 = (((Object)(object)gui.m_craftButton != (Object)null) ? ((Component)gui.m_craftButton).GetComponent<UITooltip>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				val = val2.m_tooltipPrefab;
			}
			if ((Object)(object)val == (Object)null)
			{
				UITooltip[] componentsInChildren = ((Component)gui).GetComponentsInChildren<UITooltip>(true);
				foreach (UITooltip val3 in componentsInChildren)
				{
					if ((Object)(object)val3.m_tooltipPrefab != (Object)null)
					{
						val = val3.m_tooltipPrefab;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				if (!_warnedNoPrefab)
				{
					_warnedNoPrefab = true;
					WhatsMyWorkbenchMissingMod.Log.LogWarning((object)"No tooltip prefab found in the inventory panel; the level tooltip is off.");
				}
				return null;
			}
			bool flag = false;
			Graphic[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Graphic>(true);
			foreach (Graphic obj in componentsInChildren2)
			{
				obj.raycastTarget = true;
				if ((Object)(object)((Component)obj).gameObject == (Object)(object)((Component)root).gameObject)
				{
					flag = true;
				}
			}
			if (!flag)
			{
				Image obj2 = ((Component)root).gameObject.AddComponent<Image>();
				((Graphic)obj2).color = Color.clear;
				((Graphic)obj2).raycastTarget = true;
			}
			UITooltip obj3 = ((Component)root).gameObject.AddComponent<UITooltip>();
			obj3.m_tooltipPrefab = val;
			WhatsMyWorkbenchMissingMod.Log.LogInfo((object)"Level tooltip attached to the crafting panel.");
			return obj3;
		}
	}
	internal static class UpgradeReport
	{
		private const string ColorReady = "#9be27a";

		private const string ColorKnown = "#ffb866";

		private const string ColorShort = "#ff5e5e";

		private const string ColorDim = "#9a9a9a";

		private static Dictionary<string, List<Piece>> _byStation;

		private static ObjectDB _indexedDb;

		private static int _indexedItemCount = -1;

		private static readonly List<StationExtension> _attached = new List<StationExtension>();

		private static readonly HashSet<string> _builtNames = new HashSet<string>();

		private static readonly List<Piece> _ready = new List<Piece>();

		private static readonly List<Piece> _known = new List<Piece>();

		private static readonly List<Piece> _built = new List<Piece>();

		internal static void Build(CraftingStation station, Player player, out string topic, out string text)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			int level = station.GetLevel(true);
			topic = $"{station.m_name} level {level}";
			Dictionary<string, List<Piece>> dictionary = Index();
			List<Piece> value = null;
			dictionary?.TryGetValue(station.m_name, out value);
			if (value == null || value.Count == 0)
			{
				text = "This station has no upgrades.";
				return;
			}
			_attached.Clear();
			StationExtension.FindExtensions(station, ((Component)station).transform.position, _attached);
			_builtNames.Clear();
			foreach (StationExtension item in _attached)
			{
				Piece val = (Object.op_Implicit((Object)(object)item) ? ((Component)item).GetComponent<Piece>() : null);
				if ((Object)(object)val != (Object)null)
				{
					_builtNames.Add(val.m_name);
				}
			}
			_ready.Clear();
			_known.Clear();
			_built.Clear();
			int num = 0;
			foreach (Piece item2 in value)
			{
				if (_builtNames.Contains(item2.m_name))
				{
					_built.Add(item2);
				}
				else if (item2.m_enabled)
				{
					if (!IsKnown(item2, player))
					{
						num++;
					}
					else if (player.HaveRequirements(item2, (RequirementMode)0))
					{
						_ready.Add(item2);
					}
					else
					{
						_known.Add(item2);
					}
				}
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			StringBuilder stringBuilder = new StringBuilder();
			if (_ready.Count > 0)
			{
				stringBuilder.Append("<color=").Append("#9be27a").Append(">Ready to build:</color>\n");
				foreach (Piece item3 in _ready)
				{
					AppendPiece(stringBuilder, item3, inventory, "#9be27a");
				}
			}
			if (_known.Count > 0)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append("<color=").Append("#ffb866").Append(">Missing materials:</color>\n");
				foreach (Piece item4 in _known)
				{
					AppendPiece(stringBuilder, item4, inventory, "#ffb866");
				}
			}
			if (_ready.Count == 0 && _known.Count == 0)
			{
				if (num == 0)
				{
					stringBuilder.Append("Fully upgraded.\n");
				}
				else if (_built.Count == 0)
				{
					stringBuilder.Append("No upgrades discovered yet.\n");
				}
				else
				{
					stringBuilder.Append("Every upgrade you know is built.\n");
				}
			}
			if (WhatsMyWorkbenchMissingMod.ShowUndiscovered.Value && num > 0)
			{
				stringBuilder.Append("<color=").Append("#9a9a9a").Append('>')
					.Append(num)
					.Append((num == 1) ? " more upgrade" : " more upgrades")
					.Append(" not yet discovered.</color>\n");
			}
			if (WhatsMyWorkbenchMissingMod.ShowBuilt.Value && _built.Count > 0)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append("<color=").Append("#9a9a9a").Append(">Built:\n");
				foreach (Piece item5 in _built)
				{
					stringBuilder.Append("  ").Append(item5.m_name).Append('\n');
				}
				stringBuilder.Append("</color>");
			}
			text = stringBuilder.ToString().TrimEnd(new char[1] { '\n' });
		}

		private static bool IsKnown(Piece piece, Player player)
		{
			if (player.NoCostCheat())
			{
				return true;
			}
			if (player.IsRecipeKnown(piece.m_name))
			{
				return player.HaveRequirements(piece, (RequirementMode)1);
			}
			return false;
		}

		private static void AppendPiece(StringBuilder sb, Piece piece, Inventory inventory, string nameColor)
		{
			sb.Append("  <color=").Append(nameColor).Append('>')
				.Append(piece.m_name)
				.Append("</color>");
			if (WhatsMyWorkbenchMissingMod.ShowMaterials.Value)
			{
				bool flag = true;
				Requirement[] resources = piece.m_resources;
				foreach (Requirement val in resources)
				{
					if (!((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0)
					{
						string name = val.m_resItem.m_itemData.m_shared.m_name;
						int num = ((inventory != null) ? inventory.CountItems(name, -1, true) : 0);
						sb.Append(flag ? "   " : ", ");
						flag = false;
						if (num >= val.m_amount)
						{
							sb.Append(val.m_amount).Append(' ').Append(name);
						}
						else
						{
							sb.Append("<color=").Append("#ff5e5e").Append('>')
								.Append(num)
								.Append('/')
								.Append(val.m_amount)
								.Append(' ')
								.Append(name)
								.Append("</color>");
						}
					}
				}
			}
			sb.Append('\n');
		}

		private static Dictionary<string, List<Piece>> Index()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if (_byStation != null && (Object)(object)_indexedDb == (Object)(object)instance && _indexedItemCount == instance.m_items.Count)
			{
				return _byStation;
			}
			Dictionary<string, List<Piece>> dictionary = new Dictionary<string, List<Piece>>();
			HashSet<GameObject> hashSet = new HashSet<GameObject>();
			HashSet<string> hashSet2 = new HashSet<string>();
			foreach (GameObject item in instance.m_items)
			{
				PieceTable val = (Object.op_Implicit((Object)(object)item) ? item.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_buildPieces;
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				foreach (GameObject piece in val.m_pieces)
				{
					if ((Object)(object)piece == (Object)null || !hashSet.Add(piece))
					{
						continue;
					}
					StationExtension component = piece.GetComponent<StationExtension>();
					if ((Object)(object)component == (Object)null || (Object)(object)component.m_craftingStation == (Object)null)
					{
						continue;
					}
					Piece component2 = piece.GetComponent<Piece>();
					if (!((Object)(object)component2 == (Object)null) && hashSet2.Add(component.m_craftingStation.m_name + "\n" + component2.m_name))
					{
						if (!dictionary.TryGetValue(component.m_craftingStation.m_name, out var value))
						{
							value = new List<Piece>();
							dictionary[component.m_craftingStation.m_name] = value;
						}
						value.Add(component2);
					}
				}
			}
			_byStation = dictionary;
			_indexedDb = instance;
			_indexedItemCount = instance.m_items.Count;
			int num = 0;
			foreach (List<Piece> value2 in dictionary.Values)
			{
				num += value2.Count;
			}
			WhatsMyWorkbenchMissingMod.Log.LogInfo((object)$"Indexed {num} station upgrades for {dictionary.Count} stations.");
			return dictionary;
		}
	}
	[BepInPlugin("DeathMonger.WhatsMyWorkbenchMissing", "What's My Workbench Missing", "0.1.0")]
	[BepInProcess("valheim.exe")]
	public class WhatsMyWorkbenchMissingMod : BaseUnityPlugin
	{
		public const string ModGuid = "DeathMonger.WhatsMyWorkbenchMissing";

		public const string ModName = "What's My Workbench Missing";

		public const string ModVersion = "0.1.0";

		internal static ConfigEntry<bool> ModEnabled;

		internal static ConfigEntry<bool> ShowMaterials;

		internal static ConfigEntry<bool> ShowUndiscovered;

		internal static ConfigEntry<bool> ShowBuilt;

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Mod Enabled", true, "Master switch. Off means the level number shows no tooltip. Takes effect immediately.");
			ShowMaterials = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Materials", true, "List each upgrade's materials after its name. Amounts you are short of are red and show how many you carry, as in 4/10 Flint.");
			ShowUndiscovered = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Undiscovered Count", true, "Add a line counting the upgrades you have not discovered yet, without naming them. Off leaves the undiscovered ones out entirely.");
			ShowBuilt = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Built", false, "Also list the upgrades already attached to the station, dimmed, so the tooltip shows the whole picture.");
			_harmony = new Harmony("DeathMonger.WhatsMyWorkbenchMissing");
			_harmony.PatchAll();
			Log.LogInfo((object)"What's My Workbench Missing 0.1.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}