Decompiled source of CDEV HoverInfo v0.1.0

plugins\CDEV.HoverInfo\CDEV.HoverInfo.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("CDEV.HoverInfo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+dc973356a9e1d4377ae0cec010ca435f57d87290")]
[assembly: AssemblyProduct("CDEV.HoverInfo")]
[assembly: AssemblyTitle("CDEV.HoverInfo")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[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 CDEV.HoverInfo
{
	internal enum InfoKind
	{
		Cooking,
		Plant,
		Pickable,
		Fermenter,
		Smelter,
		Beehive,
		SapCollector,
		Fireplace,
		Egg,
		Creature
	}
	internal static class InfoText
	{
		internal const string Neutral = "#A8D8FF";

		internal const string Good = "#9EE89E";

		internal const string Warn = "#FFC04D";

		internal const string Bad = "#FF8080";

		private const float CacheSeconds = 0.25f;

		private static readonly StringBuilder Builder = new StringBuilder(256);

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

		private static Object s_cachedTarget;

		private static InfoKind s_cachedKind;

		private static float s_cachedAt;

		private static string s_cachedInfo;

		internal static bool CanRun(ConfigEntry<bool> source)
		{
			if (ModConfig.Enabled.Value && source.Value && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsDedicated())
			{
				return Localization.instance != null;
			}
			return false;
		}

		internal static bool TryGetCached(Object target, InfoKind kind, out string info)
		{
			if (s_cachedTarget != (Object)null && s_cachedTarget == target && s_cachedKind == kind && Time.unscaledTime - s_cachedAt < 0.25f)
			{
				info = s_cachedInfo;
				return true;
			}
			info = null;
			return false;
		}

		internal static string Store(Object target, InfoKind kind, string info)
		{
			s_cachedTarget = target;
			s_cachedKind = kind;
			s_cachedAt = Time.unscaledTime;
			s_cachedInfo = info;
			return info;
		}

		internal static StringBuilder Begin()
		{
			Builder.Length = 0;
			return Builder;
		}

		internal static void Line(StringBuilder sb, string color, string text)
		{
			if (sb.Length > 0)
			{
				sb.Append('\n');
			}
			sb.Append("<color=").Append(color).Append('>')
				.Append(text)
				.Append("</color>");
		}

		internal static string End(StringBuilder sb)
		{
			if (sb.Length != 0)
			{
				return sb.ToString();
			}
			return null;
		}

		internal static string Inject(string hover, string info)
		{
			if (string.IsNullOrEmpty(info))
			{
				return hover;
			}
			if (string.IsNullOrEmpty(hover))
			{
				return info;
			}
			int num = hover.IndexOf("\n[", StringComparison.Ordinal);
			if (num >= 0)
			{
				return hover.Substring(0, num) + "\n" + info + hover.Substring(num);
			}
			return hover + "\n" + info;
		}

		internal static string T(string token)
		{
			return Localization.instance.Localize(token);
		}

		internal static string Format(string token, object arg0)
		{
			return string.Format(CultureInfo.InvariantCulture, T(token), arg0);
		}

		internal static string Format(string token, object arg0, object arg1)
		{
			return string.Format(CultureInfo.InvariantCulture, T(token), arg0, arg1);
		}

		internal static string ItemName(ItemDrop item)
		{
			if (!((Object)(object)item != (Object)null))
			{
				return string.Empty;
			}
			return T(item.m_itemData.m_shared.m_name);
		}

		internal static string Duration(double seconds)
		{
			long num = ((seconds > 0.0) ? ((long)Math.Ceiling(seconds)) : 0);
			long num2 = num / 3600;
			long num3 = num % 3600 / 60;
			long num4 = num % 60;
			if (num2 > 0)
			{
				return num2.ToString(CultureInfo.InvariantCulture) + T("$cdev_hi_unit_h") + " " + num3.ToString("00", CultureInfo.InvariantCulture) + T("$cdev_hi_unit_m");
			}
			if (num3 > 0)
			{
				return num3.ToString(CultureInfo.InvariantCulture) + T("$cdev_hi_unit_m") + " " + num4.ToString("00", CultureInfo.InvariantCulture) + T("$cdev_hi_unit_s");
			}
			return num4.ToString(CultureInfo.InvariantCulture) + T("$cdev_hi_unit_s");
		}

		internal static double SecondsSince(long ticks)
		{
			return (ZNet.instance.GetTime() - new DateTime(ticks)).TotalSeconds;
		}

		internal static void Fail(string where, Exception e)
		{
			if (ReportedFailures.Add(where))
			{
				HoverInfoPlugin.Log.LogError((object)(where + " failed (further errors suppressed): " + e));
			}
		}
	}
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> Cooking;

		internal static ConfigEntry<bool> Plants;

		internal static ConfigEntry<bool> Pickables;

		internal static ConfigEntry<bool> Fermenters;

		internal static ConfigEntry<bool> Smelters;

		internal static ConfigEntry<bool> Beehives;

		internal static ConfigEntry<bool> SapCollectors;

		internal static ConfigEntry<bool> Fireplaces;

		internal static ConfigEntry<bool> Eggs;

		internal static ConfigEntry<bool> Creatures;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "Show timers in hover text.");
			Cooking = config.Bind<bool>("Sources", "CookingStations", true, "Cooking station and oven: time left per slot, burn warning, oven fuel.");
			Plants = config.Bind<bool>("Sources", "Plants", true, "Saplings and crops: time until grown.");
			Pickables = config.Bind<bool>("Sources", "Pickables", true, "Picked bushes, mushrooms etc.: time until they respawn.");
			Fermenters = config.Bind<bool>("Sources", "Fermenters", true, "Fermenter: time until ready.");
			Smelters = config.Bind<bool>("Sources", "Smelters", true, "Smelter, kiln, blast furnace, spinning wheel, windmill, eitr refinery: queue timers and fuel.");
			Beehives = config.Bind<bool>("Sources", "Beehives", true, "Beehive: next honey and time until full.");
			SapCollectors = config.Bind<bool>("Sources", "SapCollectors", true, "Sap extractor: next sap and time until full.");
			Fireplaces = config.Bind<bool>("Sources", "Fireplaces", true, "Fires, torches, braziers: how long the fuel lasts.");
			Eggs = config.Bind<bool>("Sources", "Eggs", true, "Warm eggs: time until hatching.");
			Creatures = config.Bind<bool>("Sources", "Creatures", true, "Taming, feeding, breeding and growing-up timers.");
		}
	}
	[BepInPlugin("cdev.hoverinfo", "CDEV.HoverInfo", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class HoverInfoPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			AddLocalization();
			_harmony = new Harmony("cdev.hoverinfo");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
		}

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

		private static void AddLocalization()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "cdev_hi_unit_h", "h" },
				{ "cdev_hi_unit_m", "m" },
				{ "cdev_hi_unit_s", "s" },
				{ "cdev_hi_paused", "paused" },
				{ "cdev_hi_burns_in", "burns in {0}" },
				{ "cdev_hi_fuel_lasts", "Fuel lasts {0}" },
				{ "cdev_hi_grows_in", "Grows in {0} ({1}%)" },
				{ "cdev_hi_grows_soon", "Grows any moment" },
				{ "cdev_hi_grows_blocked", "Due to grow - fix the problem first" },
				{ "cdev_hi_respawns_in", "Respawns in {0}" },
				{ "cdev_hi_respawns_soon", "Respawns any moment" },
				{ "cdev_hi_ready_in", "Ready in {0}" },
				{ "cdev_hi_next_in", "Next in {0}" },
				{ "cdev_hi_all_in", "All {0} in {1}" },
				{ "cdev_hi_full_in", "Full in {0}" },
				{ "cdev_hi_no_fuel", "No fuel" },
				{ "cdev_hi_no_wind", "No wind" },
				{ "cdev_hi_smoke_blocked", "Smoke is blocked" },
				{ "cdev_hi_fuel_short", "Fuel runs out in {0}, add {1} more" },
				{ "cdev_hi_burns_for", "Burns for {0}" },
				{ "cdev_hi_hatches_in", "Hatches in {0}" },
				{ "cdev_hi_tamed_in", "Tamed in ~{0}" },
				{ "cdev_hi_fed_for", "Fed for {0}" },
				{ "cdev_hi_love", "Love {0}/{1}" },
				{ "cdev_hi_offspring_in", "Offspring in {0}" },
				{ "cdev_hi_grows_up_in", "Grows up in {0}" }
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "cdev_hi_unit_h", "ч" },
				{ "cdev_hi_unit_m", "м" },
				{ "cdev_hi_unit_s", "с" },
				{ "cdev_hi_paused", "на паузе" },
				{ "cdev_hi_burns_in", "сгорит через {0}" },
				{ "cdev_hi_fuel_lasts", "Топлива на {0}" },
				{ "cdev_hi_grows_in", "Вырастет через {0} ({1}%)" },
				{ "cdev_hi_grows_soon", "Вот-вот вырастет" },
				{ "cdev_hi_grows_blocked", "Пора расти - сначала устраните проблему" },
				{ "cdev_hi_respawns_in", "Отрастёт через {0}" },
				{ "cdev_hi_respawns_soon", "Вот-вот отрастёт" },
				{ "cdev_hi_ready_in", "Готово через {0}" },
				{ "cdev_hi_next_in", "Следующий через {0}" },
				{ "cdev_hi_all_in", "Все {0} через {1}" },
				{ "cdev_hi_full_in", "Заполнится через {0}" },
				{ "cdev_hi_no_fuel", "Нет топлива" },
				{ "cdev_hi_no_wind", "Нет ветра" },
				{ "cdev_hi_smoke_blocked", "Дыму некуда выходить" },
				{ "cdev_hi_fuel_short", "Топливо кончится через {0}, добавьте ещё {1}" },
				{ "cdev_hi_burns_for", "Будет гореть {0}" },
				{ "cdev_hi_hatches_in", "Проклюнется через {0}" },
				{ "cdev_hi_tamed_in", "Приручится через ~{0}" },
				{ "cdev_hi_fed_for", "Сыт ещё {0}" },
				{ "cdev_hi_love", "Любовь {0}/{1}" },
				{ "cdev_hi_offspring_in", "Потомство через {0}" },
				{ "cdev_hi_grows_up_in", "Вырастет через {0}" }
			});
		}
	}
	internal static class BuildInfo
	{
		public const string Name = "CDEV.HoverInfo";

		public const string Guid = "cdev.hoverinfo";

		public const string Version = "0.1.0";
	}
}
namespace CDEV.HoverInfo.Patches
{
	[HarmonyPatch(typeof(CookingStation), "HoverText")]
	internal static class CookingStationHoverTextPatch
	{
		private static void Postfix(CookingStation __instance, ref string __result)
		{
			if (!InfoText.CanRun(ModConfig.Cooking))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Cooking, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Cooking, Compose(__instance));
				}
				__result = InfoText.Inject(__result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("CookingStation.HoverText postfix", e);
			}
		}

		private static string Compose(CookingStation station)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)station.m_nview == (Object)null || !station.m_nview.IsValid() || station.m_slots == null)
			{
				return null;
			}
			StringBuilder sb = InfoText.Begin();
			bool flag = IsCooking(station);
			string text = default(string);
			float num = default(float);
			Status val = default(Status);
			bool flag2 = default(bool);
			for (int i = 0; i < station.m_slots.Length; i++)
			{
				station.GetSlot(i, ref text, ref num, ref val, ref flag2);
				if (string.IsNullOrEmpty(text) || (int)val == 2)
				{
					continue;
				}
				ItemConversion itemConversion = station.GetItemConversion(text);
				if (itemConversion != null && !(itemConversion.m_cookTime <= 0f))
				{
					if ((int)val == 0)
					{
						string text2 = InfoText.ItemName(itemConversion.m_from) + ": " + InfoText.Duration(itemConversion.m_cookTime - num);
						InfoText.Line(sb, flag ? "#A8D8FF" : "#FFC04D", flag ? text2 : (text2 + " (" + InfoText.T("$cdev_hi_paused") + ")"));
					}
					else if (station.m_canOvercookItems)
					{
						InfoText.Line(sb, "#FFC04D", InfoText.ItemName(itemConversion.m_to) + ": " + InfoText.Format("$cdev_hi_burns_in", InfoText.Duration(itemConversion.m_cookTime * 2f - num)));
					}
				}
			}
			if (station.m_useFuel && station.m_secPerFuel > 0)
			{
				float fuel = station.GetFuel();
				if (fuel > 0f)
				{
					InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_fuel_lasts", InfoText.Duration(fuel * (float)station.m_secPerFuel)));
				}
			}
			return InfoText.End(sb);
		}

		private static bool IsCooking(CookingStation station)
		{
			if (station.m_requireFire && station.IsFireLit())
			{
				return true;
			}
			if (station.m_useFuel && station.GetFuel() > 0f)
			{
				if (!station.m_useFueldWhileEmpty)
				{
					return station.HaveUncookedItem();
				}
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Character), "GetHoverText")]
	internal static class CharacterHoverTextPatch
	{
		private static void Postfix(Character __instance, ref string __result)
		{
			if (!InfoText.CanRun(ModConfig.Creatures))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Creature, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Creature, Compose(__instance));
				}
				if (info != null)
				{
					string hover = (string.IsNullOrEmpty(__result) ? InfoText.T(__instance.GetHoverName()) : __result);
					__result = InfoText.Inject(hover, info);
				}
			}
			catch (Exception e)
			{
				InfoText.Fail("Character.GetHoverText postfix", e);
			}
		}

		private static string Compose(Character character)
		{
			if ((Object)(object)character.m_nview == (Object)null || !character.m_nview.IsValid())
			{
				return null;
			}
			ZDO zDO = character.m_nview.GetZDO();
			StringBuilder sb = InfoText.Begin();
			Tameable component = ((Component)character).GetComponent<Tameable>();
			if ((Object)(object)component != (Object)null)
			{
				if (!component.IsTamed())
				{
					float remainingTime = component.GetRemainingTime();
					if (!component.IsHungry() && remainingTime > 0f)
					{
						InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_tamed_in", InfoText.Duration(remainingTime)));
					}
				}
				else
				{
					long num = zDO.GetLong(ZDOVars.s_tameLastFeeding, 0L);
					if (num > 0)
					{
						double num2 = (double)component.m_fedDuration - InfoText.SecondsSince(num);
						if (num2 > 0.0)
						{
							InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_fed_for", InfoText.Duration(num2)));
						}
					}
					AppendProcreation(sb, ((Component)character).GetComponent<Procreation>(), zDO);
				}
			}
			Growup component2 = ((Component)character).GetComponent<Growup>();
			if ((Object)(object)component2 != (Object)null && component2.m_growTime > 0f)
			{
				long num3 = zDO.GetLong(ZDOVars.s_spawnTime, 0L);
				if (num3 > 0)
				{
					InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_grows_up_in", InfoText.Duration((double)component2.m_growTime - InfoText.SecondsSince(num3))));
				}
			}
			return InfoText.End(sb);
		}

		private static void AppendProcreation(StringBuilder sb, Procreation procreation, ZDO zdo)
		{
			if (!((Object)(object)procreation == (Object)null))
			{
				long num = zdo.GetLong(ZDOVars.s_pregnant, 0L);
				if (num != 0L)
				{
					InfoText.Line(sb, "#9EE89E", InfoText.Format("$cdev_hi_offspring_in", InfoText.Duration((double)procreation.m_pregnancyDuration - InfoText.SecondsSince(num))));
				}
				else if (procreation.m_requiredLovePoints > 0)
				{
					InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_love", zdo.GetInt(ZDOVars.s_lovePoints, 0), procreation.m_requiredLovePoints));
				}
			}
		}
	}
	[HarmonyPatch(typeof(EggGrow), "GetHoverText")]
	internal static class EggGrowHoverTextPatch
	{
		private static void Postfix(EggGrow __instance, ref string __result)
		{
			if (!InfoText.CanRun(ModConfig.Eggs))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Egg, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Egg, Compose(__instance));
				}
				__result = InfoText.Inject(__result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("EggGrow.GetHoverText postfix", e);
			}
		}

		private static string Compose(EggGrow egg)
		{
			if ((Object)(object)egg.m_item == (Object)null || egg.m_item.m_itemData.m_stack > 1 || (Object)(object)egg.m_nview == (Object)null || !egg.m_nview.IsValid())
			{
				return null;
			}
			float num = egg.m_nview.GetZDO().GetFloat(ZDOVars.s_growStart, 0f);
			if (num <= 0f)
			{
				return null;
			}
			StringBuilder sb = InfoText.Begin();
			InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_hatches_in", InfoText.Duration((double)(num + egg.m_growTime) - ZNet.instance.GetTimeSeconds())));
			return InfoText.End(sb);
		}
	}
	[HarmonyPatch(typeof(Plant), "GetHoverText")]
	internal static class PlantHoverTextPatch
	{
		private static void Postfix(Plant __instance, ref string __result)
		{
			if (!InfoText.CanRun(ModConfig.Plants))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Plant, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Plant, Compose(__instance));
				}
				__result = InfoText.Inject(__result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("Plant.GetHoverText postfix", e);
			}
		}

		private static string Compose(Plant plant)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			if ((Object)(object)plant.m_nview == (Object)null || !plant.m_nview.IsValid())
			{
				return null;
			}
			float growTime = plant.GetGrowTime();
			if (growTime <= 0f)
			{
				return null;
			}
			double num = plant.TimeSincePlanted();
			double num2 = (double)growTime - num;
			bool flag = (int)plant.m_status == 0;
			StringBuilder sb = InfoText.Begin();
			if (num2 > 0.0)
			{
				int num3 = Mathf.Clamp((int)(num / (double)growTime * 100.0), 0, 99);
				InfoText.Line(sb, flag ? "#A8D8FF" : "#FFC04D", InfoText.Format("$cdev_hi_grows_in", InfoText.Duration(num2), num3));
			}
			else
			{
				InfoText.Line(sb, flag ? "#9EE89E" : "#FFC04D", InfoText.T(flag ? "$cdev_hi_grows_soon" : "$cdev_hi_grows_blocked"));
			}
			return InfoText.End(sb);
		}
	}
	[HarmonyPatch(typeof(Pickable), "GetHoverText")]
	internal static class PickableHoverTextPatch
	{
		private static void Postfix(Pickable __instance, ref string __result)
		{
			if (!__instance.m_picked || __instance.m_respawnTimeMinutes <= 0f || !InfoText.CanRun(ModConfig.Pickables))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Pickable, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Pickable, Compose(__instance));
				}
				if (info != null)
				{
					string hover = (string.IsNullOrEmpty(__result) ? InfoText.T(__instance.GetHoverName()) : __result);
					__result = InfoText.Inject(hover, info);
				}
			}
			catch (Exception e)
			{
				InfoText.Fail("Pickable.GetHoverText postfix", e);
			}
		}

		private static string Compose(Pickable pickable)
		{
			if (pickable.m_enabled == 0 || (Object)(object)pickable.m_nview == (Object)null || !pickable.m_nview.IsValid())
			{
				return null;
			}
			long num = pickable.m_nview.GetZDO().GetLong(ZDOVars.s_pickedTime, 0L);
			if (num <= 1)
			{
				return null;
			}
			double num2 = (double)pickable.m_respawnTimeMinutes * 60.0 - InfoText.SecondsSince(num);
			StringBuilder sb = InfoText.Begin();
			InfoText.Line(sb, (num2 > 0.0) ? "#A8D8FF" : "#9EE89E", (num2 > 0.0) ? InfoText.Format("$cdev_hi_respawns_in", InfoText.Duration(num2)) : InfoText.T("$cdev_hi_respawns_soon"));
			return InfoText.End(sb);
		}
	}
	[HarmonyPatch(typeof(Fireplace), "GetHoverText")]
	internal static class FireplaceHoverTextPatch
	{
		private static void Postfix(Fireplace __instance, ref string __result)
		{
			if (__instance.m_infiniteFuel || !InfoText.CanRun(ModConfig.Fireplaces))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Fireplace, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Fireplace, Compose(__instance));
				}
				__result = InfoText.Inject(__result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("Fireplace.GetHoverText postfix", e);
			}
		}

		private static string Compose(Fireplace fireplace)
		{
			if (fireplace.m_secPerFuel <= 0f || (Object)(object)fireplace.m_nview == (Object)null || !fireplace.m_nview.IsValid())
			{
				return null;
			}
			ZDO zDO = fireplace.m_nview.GetZDO();
			float num = zDO.GetFloat(ZDOVars.s_fuel, 0f);
			if (num <= 0f)
			{
				return null;
			}
			bool flag = zDO.GetInt(ZDOVars.s_state, 1) == 1 && fireplace.IsBurning();
			string text = InfoText.Format("$cdev_hi_burns_for", InfoText.Duration(num * fireplace.m_secPerFuel));
			StringBuilder sb = InfoText.Begin();
			InfoText.Line(sb, flag ? "#A8D8FF" : "#FFC04D", flag ? text : (text + " (" + InfoText.T("$cdev_hi_paused") + ")"));
			return InfoText.End(sb);
		}
	}
	[HarmonyPatch(typeof(Fermenter), "GetHoverText")]
	internal static class FermenterHoverTextPatch
	{
		private static void Postfix(Fermenter __instance, ref string __result)
		{
			if (!InfoText.CanRun(ModConfig.Fermenters))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Fermenter, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Fermenter, Compose(__instance));
				}
				__result = InfoText.Inject(__result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("Fermenter.GetHoverText postfix", e);
			}
		}

		private static string Compose(Fermenter fermenter)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			if ((Object)(object)fermenter.m_nview == (Object)null || !fermenter.m_nview.IsValid() || !PrivateArea.CheckAccess(((Component)fermenter).transform.position, 0f, false, false) || (int)fermenter.GetStatus() != 1)
			{
				return null;
			}
			if (fermenter.m_exposed || !fermenter.m_hasRoof)
			{
				return null;
			}
			double fermentationTime = fermenter.GetFermentationTime();
			if (fermentationTime < 0.0)
			{
				return null;
			}
			StringBuilder sb = InfoText.Begin();
			InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_ready_in", InfoText.Duration((double)fermenter.m_fermentationDuration - fermentationTime)));
			return InfoText.End(sb);
		}
	}
	[HarmonyPatch]
	internal static class SmelterHoverPatches
	{
		[HarmonyPatch(typeof(Smelter), "OnHoverAddOre")]
		[HarmonyPostfix]
		private static void OnHoverAddOrePostfix(Smelter __instance, ref string __result)
		{
			Apply(__instance, ref __result);
		}

		[HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")]
		[HarmonyPostfix]
		private static void OnHoverAddFuelPostfix(Smelter __instance, ref string __result)
		{
			Apply(__instance, ref __result);
		}

		private static void Apply(Smelter smelter, ref string result)
		{
			if (!InfoText.CanRun(ModConfig.Smelters))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)smelter, InfoKind.Smelter, out var info))
				{
					info = InfoText.Store((Object)(object)smelter, InfoKind.Smelter, Compose(smelter));
				}
				result = InfoText.Inject(result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("Smelter hover postfix", e);
			}
		}

		private static string Compose(Smelter smelter)
		{
			if ((Object)(object)smelter.m_nview == (Object)null || !smelter.m_nview.IsValid() || smelter.m_secPerProduct <= 0f)
			{
				return null;
			}
			int queueSize = smelter.GetQueueSize();
			if (queueSize <= 0)
			{
				return null;
			}
			StringBuilder sb = InfoText.Begin();
			float num = ((smelter.m_maxFuel > 0) ? smelter.GetFuel() : 0f);
			if (smelter.m_maxFuel > 0 && num <= 0f)
			{
				InfoText.Line(sb, "#FF8080", InfoText.T("$cdev_hi_no_fuel"));
				return InfoText.End(sb);
			}
			if (smelter.m_blockedSmoke)
			{
				InfoText.Line(sb, "#FF8080", InfoText.T("$cdev_hi_smoke_blocked"));
				return InfoText.End(sb);
			}
			if (smelter.m_requiresRoof && !smelter.m_haveRoof)
			{
				return null;
			}
			float num2 = (((Object)(object)smelter.m_windmill != (Object)null) ? smelter.m_windmill.GetPowerOutput() : 1f);
			if (num2 <= 0.01f)
			{
				InfoText.Line(sb, "#FFC04D", InfoText.T("$cdev_hi_no_wind"));
				return InfoText.End(sb);
			}
			float num3 = Mathf.Clamp(smelter.GetBakeTimer(), 0f, smelter.m_secPerProduct);
			double num4 = (smelter.m_secPerProduct - num3) / num2;
			InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_next_in", InfoText.Duration(num4)));
			if (queueSize > 1)
			{
				double seconds = num4 + (double)(queueSize - 1) * (double)smelter.m_secPerProduct / (double)num2;
				InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_all_in", queueSize, InfoText.Duration(seconds)));
			}
			if (smelter.m_maxFuel > 0 && smelter.m_fuelPerProduct > 0)
			{
				double num5 = (smelter.m_secPerProduct - num3) / smelter.m_secPerProduct + (float)(queueSize - 1);
				double num6 = (double)num / (double)smelter.m_fuelPerProduct;
				if (num6 + 0.001 < num5)
				{
					double seconds2 = num6 * (double)smelter.m_secPerProduct / (double)num2;
					int num7 = Mathf.CeilToInt((float)((num5 - num6) * (double)smelter.m_fuelPerProduct));
					InfoText.Line(sb, "#FFC04D", InfoText.Format("$cdev_hi_fuel_short", InfoText.Duration(seconds2), num7));
				}
			}
			return InfoText.End(sb);
		}
	}
	[HarmonyPatch(typeof(Beehive), "GetHoverText")]
	internal static class BeehiveHoverTextPatch
	{
		private static void Postfix(Beehive __instance, ref string __result)
		{
			if (!InfoText.CanRun(ModConfig.Beehives))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.Beehive, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.Beehive, Compose(__instance));
				}
				__result = InfoText.Inject(__result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("Beehive.GetHoverText postfix", e);
			}
		}

		private static string Compose(Beehive hive)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hive.m_nview == (Object)null || !hive.m_nview.IsValid() || hive.m_secPerUnit <= 0f || !PrivateArea.CheckAccess(((Component)hive).transform.position, 0f, false, false))
			{
				return null;
			}
			int honeyLevel = hive.GetHoneyLevel();
			if (honeyLevel >= hive.m_maxHoney || !hive.CheckBiome() || !hive.HaveFreeSpace())
			{
				return null;
			}
			return UnitTimers.Compose(hive.m_nview.GetZDO(), hive.m_secPerUnit, hive.m_maxHoney - honeyLevel);
		}
	}
	[HarmonyPatch(typeof(SapCollector), "GetHoverText")]
	internal static class SapCollectorHoverTextPatch
	{
		private static void Postfix(SapCollector __instance, ref string __result)
		{
			if (!InfoText.CanRun(ModConfig.SapCollectors))
			{
				return;
			}
			try
			{
				if (!InfoText.TryGetCached((Object)(object)__instance, InfoKind.SapCollector, out var info))
				{
					info = InfoText.Store((Object)(object)__instance, InfoKind.SapCollector, Compose(__instance));
				}
				__result = InfoText.Inject(__result, info);
			}
			catch (Exception e)
			{
				InfoText.Fail("SapCollector.GetHoverText postfix", e);
			}
		}

		private static string Compose(SapCollector collector)
		{
			if ((Object)(object)collector.m_nview == (Object)null || !collector.m_nview.IsValid() || collector.m_secPerUnit <= 0f)
			{
				return null;
			}
			int level = collector.GetLevel();
			if (level >= collector.m_maxLevel || (Object)(object)collector.m_root == (Object)null || !collector.m_root.CanDrain(1f))
			{
				return null;
			}
			return UnitTimers.Compose(collector.m_nview.GetZDO(), collector.m_secPerUnit, collector.m_maxLevel - level);
		}
	}
	internal static class UnitTimers
	{
		internal static string Compose(ZDO zdo, float secPerUnit, int unitsMissing)
		{
			if (unitsMissing <= 0)
			{
				return null;
			}
			double num = zdo.GetFloat(ZDOVars.s_product, 0f);
			long num2 = zdo.GetLong(ZDOVars.s_lastTime, 0L);
			if (num2 > 0)
			{
				num += Math.Max(0.0, InfoText.SecondsSince(num2));
			}
			double num3 = Math.Max(0.0, (double)secPerUnit - num);
			StringBuilder sb = InfoText.Begin();
			InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_next_in", InfoText.Duration(num3)));
			if (unitsMissing > 1)
			{
				InfoText.Line(sb, "#A8D8FF", InfoText.Format("$cdev_hi_full_in", InfoText.Duration(num3 + (double)(unitsMissing - 1) * (double)secPerUnit)));
			}
			return InfoText.End(sb);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}