Decompiled source of Hugin What The Hel Is That v1.0.0

Hugin.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Hugin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b2d1831e78047b263c4f86bf4960531bae2d7afb")]
[assembly: AssemblyProduct("Hugin")]
[assembly: AssemblyTitle("Hugin")]
[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 Hugin
{
	internal class BossBar : MonoBehaviour
	{
		private const float IconSize = 20f;

		private static readonly FieldRef<EnemyHud, IDictionary> Huds = AccessTools.FieldRefAccess<EnemyHud, IDictionary>(AccessTools.Field(typeof(EnemyHud), "m_huds"));

		private static int _frame = -1;

		private static bool _showing;

		private static Rect _bar;

		private static Character _boss;

		private static Character _groupsFor;

		private static List<Weakness.Group> _groups;

		internal static bool Find(out Rect bar, out Character boss)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (_frame != Time.frameCount)
			{
				_frame = Time.frameCount;
				_showing = Locate(out _bar, out _boss);
			}
			bar = _bar;
			boss = _boss;
			return _showing;
		}

		private static bool Locate(out Rect bar, out Character boss)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			bar = default(Rect);
			boss = null;
			EnemyHud instance = EnemyHud.instance;
			if ((Object)(object)instance == (Object)null || Huds == null)
			{
				return false;
			}
			IDictionary dictionary = Huds.Invoke(instance);
			if (dictionary == null)
			{
				return false;
			}
			foreach (DictionaryEntry item in dictionary)
			{
				object key = item.Key;
				Character val = (Character)((key is Character) ? key : null);
				if (!((Object)(object)val == (Object)null) && val.IsBoss())
				{
					GameObject value = Traverse.Create(item.Value).Field("m_gui").GetValue<GameObject>();
					RectTransform val2 = (RectTransform)(((Object)(object)value != (Object)null && value.activeInHierarchy) ? /*isinst with value type is only supported in some contexts*/: null);
					if (!((Object)(object)val2 == (Object)null))
					{
						bar = ToGui(val2);
						boss = val;
						return ((Rect)(ref bar)).width > 0f;
					}
				}
			}
			return false;
		}

		private static Rect ToGui(RectTransform rt)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			rt.GetWorldCorners(array);
			Canvas componentInParent = ((Component)rt).GetComponentInParent<Canvas>();
			Camera obj = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
			Vector2 val = RectTransformUtility.WorldToScreenPoint(obj, array[0]);
			Vector2 val2 = RectTransformUtility.WorldToScreenPoint(obj, array[2]);
			float num = (float)Screen.height / 1080f * Plugin.UiScale.Value;
			return new Rect(val.x / num, ((float)Screen.height - val2.y) / num, (val2.x - val.x) / num, (val2.y - val.y) / num);
		}

		internal static float Bottom()
		{
			if (!Find(out var bar, out var _))
			{
				return 0f;
			}
			return ((Rect)(ref bar)).yMax + ((Plugin.BossBar.Value && Plugin.ShowWeaknesses.Value) ? 26f : 0f) + 8f;
		}

		private void OnGUI()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type != 7 || !Plugin.BossBar.Value || !Plugin.ShowWeaknesses.Value || Panel.ScreenHidden() || !Find(out var bar, out var boss))
			{
				return;
			}
			if ((Object)(object)boss != (Object)(object)_groupsFor)
			{
				_groupsFor = boss;
				_groups = Weakness.Groups(boss.m_damageModifiers);
			}
			GUISkin skin = GUI.skin;
			GUI.skin = Ui.Skin;
			float width;
			float height;
			Matrix4x4 matrix = Ui.BeginScaled(out width, out height);
			try
			{
				if (_groups.Count == 0)
				{
					Ui.Label(new Rect(((Rect)(ref bar)).center.x - 150f, ((Rect)(ref bar)).yMax + 6f, 300f, 20f), "<color=#b9ad98>No weaknesses or resistances</color>", Ui.SmallCenter);
				}
				else
				{
					Weakness.Draw(_groups, Mathf.Round(((Rect)(ref bar)).center.x - Weakness.Width(_groups, 20f) * 0.5f), ((Rect)(ref bar)).yMax + 6f, 20f);
				}
			}
			finally
			{
				GUI.matrix = matrix;
				GUI.skin = skin;
			}
		}
	}
	internal static class Details
	{
		private static readonly Color WorkColor = new Color(0.95f, 0.75f, 0.3f);

		private static readonly MethodInfo GetSlot = AccessTools.Method(typeof(CookingStation), "GetSlot", (Type[])null, (Type[])null);

		private static readonly MethodInfo GetConversion = AccessTools.Method(typeof(CookingStation), "GetItemConversion", (Type[])null, (Type[])null);

		private static readonly Dictionary<string, MethodInfo> Methods = new Dictionary<string, MethodInfo>();

		private static readonly Dictionary<string, FieldInfo> Fields = new Dictionary<string, FieldInfo>();

		internal static void Production(GameObject go, ZDO zdo, Info info)
		{
			Smelter component = go.GetComponent<Smelter>();
			if ((Object)(object)component != (Object)null)
			{
				Smelter(component, info);
			}
			Fermenter component2 = go.GetComponent<Fermenter>();
			if ((Object)(object)component2 != (Object)null)
			{
				Fermenter(component2, info);
			}
			Beehive component3 = go.GetComponent<Beehive>();
			if ((Object)(object)component3 != (Object)null)
			{
				Beehive(component3, info);
			}
			CookingStation component4 = go.GetComponent<CookingStation>();
			if ((Object)(object)component4 != (Object)null)
			{
				Cooking(component4, info);
			}
		}

		internal static void Base(GameObject go, ZDO zdo, Info info)
		{
			if (zdo == null)
			{
				return;
			}
			PrivateArea component = go.GetComponent<PrivateArea>();
			if ((Object)(object)component != (Object)null)
			{
				string text = Call<string>(component, "GetCreatorName") ?? "";
				bool flag = Call<bool>(component, "IsEnabled");
				info.Lines.Add((flag ? "<color=#9be07a>Active</color>" : "Off") + ((text.Length > 0) ? (", " + text + "'s") : ""));
			}
			Bed component2 = go.GetComponent<Bed>();
			if ((Object)(object)component2 != (Object)null)
			{
				string text2 = Call<string>(component2, "GetOwnerName") ?? "";
				info.Lines.Add((text2.Length > 0) ? (text2 + "'s bed") : "No owner");
			}
			TombStone component3 = go.GetComponent<TombStone>();
			if ((Object)(object)component3 != (Object)null)
			{
				string ownerName = component3.GetOwnerName();
				if (!string.IsNullOrEmpty(ownerName))
				{
					info.Title = ownerName + "'s grave";
				}
			}
			TeleportWorld component4 = go.GetComponent<TeleportWorld>();
			if ((Object)(object)component4 != (Object)null)
			{
				string text3 = component4.GetText();
				info.Lines.Add(string.IsNullOrEmpty(text3) ? "No tag" : ("Tag: " + text3));
			}
			ItemStand component5 = go.GetComponent<ItemStand>();
			if ((Object)(object)component5 != (Object)null)
			{
				string text4 = (component5.HaveAttachment() ? ItemName(component5.GetAttachedItem()) : null);
				info.Lines.Add((text4 != null) ? ("Holds " + text4) : "Empty");
			}
			ArmorStand component6 = go.GetComponent<ArmorStand>();
			if (!((Object)(object)component6 != (Object)null) || component6.m_slots == null)
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < component6.m_slots.Count; i++)
			{
				if (component6.HaveAttachment(i))
				{
					num++;
				}
			}
			info.Lines.Add((num == 0) ? "Empty" : $"{num} / {component6.m_slots.Count} slots used");
		}

		internal static void Creature(Character c, Info info)
		{
			if (!c.IsTamed())
			{
				string text = Temper(c);
				if (text.Contains("Hostile"))
				{
					info.More.Add(text);
				}
				else if (text.Length > 0)
				{
					info.Lines.Add(text);
				}
			}
			Tameable component = ((Component)c).GetComponent<Tameable>();
			if ((Object)(object)component != (Object)null && c.IsTamed())
			{
				string text2 = component.GetText();
				if (!string.IsNullOrEmpty(text2))
				{
					info.Title = text2 + " <color=#b9ad98>(" + info.Title + ")</color>";
				}
				if (Call<bool>(component, "HaveSaddle"))
				{
					info.Lines.Add("Saddled");
				}
			}
			Procreation component2 = ((Component)c).GetComponent<Procreation>();
			ZNetView component3 = ((Component)c).GetComponent<ZNetView>();
			if ((Object)(object)component2 != (Object)null && c.IsTamed() && (Object)(object)component3 != (Object)null && component3.IsValid() && (Object)(object)ZNet.instance != (Object)null)
			{
				long num = component3.GetZDO().GetLong(ZDOVars.s_pregnant, 0L);
				if (num != 0L)
				{
					double totalSeconds = (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds;
					double num2 = (double)component2.m_pregnancyDuration - totalSeconds;
					info.Lines.Add((num2 > 0.0) ? ("Expecting, due in " + Time(num2)) : "Expecting, any moment now");
				}
				else if (component2.ReadyForProcreation())
				{
					info.Lines.Add("Ready to breed");
				}
			}
		}

		private static string Temper(Character c)
		{
			BaseAI baseAI = c.GetBaseAI();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)baseAI == (Object)null || (Object)(object)localPlayer == (Object)null)
			{
				return "";
			}
			if (baseAI is AnimalAI)
			{
				return "Runs away";
			}
			if (!BaseAI.IsEnemy(c, (Character)(object)localPlayer))
			{
				return "<color=#9be07a>Friendly</color>";
			}
			if (baseAI.IsAggravatable() && !baseAI.IsAggravated())
			{
				return "Neutral until provoked";
			}
			if (baseAI.m_passiveAggresive)
			{
				return "Attacks if attacked";
			}
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)30))
			{
				return "Passive (world setting)";
			}
			return "<color=#ff6f55>Hostile</color>";
		}

		private static void Smelter(Smelter s, Info info)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			int num = Call<int>(s, "GetQueueSize");
			int num2 = Call<int>(s, "GetProcessedQueueSize");
			float num3 = Call<float>(s, "GetFuel");
			float num4 = Call<float>(s, "GetBakeTimer");
			string text = Call<string>(s, "GetQueuedOre");
			if (s.m_maxOre > 0)
			{
				info.Lines.Add((num > 0) ? $"{L(ItemNameByPrefab(text) ?? text)}: {num} / {s.m_maxOre}" : "Nothing to smelt");
			}
			if (s.m_maxFuel > 0)
			{
				info.Bar = Mathf.Clamp01(num3 / (float)s.m_maxFuel);
				info.BarColor = new Color(0.95f, 0.6f, 0.2f);
				info.BarText = string.Format("{0} {1} / {2}", L(((Object)(object)s.m_fuelItem != (Object)null) ? s.m_fuelItem.m_itemData.m_shared.m_name : "Fuel"), Mathf.CeilToInt(num3), s.m_maxFuel);
			}
			if (num > 0 && s.m_secPerProduct > 0f && (s.m_maxFuel == 0 || num3 > 0f))
			{
				string text2 = ((s.m_requiresRoof && !Field<bool>(s, "m_haveRoof")) ? "needs a roof" : (Field<bool>(s, "m_blockedSmoke") ? "smoke is blocked" : (((Object)(object)s.m_windmill != (Object)null && s.m_windmill.GetPowerOutput() <= 0f) ? "no wind" : null)));
				info.Lines.Add((text2 != null) ? ("<color=#ff6f55>Stopped: " + text2 + "</color>") : ("Next in " + Time(Mathf.Max(0f, s.m_secPerProduct - num4))));
			}
			if (num2 > 0)
			{
				info.Lines.Add(string.Format("<color={0}>{1} ready to take</color>", "#9be07a", num2));
			}
		}

		private static void Fermenter(Fermenter f, Info info)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			string text = CallObject(f, "GetStatus")?.ToString();
			string text2 = Call<string>(f, "GetContentName");
			if (text == "Empty" || string.IsNullOrEmpty(text2))
			{
				info.Lines.Add("Empty");
				return;
			}
			info.Lines.Add(L(text2));
			bool flag = Field<bool>(f, "m_hasRoof");
			bool flag2 = Field<bool>(f, "m_exposed");
			if (text == "Ready")
			{
				info.Lines.Add("<color=#9be07a>Ready to tap</color>");
				return;
			}
			if (!flag)
			{
				info.Lines.Add("<color=#ff6f55>Won't ferment: needs a roof</color>");
				return;
			}
			if (flag2)
			{
				info.Lines.Add("<color=#ff6f55>Won't ferment: too exposed, needs walls</color>");
				return;
			}
			double num = Call<double>(f, "GetFermentationTime");
			float bar = ((f.m_fermentationDuration > 0f) ? Mathf.Clamp01((float)(num / (double)f.m_fermentationDuration)) : 0f);
			info.Bar = bar;
			info.BarColor = WorkColor;
			info.BarText = "Ready in " + Time((double)f.m_fermentationDuration - num);
		}

		private static void Beehive(Beehive b, Info info)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			int num = Call<int>(b, "GetHoneyLevel");
			info.Bar = ((b.m_maxHoney > 0) ? Mathf.Clamp01((float)num / (float)b.m_maxHoney) : 0f);
			info.BarColor = WorkColor;
			info.BarText = $"Honey {num} / {b.m_maxHoney}";
		}

		private static void Cooking(CookingStation station, Info info)
		{
			if (GetSlot == null || GetConversion == null || station.m_slots == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			float num4 = float.MaxValue;
			float num5 = float.MaxValue;
			for (int i = 0; i < station.m_slots.Length; i++)
			{
				object[] array = new object[5] { i, null, 0f, null, false };
				try
				{
					GetSlot.Invoke(station, array);
				}
				catch (Exception)
				{
					return;
				}
				string text = array[1] as string;
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				float num6 = (float)array[2];
				int num7 = Convert.ToInt32(array[3]);
				object? obj = GetConversion.Invoke(station, new object[1] { text });
				ItemConversion val = (ItemConversion)((obj is ItemConversion) ? obj : null);
				switch (num7)
				{
				case 2:
					num3++;
					break;
				case 1:
					num2++;
					if (val != null && station.m_canOvercookItems)
					{
						num5 = Mathf.Min(num5, val.m_cookTime * 2f - num6);
					}
					break;
				default:
					num++;
					if (val != null)
					{
						num4 = Mathf.Min(num4, val.m_cookTime - num6);
					}
					break;
				}
			}
			if (num + num2 + num3 == 0)
			{
				info.Lines.Add("Nothing cooking");
				return;
			}
			bool flag = station.m_useFuel && Call<float>(station, "GetFuel") > 0f && (station.m_useFueldWhileEmpty || Call<bool>(station, "HaveUncookedItem"));
			bool flag2 = (station.m_requireFire && Call<bool>(station, "IsFireLit")) || flag;
			if (!flag2 && num + num2 > 0)
			{
				info.Lines.Add("<color=#ff6f55>Stopped: " + (station.m_useFuel ? "no fuel" : "no fire under it") + "</color>");
			}
			if (num > 0)
			{
				info.Lines.Add($"{num} cooking" + ((flag2 && num4 < float.MaxValue) ? (", first done in " + Time(Mathf.Max(0f, num4))) : ""));
			}
			if (num2 > 0)
			{
				info.Lines.Add(string.Format("<color={0}>{1} done</color>", "#9be07a", num2) + ((flag2 && num5 < float.MaxValue) ? ("<color=#f0b04a>, burns in " + Time(Mathf.Max(0f, num5)) + "</color>") : ""));
			}
			if (num3 > 0)
			{
				info.Lines.Add(string.Format("<color={0}>{1} burnt</color>", "#ff6f55", num3));
			}
		}

		private static object CallObject(object target, string method)
		{
			string key = target.GetType().FullName + "." + method;
			if (!Methods.TryGetValue(key, out var value))
			{
				value = AccessTools.Method(target.GetType(), method, Type.EmptyTypes, (Type[])null);
				Methods[key] = value;
			}
			if (value == null)
			{
				return null;
			}
			try
			{
				return value.Invoke(target, null);
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static T Call<T>(object target, string method)
		{
			object obj = CallObject(target, method);
			if (obj is T)
			{
				return (T)obj;
			}
			return default(T);
		}

		private static T Field<T>(object target, string field)
		{
			string key = target.GetType().FullName + "." + field;
			if (!Fields.TryGetValue(key, out var value))
			{
				value = (Fields[key] = AccessTools.Field(target.GetType(), field));
			}
			if (value != null)
			{
				object value2 = value.GetValue(target);
				if (value2 is T)
				{
					return (T)value2;
				}
			}
			return default(T);
		}

		private static string ItemName(int hash)
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(hash) : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return null;
			}
			return L(val2.m_itemData.m_shared.m_name);
		}

		private static string ItemNameByPrefab(string prefab)
		{
			if (string.IsNullOrEmpty(prefab) || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
			if (!((Object)(object)itemPrefab != (Object)null))
			{
				return null;
			}
			return itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_name;
		}

		private static string L(string token)
		{
			return Looking.L(token);
		}

		internal static string Time(double seconds)
		{
			if (seconds < 60.0)
			{
				return $"{Mathf.CeilToInt((float)seconds)} s";
			}
			int num = Mathf.CeilToInt((float)(seconds / 60.0));
			if (num < 60)
			{
				return $"{num} min";
			}
			return $"{num / 60} h {num % 60} min";
		}
	}
	internal static class Extended
	{
		private enum Tool
		{
			None,
			Pickaxe,
			Axe
		}

		private static readonly Dictionary<string, string> ToolNames = new Dictionary<string, string>();

		internal static void Resistances(List<Weakness.Group> groups, Info info)
		{
			foreach (Weakness.Group group in groups)
			{
				List<string> list = new List<string>();
				foreach (Weakness.Icon icon in group.Icons)
				{
					list.Add((icon.Amount != null) ? (icon.Name + " (" + icon.Amount + ")") : icon.Name);
				}
				info.More.Add(group.Text + " " + string.Join(", ", list.ToArray()));
			}
		}

		internal static void Drops(GameObject go, Info info)
		{
			HashSet<Sprite> seen = new HashSet<Sprite>();
			CharacterDrop component = go.GetComponent<CharacterDrop>();
			if ((Object)(object)component != (Object)null)
			{
				foreach (Drop drop in component.m_drops)
				{
					Add(drop.m_prefab, info, seen);
				}
			}
			AddTable(go.GetComponent<TreeBase>()?.m_dropWhenDestroyed, info, seen);
			AddTable(go.GetComponent<TreeLog>()?.m_dropWhenDestroyed, info, seen);
			AddTable(go.GetComponent<MineRock>()?.m_dropItems, info, seen);
			AddTable(go.GetComponent<MineRock5>()?.m_dropItems, info, seen);
			AddTable(go.GetComponent<DropOnDestroyed>()?.m_dropWhenDestroyed, info, seen);
			Pickable component2 = go.GetComponent<Pickable>();
			if ((Object)(object)component2 != (Object)null)
			{
				Add(component2.m_itemPrefab, info, seen);
				AddTable(component2.m_extraDrops, info, seen);
			}
		}

		private static void AddTable(DropTable table, Info info, HashSet<Sprite> seen)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (table?.m_drops == null)
			{
				return;
			}
			foreach (DropData drop in table.m_drops)
			{
				Add(drop.m_item, info, seen);
			}
		}

		private static void Add(GameObject prefab, Info info, HashSet<Sprite> seen)
		{
			object obj;
			if (!((Object)(object)prefab != (Object)null))
			{
				obj = null;
			}
			else
			{
				ItemDrop component = prefab.GetComponent<ItemDrop>();
				obj = ((component != null) ? component.m_itemData.GetIcon() : null);
			}
			Sprite val = (Sprite)obj;
			if ((Object)(object)val != (Object)null && seen.Add(val))
			{
				info.Drops.Add(val);
			}
		}

		internal static void Item(ItemData data, Info info)
		{
			SharedData shared = data.m_shared;
			if (!shared.m_teleportable)
			{
				info.Lines.Add("<color=#ff6f55>Can't go through portals</color>");
			}
			info.More.Add($"Weight {data.GetWeight(-1):0.#}" + ((data.m_stack > 1) ? $" ({shared.m_weight:0.#} each)" : ""));
			if (shared.m_value > 0)
			{
				info.More.Add($"Sells for {shared.m_value * data.m_stack} coins");
			}
			if (shared.m_maxStackSize > 1)
			{
				info.More.Add($"Stacks to {shared.m_maxStackSize}");
			}
		}

		internal static void ToolNeed(GameObject go, Info info)
		{
			if (!Requirement(go, out var tool, out var tier) || tool == Tool.None)
			{
				return;
			}
			string text = Weakest(tool, tier);
			if (text != null)
			{
				if (!Carrying(tool, tier))
				{
					info.Lines.Add("<color=#ff6f55>Needs " + text + "</color>");
				}
				else if (tier > 0)
				{
					info.More.Add("Needs " + text);
				}
			}
		}

		private static bool Requirement(GameObject go, out Tool tool, out int tier)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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)
			tool = Tool.None;
			tier = 0;
			MineRock component = go.GetComponent<MineRock>();
			MineRock5 component2 = go.GetComponent<MineRock5>();
			TreeBase component3 = go.GetComponent<TreeBase>();
			TreeLog component4 = go.GetComponent<TreeLog>();
			Destructible component5 = go.GetComponent<Destructible>();
			if ((Object)(object)component != (Object)null)
			{
				Set(component.m_damageModifiers, component.m_minToolTier, out tool, out tier);
			}
			else if ((Object)(object)component2 != (Object)null)
			{
				Set(component2.m_damageModifiers, component2.m_minToolTier, out tool, out tier);
			}
			else if ((Object)(object)component3 != (Object)null)
			{
				Set(component3.m_damageModifiers, component3.m_minToolTier, out tool, out tier);
			}
			else if ((Object)(object)component4 != (Object)null)
			{
				Set(component4.m_damages, component4.m_minToolTier, out tool, out tier);
			}
			else
			{
				if (!((Object)(object)component5 != (Object)null))
				{
					return false;
				}
				Set(component5.m_damages, component5.m_minToolTier, out tool, out tier);
			}
			return true;
		}

		private static void Set(DamageModifiers m, int minTier, out Tool tool, out int tier)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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)
			tier = minTier;
			bool flag = Immune(m.m_blunt) && Immune(m.m_slash) && Immune(m.m_pierce);
			if (flag && !Immune(m.m_pickaxe) && Immune(m.m_chop))
			{
				tool = Tool.Pickaxe;
			}
			else if (flag && !Immune(m.m_chop) && Immune(m.m_pickaxe))
			{
				tool = Tool.Axe;
			}
			else
			{
				tool = Tool.None;
			}
		}

		private static bool Immune(DamageModifier m)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)m != 3)
			{
				return (int)m == 4;
			}
			return true;
		}

		private static bool Fits(SharedData shared, Tool tool, int tier)
		{
			if (shared.m_toolTier >= tier)
			{
				if (tool != Tool.Pickaxe)
				{
					return shared.m_damages.m_chop > 0f;
				}
				return shared.m_damages.m_pickaxe > 0f;
			}
			return false;
		}

		private static bool Carrying(Tool tool, int tier)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return true;
			}
			foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
			{
				if (Fits(allItem.m_shared, tool, tier))
				{
					return true;
				}
			}
			return false;
		}

		private static string Weakest(Tool tool, int tier)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			string key = tool.ToString() + "/" + tier;
			if (ToolNames.TryGetValue(key, out var value))
			{
				return value;
			}
			SharedData val = null;
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				foreach (GameObject item in ObjectDB.instance.m_items)
				{
					SharedData val2 = ((!((Object)(object)item != (Object)null)) ? null : item.GetComponent<ItemDrop>()?.m_itemData.m_shared);
					if (val2 != null && Fits(val2, tool, tier) && (int)val2.m_itemType != 0 && (val == null || val2.m_toolTier < val.m_toolTier))
					{
						val = val2;
					}
				}
			}
			if (val == null || Localization.instance == null)
			{
				return null;
			}
			string text = Looking.L(val.m_name);
			if (tier == 0)
			{
				text = ((tool == Tool.Pickaxe) ? "a pickaxe" : "an axe");
			}
			else
			{
				text = text.ToLowerInvariant();
				text = (("aeiou".IndexOf(text[0]) >= 0) ? "an " : "a ") + text + " or better";
			}
			ToolNames[key] = text;
			return text;
		}
	}
	internal static class GameArt
	{
		private static Dictionary<string, Sprite> _sprites;

		private static readonly Dictionary<Sprite, Rect> UvCache = new Dictionary<Sprite, Rect>();

		internal static Sprite Find(string name)
		{
			if (_sprites == null)
			{
				_sprites = new Dictionary<string, Sprite>();
				Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
				foreach (Sprite val in array)
				{
					if ((Object)(object)val != (Object)null && !_sprites.ContainsKey(((Object)val).name))
					{
						_sprites[((Object)val).name] = val;
					}
				}
			}
			if (!_sprites.TryGetValue(name, out var value) || !((Object)(object)value != (Object)null))
			{
				return null;
			}
			return value;
		}

		internal static bool UvRect(Sprite sprite, out Rect uv)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			uv = default(Rect);
			if ((Object)(object)sprite == (Object)null)
			{
				return false;
			}
			if (UvCache.TryGetValue(sprite, out uv))
			{
				return ((Rect)(ref uv)).width > 0f;
			}
			bool flag = ComputeUvRect(sprite, out uv);
			if (UvCache.Count > 512)
			{
				UvCache.Clear();
			}
			UvCache[sprite] = (Rect)(flag ? uv : default(Rect));
			return flag;
		}

		private static bool ComputeUvRect(Sprite sprite, out Rect uv)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			uv = default(Rect);
			if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null)
			{
				return false;
			}
			if (sprite.packed && (int)sprite.packingRotation != 0)
			{
				return false;
			}
			Vector2[] uv2 = sprite.uv;
			if (uv2 == null || uv2.Length == 0)
			{
				return false;
			}
			Vector2 val = uv2[0];
			Vector2 val2 = uv2[0];
			Vector2[] array = uv2;
			foreach (Vector2 val3 in array)
			{
				val = Vector2.Min(val, val3);
				val2 = Vector2.Max(val2, val3);
			}
			uv = Rect.MinMaxRect(val.x, val.y, val2.x, val2.y);
			if (((Rect)(ref uv)).width > 0f)
			{
				return ((Rect)(ref uv)).height > 0f;
			}
			return false;
		}

		private static bool CoversRect(Sprite sprite)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			Vector2[] vertices = sprite.vertices;
			if (vertices == null || vertices.Length == 0)
			{
				return false;
			}
			Vector2 val = vertices[0];
			Vector2 val2 = vertices[0];
			Vector2[] array = vertices;
			foreach (Vector2 val3 in array)
			{
				val = Vector2.Min(val, val3);
				val2 = Vector2.Max(val2, val3);
			}
			Vector2 val4 = (val2 - val) * sprite.pixelsPerUnit;
			float x = val4.x;
			Rect rect = sprite.rect;
			if (Mathf.Abs(x - ((Rect)(ref rect)).width) <= 1.5f)
			{
				float y = val4.y;
				rect = sprite.rect;
				return Mathf.Abs(y - ((Rect)(ref rect)).height) <= 1.5f;
			}
			return false;
		}

		internal static Texture2D Copy(string name, out RectOffset border)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_012a: Expected O, but got Unknown
			border = null;
			Sprite val = Find(name);
			if ((Object)(object)val == (Object)null || !UvRect(val, out var uv) || !CoversRect(val))
			{
				return null;
			}
			Rect rect = val.rect;
			int num = Mathf.RoundToInt(((Rect)(ref rect)).width);
			rect = val.rect;
			int num2 = Mathf.RoundToInt(((Rect)(ref rect)).height);
			RenderTexture active = RenderTexture.active;
			RenderTexture temporary = RenderTexture.GetTemporary(num, num2, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			try
			{
				Graphics.Blit((Texture)(object)val.texture, temporary, new Vector2(((Rect)(ref uv)).width, ((Rect)(ref uv)).height), new Vector2(((Rect)(ref uv)).x, ((Rect)(ref uv)).y));
				RenderTexture.active = temporary;
				Texture2D val2 = new Texture2D(num, num2, (TextureFormat)4, false, false)
				{
					name = "Hugin_" + name,
					wrapMode = (TextureWrapMode)1,
					hideFlags = (HideFlags)61
				};
				val2.ReadPixels(new Rect(0f, 0f, (float)num, (float)num2), 0, 0);
				val2.Apply();
				Vector4 border2 = val.border;
				border = new RectOffset(Mathf.RoundToInt(border2.x), Mathf.RoundToInt(border2.z), Mathf.RoundToInt(border2.w), Mathf.RoundToInt(border2.y));
				return val2;
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[Hugin] Couldn't copy UI sprite " + name + ": " + ex.Message));
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		internal static Texture2D Composite(Texture2D bottom, Texture2D top)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			if ((Object)(object)bottom == (Object)null || (Object)(object)top == (Object)null || ((Texture)bottom).width != ((Texture)top).width || ((Texture)bottom).height != ((Texture)top).height)
			{
				return null;
			}
			Color[] pixels = bottom.GetPixels();
			Color[] pixels2 = top.GetPixels();
			for (int i = 0; i < pixels.Length; i++)
			{
				float a = pixels2[i].a;
				pixels[i] = new Color(Mathf.Lerp(pixels[i].r, pixels2[i].r, a), Mathf.Lerp(pixels[i].g, pixels2[i].g, a), Mathf.Lerp(pixels[i].b, pixels2[i].b, a), Mathf.Max(pixels[i].a, a));
			}
			Texture2D val = new Texture2D(((Texture)bottom).width, ((Texture)bottom).height, (TextureFormat)4, false, false)
			{
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
			val.SetPixels(pixels);
			val.Apply();
			return val;
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class ItemTooltipPatch
	{
		private static readonly Dictionary<string, GameObject> ByName = new Dictionary<string, GameObject>();

		private static ObjectDB _builtFor;

		private static void Postfix(ItemData item, bool appending, ref string __result)
		{
			if (appending || item == null || !Plugin.ItemTooltips.Value)
			{
				return;
			}
			GameObject val = (((Object)(object)item.m_dropPrefab != (Object)null) ? item.m_dropPrefab : Find(item.m_shared.m_name));
			if (!((Object)(object)val == (Object)null))
			{
				string text = ModSource.Of(((Object)val).name, val);
				if (text != null && (!(text == "Valheim") || Plugin.ShowVanilla.Value))
				{
					string text2 = ((text == "a mod") ? "Added by a mod" : text);
					__result = __result.TrimEnd(new char[1] { '\n' }) + "\n\n<color=#8ab4f8><i>" + text2 + "</i></color>";
				}
			}
		}

		private static GameObject Find(string sharedName)
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || string.IsNullOrEmpty(sharedName))
			{
				return null;
			}
			if ((Object)(object)instance != (Object)(object)_builtFor)
			{
				_builtFor = instance;
				ByName.Clear();
				foreach (GameObject item in instance.m_items)
				{
					ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
					if (!((Object)(object)val == (Object)null))
					{
						string name = val.m_itemData.m_shared.m_name;
						ByName[name] = (ByName.ContainsKey(name) ? null : item);
					}
				}
			}
			if (!ByName.TryGetValue(sharedName, out var value))
			{
				return null;
			}
			return value;
		}
	}
	internal class Info
	{
		internal string Title;

		internal string Source;

		internal string Prefab;

		internal int Id;

		internal Sprite Icon;

		internal readonly List<string> Lines = new List<string>();

		internal readonly List<string> More = new List<string>();

		internal readonly List<Sprite> Drops = new List<Sprite>();

		internal float Bar = -1f;

		internal Color BarColor;

		internal string BarText;

		internal List<Weakness.Group> Weaknesses;
	}
	internal static class Looking
	{
		private static readonly Color HealthColor = new Color(0.78f, 0.2f, 0.15f);

		private static readonly Color GrowColor = new Color(0.45f, 0.75f, 0.3f);

		private static readonly Color FuelColor = new Color(0.95f, 0.6f, 0.2f);

		private static readonly FieldRef<Plant, Status> PlantStatus = AccessTools.FieldRefAccess<Plant, Status>("m_status");

		private static readonly Func<Plant, double> SincePlanted = AccessTools.MethodDelegate<Func<Plant, double>>(AccessTools.Method(typeof(Plant), "TimeSincePlanted", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Plant, float> GrowTime = AccessTools.MethodDelegate<Func<Plant, float>>(AccessTools.Method(typeof(Plant), "GetGrowTime", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Tameable, int> Tameness = AccessTools.MethodDelegate<Func<Tameable, int>>(AccessTools.Method(typeof(Tameable), "GetTameness", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Dictionary<string, Sprite> Icons = new Dictionary<string, Sprite>();

		internal static GameObject Find(out Vector3 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			point = Vector3.zero;
			Player localPlayer = Player.m_localPlayer;
			Transform val = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform : null);
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = null;
			float num = float.MaxValue;
			float num2 = Mathf.Max(Plugin.CreatureRange.Value, Plugin.ObjectRange.Value);
			RaycastHit[] array = Physics.RaycastAll(val.position, val.forward, num2 + 8f, -1, (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val3 = array[i];
				if (((RaycastHit)(ref val3)).distance >= num || ((Component)((RaycastHit)(ref val3)).collider).transform.IsChildOf(((Component)localPlayer).transform))
				{
					continue;
				}
				num = ((RaycastHit)(ref val3)).distance;
				point = ((RaycastHit)(ref val3)).point;
				ZNetView val4 = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<ZNetView>();
				if ((Object)(object)val4 != (Object)null && IsStructure(((Component)val4).gameObject))
				{
					val4 = null;
				}
				Heightmap val5 = (((Object)(object)val4 == (Object)null) ? ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<Heightmap>() : null);
				object obj;
				if (!((Object)(object)val4 != (Object)null))
				{
					if (!((Object)(object)val5 != (Object)null))
					{
						Hoverable componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<Hoverable>();
						Component val6 = (Component)(object)((componentInParent is Component) ? componentInParent : null);
						obj = ((val6 != null) ? val6.gameObject : null);
					}
					else
					{
						obj = ((Component)val5).gameObject;
					}
				}
				else
				{
					obj = ((Component)val4).gameObject;
				}
				val2 = (GameObject)obj;
			}
			if ((Object)(object)val2 != (Object)null)
			{
				float num3 = (((Object)(object)val2.GetComponent<Character>() != (Object)null) ? Plugin.CreatureRange.Value : Plugin.ObjectRange.Value);
				if (Vector3.Distance(((Component)localPlayer).transform.position, point) > num3)
				{
					val2 = null;
				}
			}
			GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
			if ((Object)(object)hoverObject != (Object)null)
			{
				ZNetView componentInParent2 = hoverObject.GetComponentInParent<ZNetView>();
				if (!((Object)(object)componentInParent2 != (Object)null) || IsStructure(((Component)componentInParent2).gameObject))
				{
					return hoverObject;
				}
				return ((Component)componentInParent2).gameObject;
			}
			return val2;
		}

		private static bool IsStructure(GameObject go)
		{
			if (!((Object)(object)go.GetComponent<LocationProxy>() != (Object)null) && !((Object)(object)go.GetComponent<Location>() != (Object)null))
			{
				return (Object)(object)go.GetComponent<DungeonGenerator>() != (Object)null;
			}
			return true;
		}

		internal unsafe static Info Describe(GameObject go, Vector3 point)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)go == (Object)null)
			{
				return null;
			}
			if ((Object)(object)go.GetComponent<Ragdoll>() != (Object)null)
			{
				return null;
			}
			Info info = new Info
			{
				Prefab = PrefabName(go),
				Id = ((Object)go).GetInstanceID()
			};
			if ((Object)(object)go.GetComponent<Heightmap>() != (Object)null)
			{
				if (!Plugin.ShowTerrain.Value)
				{
					return null;
				}
				info.Title = "Ground";
				Biome val = Heightmap.FindBiome(point);
				string text = L("$biome_" + ((object)(*(Biome*)(&val))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant());
				info.Lines.Add((string.IsNullOrEmpty(text) || text.StartsWith("$") || text.StartsWith("[")) ? Pretty(((object)(*(Biome*)(&val))/*cast due to .constrained prefix*/).ToString()) : text);
				return info;
			}
			Character component = go.GetComponent<Character>();
			ItemDrop component2 = go.GetComponent<ItemDrop>();
			Piece component3 = go.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && component.IsBoss() && Plugin.BossBar.Value)
			{
				return null;
			}
			if ((Object)(object)component != (Object)null)
			{
				DescribeCharacter(component, info);
			}
			else if ((Object)(object)component2 != (Object)null)
			{
				DescribeItem(component2, info);
			}
			else
			{
				info.Title = HoverName(go, component3);
				if ((Object)(object)component3 != (Object)null)
				{
					info.Icon = component3.m_icon;
				}
				DescribeParts(go, info);
			}
			if (string.IsNullOrEmpty(info.Title))
			{
				info.Title = Pretty(info.Prefab);
			}
			if ((Object)(object)info.Icon == (Object)null)
			{
				info.Icon = DropIcon(go, info.Prefab);
			}
			if ((Object)(object)component2 == (Object)null && !(component is Player) && Plugin.ShowDrops.Value)
			{
				Extended.Drops(go, info);
			}
			info.Source = ModSource.Of(info.Prefab, go);
			return info;
		}

		private static void DescribeCharacter(Character c, Info info)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			Player val = (Player)(object)((c is Player) ? c : null);
			info.Title = (((Object)(object)val != (Object)null) ? val.GetPlayerName() : L(c.m_name));
			int num = c.GetLevel() - 1;
			if (num > 0)
			{
				info.Title = info.Title + " <color=#e8c77e>" + new string('*', num) + "</color>";
			}
			info.Bar = c.GetHealthPercentage();
			info.BarColor = HealthColor;
			info.BarText = $"{Mathf.CeilToInt(c.GetHealth())} / {Mathf.CeilToInt(c.GetMaxHealth())}";
			if ((Object)(object)val != (Object)null)
			{
				return;
			}
			if (c.IsBoss())
			{
				info.Lines.Add("<color=#ff6f55>Boss</color>");
			}
			if (Plugin.ShowWeaknesses.Value)
			{
				info.Weaknesses = Weakness.Groups(c.m_damageModifiers);
				Extended.Resistances(info.Weaknesses, info);
			}
			if (!Plugin.ShowCreatures.Value)
			{
				return;
			}
			Tameable component = ((Component)c).GetComponent<Tameable>();
			if (c.IsTamed())
			{
				string text = "<color=#9be07a>Tamed</color>";
				if ((Object)(object)component != (Object)null)
				{
					text += (component.IsHungry() ? ", hungry" : ", fed");
				}
				info.Lines.Add(text);
			}
			else if ((Object)(object)component != (Object)null && Tameness != null)
			{
				int num2 = Tameness(component);
				info.Lines.Add((num2 > 0) ? ($"Taming: {num2}%" + (component.IsHungry() ? ", hungry" : ", fed")) : "Can be tamed");
			}
			BaseAI baseAI = c.GetBaseAI();
			if ((Object)(object)baseAI != (Object)null && !c.IsTamed() && baseAI.IsAlerted())
			{
				info.Lines.Add("<color=#f0b04a>Alerted</color>");
			}
			Details.Creature(c, info);
		}

		private static void DescribeItem(ItemDrop drop, Info info)
		{
			ItemData itemData = drop.m_itemData;
			info.Title = L(itemData.m_shared.m_name) + ((itemData.m_stack > 1) ? $" x{itemData.m_stack}" : "");
			info.Icon = itemData.GetIcon();
			if (itemData.m_shared.m_maxQuality > 1)
			{
				info.Lines.Add($"Quality {itemData.m_quality}");
			}
			if (Plugin.ShowItems.Value)
			{
				Extended.Item(itemData, info);
			}
		}

		private static void DescribeParts(GameObject go, Info info)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = go.GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
			WearNTear component2 = go.GetComponent<WearNTear>();
			if ((Object)(object)component2 != (Object)null)
			{
				float num = (info.Bar = component2.GetHealthPercentage());
				info.BarColor = Color.Lerp(HealthColor, GrowColor, num);
				info.BarText = $"{num * 100f:0}%";
			}
			bool value = Plugin.ShowPlants.Value;
			bool value2 = Plugin.ShowProduction.Value;
			bool value3 = Plugin.ShowBase.Value;
			Plant component3 = go.GetComponent<Plant>();
			if (value && (Object)(object)component3 != (Object)null && SincePlanted != null && GrowTime != null)
			{
				float num2 = GrowTime(component3);
				double num3 = SincePlanted(component3);
				float num4 = (info.Bar = ((num2 > 0f) ? Mathf.Clamp01((float)(num3 / (double)num2)) : 0f));
				info.BarColor = GrowColor;
				info.BarText = $"{num4 * 100f:0}% grown";
				Status val2 = PlantStatus.Invoke(component3);
				if ((int)val2 != 0)
				{
					info.Lines.Add("<color=#ff6f55>Won't grow: " + PlantProblem(val2) + "</color>");
				}
				else if (num4 < 1f)
				{
					info.Lines.Add("Ready in " + Details.Time((double)num2 - num3));
				}
			}
			Pickable component4 = go.GetComponent<Pickable>();
			if ((Object)(object)component4 != (Object)null && (Object)(object)component4.m_itemPrefab != (Object)null)
			{
				ItemDrop component5 = component4.m_itemPrefab.GetComponent<ItemDrop>();
				info.Icon = ((component5 != null) ? component5.m_itemData.GetIcon() : null);
			}
			if (value && (Object)(object)component4 != (Object)null)
			{
				if (component4.CanBePicked())
				{
					info.Lines.Add("<color=#9be07a>Ready to pick</color>");
				}
				else
				{
					info.Lines.Add(Regrows(component4, val));
				}
			}
			Fireplace component6 = go.GetComponent<Fireplace>();
			if (value2 && (Object)(object)component6 != (Object)null && component6.m_infiniteFuel)
			{
				info.Lines.Add("Burns forever");
			}
			else if (value2 && (Object)(object)component6 != (Object)null && val != null)
			{
				float num5 = val.GetFloat(ZDOVars.s_fuel, 0f);
				info.Bar = ((component6.m_maxFuel > 0f) ? Mathf.Clamp01(num5 / component6.m_maxFuel) : 0f);
				info.BarColor = FuelColor;
				info.BarText = $"Fuel {Mathf.CeilToInt(num5)} / {component6.m_maxFuel:0}";
			}
			Container component7 = go.GetComponent<Container>();
			if (value3 && (Object)(object)component7 != (Object)null && component7.GetInventory() != null)
			{
				Inventory inventory = component7.GetInventory();
				int count = inventory.GetAllItems().Count;
				int num6 = inventory.GetWidth() * inventory.GetHeight();
				info.Lines.Add((count == 0) ? "Empty" : $"{count} / {num6} slots used");
			}
			CraftingStation component8 = go.GetComponent<CraftingStation>();
			if (value3 && (Object)(object)component8 != (Object)null)
			{
				info.Lines.Add($"Level {component8.GetLevel(true)}");
			}
			if (value2)
			{
				Details.Production(go, val, info);
			}
			if (value3)
			{
				Details.Base(go, val, info);
			}
			if (Plugin.ShowTool.Value)
			{
				Extended.ToolNeed(go, info);
			}
			if (!((Object)(object)component2 == (Object)null) || val == null)
			{
				return;
			}
			float num7 = MaxHealth(go);
			if (num7 > 0f)
			{
				float num8 = val.GetFloat(ZDOVars.s_health, num7);
				if (num8 < num7)
				{
					info.Bar = Mathf.Clamp01(num8 / num7);
					info.BarColor = HealthColor;
					info.BarText = $"{Mathf.CeilToInt(num8)} / {num7:0}";
				}
			}
		}

		private static string Regrows(Pickable pickable, ZDO zdo)
		{
			if (pickable.m_respawnTimeMinutes <= 0f || zdo == null || (Object)(object)ZNet.instance == (Object)null)
			{
				return "Picked";
			}
			long num = zdo.GetLong(ZDOVars.s_pickedTime, 0L);
			if (num <= 1)
			{
				return "Picked";
			}
			double num2 = (double)pickable.m_respawnTimeMinutes * 60.0 - (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds;
			if (!(num2 > 0.0))
			{
				return "Regrowing any moment";
			}
			return "Regrows in " + Details.Time(num2);
		}

		private static float MaxHealth(GameObject go)
		{
			TreeBase component = go.GetComponent<TreeBase>();
			if ((Object)(object)component != (Object)null)
			{
				return component.m_health;
			}
			TreeLog component2 = go.GetComponent<TreeLog>();
			if ((Object)(object)component2 != (Object)null)
			{
				return component2.m_health;
			}
			MineRock component3 = go.GetComponent<MineRock>();
			if ((Object)(object)component3 != (Object)null)
			{
				return component3.m_health;
			}
			Destructible component4 = go.GetComponent<Destructible>();
			if ((Object)(object)component4 != (Object)null)
			{
				return component4.m_health;
			}
			return 0f;
		}

		private unsafe static string PlantProblem(Status status)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			return (status - 1) switch
			{
				0 => "needs sun", 
				1 => "not enough space", 
				2 => "wrong biome", 
				3 => "needs cultivated ground", 
				4 => "nothing to grow on", 
				5 => "too hot", 
				6 => "too cold", 
				_ => ((object)(*(Status*)(&status))/*cast due to .constrained prefix*/).ToString(), 
			};
		}

		private static string HoverName(GameObject go, Piece piece)
		{
			string text = NameOf(go.GetComponent<Hoverable>());
			if (text != null)
			{
				return text;
			}
			string text2 = (((Object)(object)piece != (Object)null) ? L(piece.m_name) : null);
			if (!string.IsNullOrEmpty(text2) && !text2.StartsWith("$"))
			{
				return text2;
			}
			Hoverable[] componentsInChildren = go.GetComponentsInChildren<Hoverable>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				string text3 = NameOf(componentsInChildren[i]);
				if (text3 != null)
				{
					return text3;
				}
			}
			return null;
		}

		private static string NameOf(Hoverable hoverable)
		{
			if (hoverable == null)
			{
				return null;
			}
			string text;
			try
			{
				text = L(hoverable.GetHoverName());
			}
			catch (Exception)
			{
				return null;
			}
			if (string.IsNullOrEmpty(text) || text.StartsWith("$"))
			{
				return null;
			}
			return Ui.StripColor(text);
		}

		private static string PrefabName(GameObject go)
		{
			ZNetView component = go.GetComponent<ZNetView>();
			ZDO val = ((component != null) ? component.GetZDO() : null);
			GameObject val2 = ((val != null && (Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(val.GetPrefab()) : null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return Utils.GetPrefabName(go);
			}
			return ((Object)val2).name;
		}

		private static Sprite DropIcon(GameObject go, string prefab)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Invalid comparison between Unknown and I4
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Invalid comparison between Unknown and I4
			if (Icons.TryGetValue(prefab, out var value))
			{
				return value;
			}
			Sprite val = null;
			CharacterDrop component = go.GetComponent<CharacterDrop>();
			if ((Object)(object)component != (Object)null)
			{
				foreach (Drop drop in component.m_drops)
				{
					ItemData val2 = ((!((Object)(object)drop.m_prefab != (Object)null)) ? null : drop.m_prefab.GetComponent<ItemDrop>()?.m_itemData);
					if (val2 != null)
					{
						if ((Object)(object)val == (Object)null || (int)val2.m_shared.m_itemType == 13)
						{
							val = val2.GetIcon();
						}
						if ((int)val2.m_shared.m_itemType == 13)
						{
							break;
						}
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = FirstDrop(go.GetComponent<TreeBase>()?.m_dropWhenDestroyed) ?? FirstDrop(go.GetComponent<TreeLog>()?.m_dropWhenDestroyed) ?? FirstDrop(go.GetComponent<MineRock>()?.m_dropItems) ?? FirstDrop(go.GetComponent<MineRock5>()?.m_dropItems) ?? FirstDrop(go.GetComponent<DropOnDestroyed>()?.m_dropWhenDestroyed);
			}
			Icons[prefab] = val;
			return val;
		}

		private static Sprite FirstDrop(DropTable table)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (table?.m_drops == null)
			{
				return null;
			}
			foreach (DropData drop in table.m_drops)
			{
				ItemData val = ((!((Object)(object)drop.m_item != (Object)null)) ? null : drop.m_item.GetComponent<ItemDrop>()?.m_itemData);
				if (val != null)
				{
					return val.GetIcon();
				}
			}
			return null;
		}

		internal static string L(string token)
		{
			if (!string.IsNullOrEmpty(token) && Localization.instance != null)
			{
				return Localization.instance.Localize(token);
			}
			return token;
		}

		private static string Pretty(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return "?";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < prefab.Length; i++)
			{
				char c = prefab[i];
				if (c == '_')
				{
					c = ' ';
				}
				else if (i > 0 && char.IsUpper(c) && char.IsLower(prefab[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append((i > 0 && char.IsUpper(c)) ? char.ToLowerInvariant(c) : c);
			}
			string text = stringBuilder.ToString().Replace("  ", " ").Trim();
			if (text.Length <= 0)
			{
				return "?";
			}
			return char.ToUpperInvariant(text[0]) + text.Substring(1);
		}
	}
	internal static class ModSource
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class VanillaSnapshotPatch
		{
			[HarmonyPriority(int.MaxValue)]
			private static void Prefix(ZNetScene __instance)
			{
				_scene = __instance;
				VanillaPrefabs.Clear();
				Cache.Clear();
				foreach (GameObject prefab in __instance.m_prefabs)
				{
					if ((Object)(object)prefab != (Object)null)
					{
						VanillaPrefabs.Add(((Object)prefab).name);
					}
				}
				foreach (GameObject nonNetViewPrefab in __instance.m_nonNetViewPrefabs)
				{
					if ((Object)(object)nonNetViewPrefab != (Object)null)
					{
						VanillaPrefabs.Add(((Object)nonNetViewPrefab).name);
					}
				}
				_snapshotTaken = true;
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDBFirstPatch
		{
			[HarmonyPriority(int.MaxValue)]
			private static void Prefix(ObjectDB __instance)
			{
				_objectDB = __instance;
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "Awake")]
		private static class WrapPatchesPatch
		{
			private static bool _done;

			private static void Postfix()
			{
				//IL_001a: 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)
				//IL_003c: Expected O, but got Unknown
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Expected O, but got Unknown
				//IL_0075: Expected O, but got Unknown
				if (!_done && !HasJotunn)
				{
					_done = true;
					Harmony val = new Harmony("Hugin.ModSource");
					Wrap(val, AccessTools.Method(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null), scene: true);
					Wrap(val, AccessTools.Method(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null), scene: false);
					Wrap(val, AccessTools.Method(typeof(ObjectDB), "CopyOtherDB", (Type[])null, (Type[])null), scene: false);
				}
			}
		}

		[HarmonyPatch]
		private static class BundlePatch
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				return from m in typeof(AssetBundle).GetMethods(BindingFlags.Static | BindingFlags.Public)
					where (m.Name == "LoadFromFile" || m.Name == "LoadFromMemory" || m.Name == "LoadFromStream") && m.ReturnType == typeof(AssetBundle) && m.GetMethodBody() != null
					select m;
			}

			private static void Postfix(AssetBundle __result)
			{
				if ((Object)(object)__result == (Object)null)
				{
					return;
				}
				try
				{
					string text = Caller();
					if (text == null)
					{
						return;
					}
					string[] allAssetNames = __result.GetAllAssetNames();
					for (int i = 0; i < allAssetNames.Length; i++)
					{
						string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(allAssetNames[i]);
						if (!BundleAsset.ContainsKey(fileNameWithoutExtension))
						{
							BundleAsset[fileNameWithoutExtension] = text;
						}
					}
				}
				catch (Exception)
				{
				}
			}

			private static string Caller()
			{
				StackFrame[] array = new StackTrace(2, fNeedFileInfo: false).GetFrames() ?? new StackFrame[0];
				for (int i = 0; i < array.Length; i++)
				{
					Assembly assembly = array[i].GetMethod()?.DeclaringType?.Assembly;
					if (!(assembly == null) && !(assembly == typeof(ModSource).Assembly))
					{
						string text = PluginOf(assembly);
						if (text != null)
						{
							return text;
						}
					}
				}
				return null;
			}
		}

		internal const string JotunnGuid = "com.jotunn.jotunn";

		internal const string Vanilla = "Valheim";

		internal const string UnknownMod = "a mod";

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

		private static readonly Dictionary<string, string> AddedBy = new Dictionary<string, string>();

		private static readonly Dictionary<string, string> BundleAsset = new Dictionary<string, string>();

		private static readonly Dictionary<string, string> Cache = new Dictionary<string, string>();

		private static Dictionary<Assembly, string> _plugins;

		private static int _pluginCount = -1;

		private static MethodInfo _jotunnGetPrefab;

		private static PropertyInfo _jotunnSourceMod;

		private static bool _snapshotTaken;

		private static ZNetScene _scene;

		private static ObjectDB _objectDB;

		private static readonly Stack<int> Counts = new Stack<int>();

		internal static bool HasJotunn => _jotunnGetPrefab != null;

		internal static void Init()
		{
			try
			{
				Type type = Type.GetType("Jotunn.Utils.ModQuery, Jotunn");
				if (!(type == null))
				{
					type.GetMethod("Enable", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null);
					_jotunnGetPrefab = type.GetMethod("GetPrefab", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
					_jotunnSourceMod = Type.GetType("Jotunn.Utils.IModPrefab, Jotunn")?.GetProperty("SourceMod");
					Plugin.Log.LogInfo((object)"Jötunn found: using its ModQuery to name the mods things come from.");
				}
			}
			catch (Exception ex)
			{
				_jotunnGetPrefab = null;
				Plugin.Log.LogWarning((object)("Couldn't use Jötunn's ModQuery: " + ex.Message));
			}
		}

		internal static string Of(string prefab, GameObject target)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return null;
			}
			if (Cache.TryGetValue(prefab, out var value))
			{
				return value;
			}
			string text = Find(prefab, target);
			if (_snapshotTaken)
			{
				Cache[prefab] = text;
			}
			return text;
		}

		private static string Find(string prefab, GameObject target)
		{
			if (!_snapshotTaken)
			{
				return null;
			}
			if (VanillaPrefabs.Contains(prefab))
			{
				return "Valheim";
			}
			string text = FromJotunn(prefab);
			if (text != null)
			{
				return text;
			}
			if (AddedBy.TryGetValue(prefab, out var value))
			{
				return value;
			}
			if (BundleAsset.TryGetValue(prefab.ToLowerInvariant(), out var value2))
			{
				return value2;
			}
			string text2 = FromScripts(target);
			if (text2 != null)
			{
				return text2;
			}
			if ((Object)(object)target != (Object)null && !Registered(target))
			{
				return null;
			}
			return "a mod";
		}

		private static bool Registered(GameObject target)
		{
			ZNetView componentInParent = target.GetComponentInParent<ZNetView>();
			ZDO val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.GetZDO() : null);
			if (val == null)
			{
				return (Object)(object)componentInParent != (Object)null;
			}
			if (!((Object)(object)ZNetScene.instance == (Object)null))
			{
				return (Object)(object)ZNetScene.instance.GetPrefab(val.GetPrefab()) != (Object)null;
			}
			return true;
		}

		private static string FromJotunn(string prefab)
		{
			if (_jotunnGetPrefab == null)
			{
				return null;
			}
			try
			{
				object obj = _jotunnGetPrefab.Invoke(null, new object[1] { prefab });
				object obj2 = (object)((obj != null) ? /*isinst with value type is only supported in some contexts*/: null);
				return (obj2 != null) ? ((BepInPlugin)obj2).Name : null;
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static string FromScripts(GameObject target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return null;
			}
			MonoBehaviour[] componentsInChildren = target.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string text = PluginOf(((object)val).GetType().Assembly);
					if (text != null && text != "Hugin")
					{
						return text;
					}
				}
			}
			return null;
		}

		internal static string PluginOf(Assembly assembly)
		{
			if (_plugins == null || _pluginCount != Chainloader.PluginInfos.Count)
			{
				_pluginCount = Chainloader.PluginInfos.Count;
				_plugins = new Dictionary<Assembly, string>();
				Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
				foreach (PluginInfo value3 in Chainloader.PluginInfos.Values)
				{
					if (!string.IsNullOrEmpty(value3.Location) && !dictionary.ContainsKey(value3.Location))
					{
						dictionary[value3.Location] = value3.Metadata.Name;
					}
				}
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly2 in assemblies)
				{
					string text;
					try
					{
						text = (assembly2.IsDynamic ? null : assembly2.Location);
					}
					catch (Exception)
					{
						text = null;
					}
					if (!string.IsNullOrEmpty(text) && dictionary.TryGetValue(text, out var value))
					{
						_plugins[assembly2] = value;
					}
				}
			}
			if (!(assembly != null) || !_plugins.TryGetValue(assembly, out var value2))
			{
				return null;
			}
			return value2;
		}

		private static void Wrap(Harmony harmony, MethodBase target, bool scene)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			Patches val = ((target != null) ? Harmony.GetPatchInfo(target) : null);
			if (val == null)
			{
				return;
			}
			HarmonyMethod val2 = new HarmonyMethod(AccessTools.Method(typeof(ModSource), scene ? "BeforeScene" : "BeforeDB", (Type[])null, (Type[])null));
			HarmonyMethod val3 = new HarmonyMethod(AccessTools.Method(typeof(ModSource), scene ? "AfterScene" : "AfterDB", (Type[])null, (Type[])null));
			foreach (Patch item in val.Prefixes.Concat(val.Postfixes))
			{
				MethodInfo patchMethod = item.PatchMethod;
				if (!(patchMethod == null) && !(patchMethod.DeclaringType?.Assembly == typeof(ModSource).Assembly) && PluginOf(patchMethod.DeclaringType?.Assembly) != null)
				{
					try
					{
						harmony.Patch((MethodBase)patchMethod, val2, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
					catch (Exception ex)
					{
						Plugin.Log.LogDebug((object)("Couldn't watch " + patchMethod.DeclaringType?.Name + "." + patchMethod.Name + ": " + ex.Message));
					}
				}
			}
		}

		private static void BeforeScene()
		{
			Counts.Push(((Object)(object)_scene != (Object)null) ? _scene.m_prefabs.Count : 0);
		}

		private static void AfterScene(MethodBase __originalMethod)
		{
			int num = ((Counts.Count > 0) ? Counts.Pop() : 0);
			if (!((Object)(object)_scene == (Object)null))
			{
				Claim(_scene.m_prefabs, num, __originalMethod);
			}
		}

		private static void BeforeDB()
		{
			Counts.Push(((Object)(object)_objectDB != (Object)null) ? _objectDB.m_items.Count : 0);
		}

		private static void AfterDB(MethodBase __originalMethod)
		{
			int num = ((Counts.Count > 0) ? Counts.Pop() : 0);
			if (!((Object)(object)_objectDB == (Object)null))
			{
				Claim(_objectDB.m_items, num, __originalMethod);
			}
		}

		private static void Claim(List<GameObject> list, int from, MethodBase patch)
		{
			string text = PluginOf(patch?.DeclaringType?.Assembly);
			if (text == null)
			{
				return;
			}
			for (int i = from; i < list.Count; i++)
			{
				if ((Object)(object)list[i] != (Object)null && !AddedBy.ContainsKey(((Object)list[i]).name))
				{
					AddedBy[((Object)list[i]).name] = text;
				}
			}
		}
	}
	internal class Panel : MonoBehaviour
	{
		private const float Pad = 10f;

		private const float IconSize = 40f;

		private const float MinW = 220f;

		private const float MaxW = 480f;

		private const float TitleH = 24f;

		private const float LineH = 19f;

		private const float BarH = 14f;

		private const float DropSize = 24f;

		private const float Edge = 24f;

		private const float Interval = 0.1f;

		private const float Linger = 0.3f;

		private const float FadeSpeed = 7f;

		private const float SizeSpeed = 14f;

		private const float ContentFade = 9f;

		private const float BarSpeed = 6f;

		private const float Slide = 10f;

		internal const string SourceColor = "#8ab4f8";

		private Info _info;

		private float _nextUpdate;

		private float _lostAt;

		private float _alpha;

		private float _w;

		private float _h;

		private float _contentAlpha;

		private float _bar = -1f;

		private int _shownId;

		private GUIStyle _source;

		private GUIStyle _title;

		private static readonly List<string> NoLines = new List<string>();

		private GUIStyle SourceStyle
		{
			get
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Expected O, but got Unknown
				//IL_0023: Expected O, but got Unknown
				GUIStyle obj = _source;
				if (obj == null)
				{
					GUIStyle val = new GUIStyle(Ui.Small)
					{
						fontStyle = (FontStyle)2
					};
					GUIStyle val2 = val;
					_source = val;
					obj = val2;
				}
				return obj;
			}
		}

		private GUIStyle TitleStyle
		{
			get
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Expected O, but got Unknown
				//IL_0023: Expected O, but got Unknown
				GUIStyle obj = _title;
				if (obj == null)
				{
					GUIStyle val = new GUIStyle(Ui.Text)
					{
						fontStyle = (FontStyle)1
					};
					GUIStyle val2 = val;
					_title = val;
					obj = val2;
				}
				return obj;
			}
		}

		private void Update()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.unscaledTime < _nextUpdate))
			{
				_nextUpdate = Time.unscaledTime + 0.1f;
				Vector3 point;
				Info info = (Hidden() ? null : Looking.Describe(Looking.Find(out point), point));
				if (info != null)
				{
					_info = info;
					_lostAt = -1f;
				}
				else if (_info != null && _lostAt < 0f)
				{
					_lostAt = Time.unscaledTime;
				}
			}
		}

		private static bool Hidden()
		{
			if (!ScreenHidden())
			{
				if (Plugin.HideWhileBuilding.Value)
				{
					return ((Character)Player.m_localPlayer).InPlaceMode();
				}
				return false;
			}
			return true;
		}

		internal static bool ScreenHidden()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Plugin.ShowPanel.Value || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || Hud.IsUserHidden())
			{
				return true;
			}
			if (InventoryGui.IsVisible() || Minimap.IsOpen() || Menu.IsVisible() || StoreGui.IsVisible() || TextInput.IsVisible())
			{
				return true;
			}
			if (!Console.IsVisible())
			{
				return GameCamera.InFreeFly();
			}
			return true;
		}

		private void OnGUI()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type != 7 || _info == null)
			{
				return;
			}
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			bool flag = _lostAt < 0f || Time.unscaledTime - _lostAt < 0.3f;
			_alpha = Mathf.MoveTowards(_alpha, flag ? 1f : 0f, unscaledDeltaTime * 7f);
			if (_alpha <= 0f)
			{
				_info = null;
				_w = (_h = 0f);
				return;
			}
			if (_info.Id != _shownId)
			{
				_shownId = _info.Id;
				Raven.Curious();
				_contentAlpha = 0f;
				_bar = _info.Bar;
			}
			_contentAlpha = Mathf.MoveTowards(_contentAlpha, 1f, unscaledDeltaTime * 9f);
			_bar = ((_info.Bar < 0f || _bar < 0f) ? _info.Bar : Mathf.Lerp(_bar, _info.Bar, 1f - Mathf.Exp(-6f * unscaledDeltaTime)));
			GUISkin skin = GUI.skin;
			Color color = GUI.color;
			GUI.skin = Ui.Skin;
			float width;
			float height;
			Matrix4x4 matrix = Ui.BeginScaled(out width, out height);
			try
			{
				GUI.color = new Color(1f, 1f, 1f, _alpha);
				Draw(width);
			}
			finally
			{
				GUI.matrix = matrix;
				GUI.skin = skin;
				GUI.color = color;
			}
		}

		private void Draw(float screenW)
		{
			//IL_001a: 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)
			//IL_0023: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0635: Unknown result type (might be due to invalid IL or missing references)
			//IL_063c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0643: Unknown result type (might be due to invalid IL or missing references)
			//IL_0648: Unknown result type (might be due to invalid IL or missing references)
			//IL_064a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0651: Unknown result type (might be due to invalid IL or missing references)
			//IL_0658: Unknown result type (might be due to invalid IL or missing references)
			//IL_065f: Unknown result type (might be due to invalid IL or missing references)
			//IL_066d: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0804: Unknown result type (might be due to invalid IL or missing references)
			//IL_0728: Unknown result type (might be due to invalid IL or missing references)
			//IL_0763: Unknown result type (might be due to invalid IL or missing references)
			//IL_0843: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a20: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a52: Unknown result type (might be due to invalid IL or missing references)
			//IL_0950: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a99: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a8c: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_09cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ad1: Unknown result type (might be due to invalid IL or missing references)
			Info info = _info;
			bool value = Plugin.Compact.Value;
			int num;
			if (!value)
			{
				KeyboardShortcut value2 = Plugin.MoreKey.Value;
				if ((int)((KeyboardShortcut)(ref value2)).MainKey != 0)
				{
					value2 = Plugin.MoreKey.Value;
					num = (((KeyboardShortcut)(ref value2)).IsPressed() ? 1 : 0);
					goto IL_0040;
				}
			}
			num = 0;
			goto IL_0040;
			IL_0040:
			bool flag = (byte)num != 0;
			bool num2 = !value && (info.More.Count > 0 || info.Drops.Count > 0);
			string text = SourceLine(info);
			string text2 = ((!value && (Plugin.ShowPrefab.Value || flag)) ? ("<color=#b9ad98>" + info.Prefab + "</color>") : null);
			List<string> list = (value ? NoLines : info.Lines);
			List<string> list2 = (flag ? info.More : NoLines);
			bool flag2 = flag && info.Drops.Count > 0;
			bool flag3 = info.Bar >= 0f && !value;
			List<Weakness.Group> list3 = ((!value && info.Weaknesses != null && info.Weaknesses.Count > 0 && (flag || Plugin.WeaknessIconsAlways.Value)) ? info.Weaknesses : null);
			string text3 = ((num2 && !flag && Plugin.ShowHint.Value) ? Ui.KeyName(Plugin.MoreKey.Value) : null);
			float num3 = ((text3 != null) ? (Ui.KeycapWidth(text3) + 8f) : 0f);
			bool flag4 = Plugin.ShowRaven.Value && Raven.Available;
			float num4 = (value ? 72f : 96f);
			float num5 = num4 * 0.625f;
			float num6 = num5 * 0.64f;
			float num7 = (flag4 ? Mathf.Max(0f, num5 * 0.32f - 10f + 4f) : 0f);
			float num8 = (value ? 28f : 40f);
			float num9 = (((Object)(object)info.Icon != (Object)null) ? (10f + num8 + 12f) : 12f);
			float num10 = Ui.LineWidth(info.Title, TitleStyle) + 4f;
			foreach (string item in list)
			{
				num10 = Mathf.Max(num10, Ui.LineWidth(item, Ui.Small));
			}
			foreach (string item2 in list2)
			{
				num10 = Mathf.Max(num10, Ui.LineWidth(item2, Ui.Small));
			}
			if (text != null || text3 != null)
			{
				num10 = Mathf.Max(num10, ((text != null) ? Ui.LineWidth(text, SourceStyle) : 0f) + num3);
			}
			if (text2 != null)
			{
				num10 = Mathf.Max(num10, Ui.LineWidth(text2, Ui.Small));
			}
			if (flag3)
			{
				num10 = Mathf.Max(num10, 170f);
			}
			List<List<Weakness.Group>> list4 = ((list3 != null) ? Weakness.Rows(list3, 16f, Mathf.Max(num10, 200f)) : null);
			if (list4 != null)
			{
				foreach (List<Weakness.Group> item3 in list4)
				{
					num10 = Mathf.Max(num10, Weakness.Width(item3, 16f));
				}
			}
			if (flag2)
			{
				num10 = Mathf.Max(num10, (float)Mathf.Min(info.Drops.Count, 8) * 28f);
			}
			float num11 = Mathf.Clamp(Mathf.Ceil((num9 + num10 + 10f + 4f) / 16f) * 16f, value ? 140f : 220f, 480f);
			float num12 = num7 + 10f + 24f + (flag3 ? 20f : 0f) + ((list4 != null) ? ((float)list4.Count * 19f + 2f) : 0f) + (float)list.Count * 19f + ((list2.Count > 0) ? (4f + (float)list2.Count * 19f) : 0f) + (flag2 ? 30f : 0f) + ((text2 != null) ? 19f : 0f) + ((text != null || text3 != null) ? 21f : 0f) + 10f;
			num12 = Mathf.Max(num12, ((Object)(object)info.Icon != (Object)null) ? (num7 + num8 + 20f) : 0f);
			float num13 = 1f - Mathf.Exp(-14f * Time.unscaledDeltaTime);
			_w = ((_w <= 0f) ? num11 : Mathf.Lerp(_w, num11, num13));
			_h = ((_h <= 0f) ? num12 : Mathf.Lerp(_h, num12, num13));
			if (Mathf.Abs(_w - num11) < 0.5f)
			{
				_w = num11;
			}
			if (Mathf.Abs(_h - num12) < 0.5f)
			{
				_h = num12;
			}
			Anchor value3 = Plugin.Position.Value;
			float num14 = (flag4 ? num6 : 0f);
			float num15 = Mathf.Clamp(value3 switch
			{
				Anchor.Right => screenW - 24f - _w, 
				Anchor.Left => 24f, 
				_ => (screenW - _w) * 0.5f, 
			} + Plugin.OffsetX.Value, 0f, Mathf.Max(0f, screenW - _w));
			float num16 = Plugin.OffsetY.Value + num14;
			if (BossBar.Find(out var bar, out var _) && num15 < ((Rect)(ref bar)).xMax + 8f && num15 + _w > ((Rect)(ref bar)).x - 8f)
			{
				num16 = Mathf.Max(num16, BossBar.Bottom() + num14);
			}
			num16 -= (1f - Mathf.SmoothStep(0f, 1f, _alpha)) * 10f;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(Mathf.Round(num15), num16, _w, _h);
			Ui.Panel(val);
			GUI.BeginGroup(val);
			Color color = GUI.color;
			GUI.color = new Color(color.r, color.g, color.b, color.a * _contentAlpha);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(value3 switch
			{
				Anchor.Right => _w - num11, 
				Anchor.Left => 0f, 
				_ => (_w - num11) * 0.5f, 
			}, num7, num11, num12 - num7);
			if ((Object)(object)info.Icon != (Object)null)
			{
				Rect r = default(Rect);
				((Rect)(ref r))..ctor(((Rect)(ref val2)).x + 10f, ((Rect)(ref val2)).y + 10f, num8 + 4f, num8 + 4f);
				if (!value)
				{
					((Rect)(ref r)).y = ((Rect)(ref val2)).y + Mathf.Min(10f, (((Rect)(ref val2)).height - ((Rect)(ref r)).height) * 0.5f);
				}
				Ui.Slot(r);
				Ui.Icon(new Rect(((Rect)(ref r)).x + 3f, ((Rect)(ref r)).y + 3f, ((Rect)(ref r)).width - 6f, ((Rect)(ref r)).height - 6f), info.Icon);
			}
			float num17 = ((Rect)(ref val2)).x + num9;
			float num18 = ((Rect)(ref val2)).xMax - 10f - num17;
			float num19 = ((Rect)(ref val2)).y + 10f - 2f;
			Ui.Label(new Rect(num17, num19, num18, 24f), "<b>" + info.Title + "</b>", Ui.Text);
			num19 += 24f;
			if (flag3)
			{
				Rect r2 = default(Rect);
				((Rect)(ref r2))..ctor(num17, num19 + 2f, num18, 14f);
				Ui.Bar(r2, _bar, info.BarColor);
				if (!string.IsNullOrEmpty(info.BarText))
				{
					Ui.Label(new Rect(((Rect)(ref r2)).x, ((Rect)(ref r2)).y - 3f, ((Rect)(ref r2)).width, ((Rect)(ref r2)).height + 6f), info.BarText, Ui.SmallCenter);
				}
				num19 += 20f;
			}
			if (list4 != null)
			{
				foreach (List<Weakness.Group> item4 in list4)
				{
					Weakness.Draw(item4, num17, num19 + 1f, 16f);
					num19 += 19f;
				}
				num19 += 2f;
			}
			foreach (string item5 in list)
			{
				Ui.Label(new Rect(num17, num19, num18, 19f), item5, Ui.Small);
				num19 += 19f;
			}
			if (list2.Count > 0)
			{
				Ui.Divider(num17, num19 + 1f, num18);
				num19 += 4f;
				foreach (string item6 in list2)
				{
					Ui.Label(new Rect(num17, num19, num18, 19f), item6, Ui.Small);
					num19 += 19f;
				}
			}
			if (flag2)
			{
				float num20 = num17;
				for (int i = 0; i < info.Drops.Count && i < 8; i++)
				{
					Ui.Slot(new Rect(num20, num19 + 2f, 24f, 24f));
					Ui.Icon(new Rect(num20 + 3f, num19 + 5f, 18f, 18f), info.Drops[i]);
					num20 += 28f;
				}
				num19 += 30f;
			}
			if (text2 != null)
			{
				Ui.Label(new Rect(num17, num19, num18, 19f), text2, Ui.Small);
				num19 += 19f;
			}
			if (text != null)
			{
				Ui.Label(new Rect(num17, num19 + 2f, num18 - num3, 19f), text, SourceStyle);
			}
			if (text3 != null)
			{
				Ui.Keycap(new Rect(((Rect)(ref val2)).xMax - 10f - num3 + 8f, num19 + 2f, num3, 18f), text3);
			}
			GUI.color = color;
			GUI.EndGroup();
			if (flag4)
			{
				Raven.Draw(new Rect(Mathf.Round(((Rect)(ref val)).center.x - num4 * 0.5f), ((Rect)(ref val)).y - num6, num4, num5));
			}
		}

		private static string SourceLine(Info info)
		{
			if (string.IsNullOrEmpty(info.Source))
			{
				return null;
			}
			if (info.Source == "Valheim")
			{
				if (!Plugin.ShowVanilla.Value)
				{
					return null;
				}
				return "<color=#8ab4f8>Valheim</color>";
			}
			if (info.Source == "a mod")
			{
				return "<color=#8ab4f8>Added by a mod</color>";
			}
			return "<color=#8ab4f8>" + info.Source + "</color>";
		}
	}
	internal enum Anchor
	{
		Left,
		Centre,
		Right
	}
	[BepInPlugin("Hugin", "Hugin, What the Hel Is That?", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("valheim.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private const string Guid = "Hugin";

		internal static ConfigEntry<bool> ShowPanel;

		internal static ConfigEntry<bool> ShowVanilla;

		internal static ConfigEntry<bool> ShowPrefab;

		internal static ConfigEntry<bool> ShowTerrain;

		internal static ConfigEntry<bool> HideWhileBuilding;

		internal static ConfigEntry<bool> Compact;

		internal static ConfigEntry<bool> ShowHint;

		internal static ConfigEntry<bool> ItemTooltips;

		internal static ConfigEntry<bool> BossBar;

		internal static ConfigEntry<bool> ShowRaven;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<KeyboardShortcut> MoreKey;

		internal static ConfigEntry<float> UiScale;

		internal static ConfigEntry<float> CreatureRange;

		internal static ConfigEntry<float> ObjectRange;

		internal static ConfigEntry<float> OffsetY;

		internal static ConfigEntry<float> OffsetX;

		internal static ConfigEntry<Anchor> Position;

		internal static ConfigEntry<bool> ShowCreatures;

		internal static ConfigEntry<bool> ShowPlants;

		internal static ConfigEntry<bool> ShowProduction;

		internal static ConfigEntry<bool> ShowBase;

		internal static ConfigEntry<bool> ShowTool;

		internal static ConfigEntry<bool> ShowItems;

		internal static ConfigEntry<bool> ShowWeaknesses;

		internal static ConfigEntry<bool> ShowDrops;

		internal static ConfigEntry<bool> WeaknessIconsAlways;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private GameObject _panelObject;

		private void Awake()
		{
			//IL_0045: 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_0091: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Expected O, but got Unknown
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ShowPanel = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show panel", true, "Show the panel for what you're looking at.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Toggle key", new KeyboardShortcut((KeyCode)277, Array.Empty<KeyCode>()), "Shows or hides the panel.");
			UiScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "UI scale", 1f, new ConfigDescription("Size of the panel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>()));
			Position = ((BaseUnityPlugin)this).Config.Bind<Anchor>("General", "Position", Anchor.Centre, "Which side of the top of the screen the panel sits on.");
			OffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Sideways offset", 0f, new ConfigDescription("Moves the panel left (negative) or right (positive) from its position, e.g. to make room for a compass.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1200f, 1200f), Array.Empty<object>()));
			OffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Distance from the top", 12f, new ConfigDescription("How far below the top of the screen the panel sits.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
			CreatureRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range for creatures", 20f, new ConfigDescription("How far away creatures and players are still shown, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 100f), Array.Empty<object>()));
			ObjectRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range for objects", 6f, new ConfigDescription("How far away everything else (rocks, trees, pieces, plants...) is still shown, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 100f), Array.Empty<object>()));
			MoreKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "More details key", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Hold to see more: weaknesses, drops, an item's weight and value, the prefab name.");
			ShowHint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show the key hint", true, "Show the \"more details\" key in the corner of the panel when there's more to see.");
			ShowRaven = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Hugin", true, "Hugin the raven peeks over the top of the panel, as if he's the one telling you.");
			Compact = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Compact", false, "Only the icon, the name and the mod it comes from: no bars or details.");
			ShowVanilla = ((BaseUnityPlugin)this).Config.Bind<bool>("Details", "Name the game for vanilla things", true, "Show \"Valheim\" as the source of the game's own things. Off: only modded things get a source line.");
			WeaknessIconsAlways = ((BaseUnityPlugin)this).Config.Bind<bool>("Details", "Weakness icons always shown", true, "Show a creature's weakness icons all the time. Off: only while holding the more key, for the smallest panel.");
			BossBar = ((BaseUnityPlugin)this).Config.Bind<bool>("Details", "Bosses use the boss bar", true, "No panel for bosses, since the game's boss bar is in the same spot; their weaknesses go under that bar as small icons instead.");
			ItemTooltips = ((BaseUnityPlugin)this).Config.Bind<bool>("Details", "Mod name on item tooltips", true, "Add the mod an item comes from to the end of its tooltip, in the inventory, chests and crafting.");
			ShowCreatures = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Creatures", true, "Behaviour, alerted, taming, tame names, saddles and breeding.");
			ShowPlants = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Plants and pickables", true, "Growth, why a plant won't grow, ready to pick, when bushes grow back.");
			ShowProduction = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Production", true, "Fires' fuel, smelters, kilns, fermenters, cooking stations and beehives.");
			ShowBase = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Base", true, "Chests, crafting station levels, wards, beds, graves, portal tags and stands.");
			ShowTool = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Tool needed", true, "Which tool a rock or tree needs (in red when you carry nothing that can break it).");
			ShowItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Item details", true, "Items on the ground: can't go through portals, weight, value and stack size.");
			ShowWeaknesses = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Weaknesses", true, "What a creature is weak to, resists or is immune to: a row of icons, and how much with the more key.");
			ShowDrops = ((BaseUnityPlugin)this).Config.Bind<bool>("Sections", "Drops", true, "With the more key: what something drops, as icons.");
			ShowPrefab = ((BaseUnityPlugin)this).Config.Bind<bool>("Details", "Show prefab name", false, "Show the internal prefab name, handy for console commands and mod configs.");
			ShowTerrain = ((BaseUnityPlugin)this).Config.Bind<bool>("Details", "Show the ground", false, "Show a panel for the ground too (biome).");
			HideWhileBuilding = ((BaseUnityPlugin)this).Config.Bind<bool>("Details", "Hide while building", true, "Hide the panel while a building piece is selected.");
			ModSource.Init();
			_panelObject = new GameObject("Hugin_Panel");
			Object.DontDestroyOnLoad((Object)(object)_panelObject);
			_panelObject.AddComponent<Panel>();
			_panelObject.AddComponent<BossBar>();
			_harmony = new Harmony("Hugin");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Hugin is watching.");
		}

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

		private void Update()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				Ui.PrepareArt();
				KeyboardShortcut value = ToggleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && !IsTyping())
				{
					ShowPanel.Value = !ShowPanel.Value;
				}
			}
		}

		private static bool IsTyping()
		{
			if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible())
			{
				return TextInput.IsVisible();
			}
			return true;
		}
	}
	internal static class Raven
	{
		private const float TiltTime = 0.45f;

		private const float TiltAngle = 9f;

		internal const float Aspect = 0.625f;

		internal const float EdgeAt = 0.64f;

		internal const float BeakTip = 0.96f;

		private static Texture2D _texture;

		private static bool _loaded;

		private static float _tiltStart = -10f;

		private static Texture2D Texture
		{
			get
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Expected O, but got Unknown
				if (_loaded)
				{
					return _texture;
				}
				_loaded = true;
				try
				{
					using Stream stream = typeof(Raven).Assembly.GetManifestResourceStream("Hugin.raven.png");
					if (stream == null)
					{
						return null;
					}
					byte[] array = new byte[stream.Length];
					stream.Read(array, 0, array.Length);
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
					{
						filterMode = (FilterMode)1,
						wrapMode = (TextureWrapMode)1
					};
					if (LoadImage(val, array))
					{
						_texture = val;
					}
				}
				catch (IOException ex)
				{
					Plugin.Log.LogWarning((object)("Couldn't load Hugin's picture: " + ex.Message));
				}
				return _texture;
			}
		}

		internal static bool Available => (Object)(object)Texture != (Object)null;

		private static bool LoadImage(Texture2D tex, byte[] bytes)
		{
			MethodInfo methodInfo = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			});
			bool flag = default(bool);
			int num;
			if (methodInfo != null)
			{
				object obj = methodInfo.Invoke(null, new object[2] { tex, bytes });
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		internal static void Curious()
		{
			_tiltStart = Time.unscaledTime;
		}

		internal static void Draw(Rect r)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown res