Decompiled source of ReadyWhen v1.0.0

ReadyWhen.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ReadyWhen.Utils;
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("ReadyWhen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ReadyWhen")]
[assembly: AssemblyTitle("ReadyWhen")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ReadyWhen
{
	[BepInPlugin("com.jubaroo.readywhen", "ReadyWhen", "1.0.0")]
	public class BatchTimersPlugin : BaseUnityPlugin
	{
		public static ConfigEntry<bool> EnableSmelters;

		public static ConfigEntry<bool> EnablePlants;

		public static ConfigEntry<bool> EnableCooking;

		public static ConfigEntry<bool> EnableBeehive;

		public static ConfigEntry<bool> EnableFermenter;

		public static ConfigEntry<bool> EnableSapCollector;

		public static ConfigEntry<bool> EnableEggs;

		public static ConfigEntry<bool> EnableFireplaces;

		public static ConfigEntry<bool> EnableTaming;

		public static ConfigEntry<bool> EnableQueueInventoryPreview;

		public static ConfigEntry<bool> ShowFullCapacityTime;

		public static ConfigEntry<TimeFormat> TimeFormatStyle;

		public static ConfigEntry<string> TimerColor;

		public static ConfigEntry<string> WarningColor;

		public static ConfigEntry<string> InfoColor;

		private readonly Harmony _harmony = new Harmony("com.jubaroo.readywhen");

		private void Awake()
		{
			EnableSmelters = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableSmelters", true, "Show timers on Smelters, Kilns, Blast Furnaces, and Windmills");
			EnablePlants = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnablePlants", true, "Show growth timers and space warnings on crops");
			EnableCooking = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableCooking", true, "Show cook/burn timers on cooking stations");
			EnableBeehive = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableBeehive", true, "Show honey production timers on beehives");
			EnableFermenter = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableFermenter", true, "Show fermentation progress timers on fermenters");
			EnableSapCollector = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableSapCollector", true, "Show extraction timers on sap collectors");
			EnableEggs = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableEggs", true, "Show hatching/incubation timers on eggs");
			EnableFireplaces = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableFireplaces", true, "Show burn-out timers on campfires, hearths, sconces, and torches");
			EnableTaming = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableTaming", true, "Show live taming percentage and remaining time countdown on creatures");
			EnableQueueInventoryPreview = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableQueueInventoryPreview", true, "Show detailed breakdown of queued items in smelters (e.g. 3x Copper, 1x Tin)");
			ShowFullCapacityTime = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "ShowFullCapacityTime", true, "Show estimated time until max capacity (e.g. 4/4 honey, 10/10 sap)");
			TimeFormatStyle = ((BaseUnityPlugin)this).Config.Bind<TimeFormat>("Formatting", "TimeFormatStyle", TimeFormat.Digital, "Style of displayed time durations: 'Digital' (02:15:30), 'Written' (2h 15m 30s), or 'Minimal' (2h 15m)");
			TimerColor = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "TimerColor", "yellow", "Color of the standard timer text (e.g., yellow, #FFFF00)");
			WarningColor = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "WarningColor", "red", "Color of warnings like missing fuel, unlit fire, or no space (e.g., red, #FF0000)");
			InfoColor = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "InfoColor", "#00FFFF", "Color of secondary info like full capacity, queue details, or stability (e.g., #00FFFF, #FFA500, orange)");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ReadyWhen v1.0.0 fully loaded with configuration!");
		}
	}
	public enum TimeFormat
	{
		Digital,
		Written,
		Minimal
	}
}
namespace ReadyWhen.Utils
{
	public static class TimeUtility
	{
		public static string Format(float seconds)
		{
			if (seconds < 0f)
			{
				seconds = 0f;
			}
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			switch (BatchTimersPlugin.TimeFormatStyle?.Value ?? TimeFormat.Digital)
			{
			case TimeFormat.Written:
				if (timeSpan.TotalHours >= 1.0)
				{
					return $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes}m {timeSpan.Seconds}s";
				}
				if (timeSpan.TotalMinutes >= 1.0)
				{
					return $"{timeSpan.Minutes}m {timeSpan.Seconds}s";
				}
				return $"{timeSpan.Seconds}s";
			case TimeFormat.Minimal:
				if (timeSpan.TotalHours >= 1.0)
				{
					return $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes}m";
				}
				if (timeSpan.TotalMinutes >= 1.0)
				{
					return $"{timeSpan.Minutes}m";
				}
				return "< 1m";
			default:
				if (timeSpan.TotalHours >= 1.0)
				{
					return $"{(int)timeSpan.TotalHours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
				}
				return $"{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
			}
		}
	}
}
namespace ReadyWhen.Patches
{
	[HarmonyPatch(typeof(Beehive), "GetHoverText")]
	public static class BeehivePatch
	{
		public static void Postfix(Beehive __instance, ref string __result)
		{
			if (!BatchTimersPlugin.EnableBeehive.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid())
			{
				return;
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.WarningColor.Value;
			string value3 = BatchTimersPlugin.InfoColor.Value;
			if (!__instance.CheckBiome())
			{
				__result = __result + "\n<color=" + value2 + ">Bees aren't happy in this environment</color>";
				return;
			}
			if (!__instance.HaveFreeSpace())
			{
				__result = __result + "\n<color=" + value2 + ">The bees need more open space</color>";
				return;
			}
			int num = __instance.m_nview.GetZDO().GetInt(ZDOVars.s_level, 0);
			if (num >= __instance.m_maxHoney)
			{
				return;
			}
			if (!EnvMan.IsDaylight() && (Object)(object)EnvMan.instance != (Object)null)
			{
				float dayFraction = EnvMan.instance.GetDayFraction();
				long dayLengthSec = EnvMan.instance.m_dayLengthSec;
				float num2 = 0.25f - dayFraction;
				if (num2 < 0f)
				{
					num2 += 1f;
				}
				float num3 = num2 * (float)dayLengthSec;
				__result = __result + "\n<color=" + value2 + ">The bees are sleeping (nighttime)</color>";
				if (num3 > 0f)
				{
					__result = __result + "\n<color=" + value3 + ">Daylight in: " + TimeUtility.Format(num3) + "</color>";
				}
				return;
			}
			float num4 = __instance.m_nview.GetZDO().GetFloat(ZDOVars.s_product, 0f);
			long num5 = __instance.m_nview.GetZDO().GetLong(ZDOVars.s_lastTime, 0L);
			if (num5 != 0L)
			{
				float num6 = (float)(ZNet.instance.GetTime() - new DateTime(num5)).TotalSeconds;
				if (num6 > 0f)
				{
					num4 += num6;
				}
			}
			float num7 = __instance.m_secPerUnit - num4 % __instance.m_secPerUnit;
			if (!(num7 > 0f))
			{
				return;
			}
			__result = __result + "\n<color=" + value + ">Next honey in: " + TimeUtility.Format(num7) + "</color>";
			if (BatchTimersPlugin.ShowFullCapacityTime.Value)
			{
				int num8 = __instance.m_maxHoney - num;
				if (num8 > 1)
				{
					float seconds = num7 + __instance.m_secPerUnit * (float)(num8 - 1);
					__result += $"\n<color={value3}>Full ({__instance.m_maxHoney}/{__instance.m_maxHoney}) in: {TimeUtility.Format(seconds)}</color>";
				}
			}
		}
	}
	[HarmonyPatch(typeof(Switch), "GetHoverText")]
	public static class CookingStationSwitchPatch
	{
		public static void Postfix(Switch __instance, ref string __result)
		{
			CookingStation componentInParent = ((Component)__instance).GetComponentInParent<CookingStation>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				CookingStationPatch.AppendCookingStationInfo(componentInParent, ref __result);
			}
		}
	}
	[HarmonyPatch(typeof(CookingStation), "GetHoverText")]
	public static class CookingStationPatch
	{
		public static void Postfix(CookingStation __instance, ref string __result)
		{
			AppendCookingStationInfo(__instance, ref __result);
		}

		public static void AppendCookingStationInfo(CookingStation station, ref string text)
		{
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Invalid comparison between Unknown and I4
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Invalid comparison between Unknown and I4
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Invalid comparison between Unknown and I4
			if (!BatchTimersPlugin.EnableCooking.Value || (Object)(object)station == (Object)null || (Object)(object)station.m_nview == (Object)null || !station.m_nview.IsValid() || (text != null && (text.Contains("Cooks in") || text.Contains("BURNS IN") || text.Contains("Ready to take") || text.Contains("Out of "))))
			{
				return;
			}
			if (string.IsNullOrEmpty(text))
			{
				text = Localization.instance.Localize(station.m_name);
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.WarningColor.Value;
			string value3 = BatchTimersPlugin.InfoColor.Value;
			bool flag = !station.m_requireFire || station.IsFireLit();
			bool flag2 = !station.m_useFuel || station.GetFuel() > 0f;
			bool flag3 = flag && flag2;
			if (station.m_useFuel)
			{
				float fuel = station.GetFuel();
				int num = Mathf.CeilToInt(fuel);
				string text2 = (((Object)(object)station.m_fuelItem != (Object)null) ? station.m_fuelItem.m_itemData.m_shared.m_name : "Fuel");
				text2 = Localization.instance.Localize(text2);
				if (fuel <= 0f)
				{
					text = text + "\n<color=" + value2 + ">Out of " + text2 + "! Cannot cook.</color>";
				}
				else
				{
					float seconds = fuel * (float)station.m_secPerFuel;
					text += $"\n<color={value3}>{text2}: {num}/{station.m_maxFuel} ({TimeUtility.Format(seconds)})</color>";
				}
			}
			else if (station.m_requireFire && !flag)
			{
				text = text + "\n<color=" + value2 + ">Warning: Fire needs to be lit to cook!</color>";
			}
			if (station.m_slots == null)
			{
				return;
			}
			string text3 = default(string);
			float num2 = default(float);
			Status val = default(Status);
			bool flag4 = default(bool);
			for (int i = 0; i < station.m_slots.Length; i++)
			{
				station.GetSlot(i, ref text3, ref num2, ref val, ref flag4);
				if (string.IsNullOrEmpty(text3))
				{
					continue;
				}
				ItemConversion itemConversion = station.GetItemConversion(text3);
				if (itemConversion == null)
				{
					continue;
				}
				string text4 = (((int)val == 0) ? (((Object)(object)itemConversion.m_from != (Object)null) ? itemConversion.m_from.m_itemData.m_shared.m_name : text3) : (((int)val != 1) ? (((Object)(object)station.m_overCookedItem != (Object)null) ? station.m_overCookedItem.m_itemData.m_shared.m_name : "Coal") : (((Object)(object)itemConversion.m_to != (Object)null) ? itemConversion.m_to.m_itemData.m_shared.m_name : text3)));
				text4 = Localization.instance.Localize(text4);
				if ((int)val == 0)
				{
					float seconds2 = Mathf.Max(0f, itemConversion.m_cookTime - num2);
					if (flag3)
					{
						text += $"\n<color={value}>Slot {i + 1} ({text4}): Cooks in {TimeUtility.Format(seconds2)}</color>";
					}
					else
					{
						text += $"\n<color={value2}>Slot {i + 1} ({text4}): Paused ({TimeUtility.Format(seconds2)} left)</color>";
					}
				}
				else if ((int)val == 1)
				{
					if (station.m_canOvercookItems)
					{
						float num3 = Mathf.Max(0f, itemConversion.m_cookTime * 2f - num2);
						if (flag3 && num3 > 0f)
						{
							text += $"\n<color={value2}>Slot {i + 1} ({text4}): Ready! BURNS IN {TimeUtility.Format(num3)}!</color>";
						}
						else
						{
							text += $"\n<color={value}>Slot {i + 1} ({text4}): Ready to take!</color>";
						}
					}
					else
					{
						text += $"\n<color={value}>Slot {i + 1} ({text4}): Ready to take!</color>";
					}
				}
				else if ((int)val == 2)
				{
					text += $"\n<color={value2}>Slot {i + 1} ({text4}): Burnt!</color>";
				}
			}
		}
	}
	[HarmonyPatch(typeof(EggGrow), "GetHoverText")]
	public static class EggGrowPatch
	{
		public static void Postfix(EggGrow __instance, ref string __result)
		{
			if (!BatchTimersPlugin.EnableEggs.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid())
			{
				return;
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.WarningColor.Value;
			if ((Object)(object)__instance.m_item != (Object)null && __instance.m_item.m_itemData != null && __instance.m_item.m_itemData.m_stack > 1)
			{
				__result = __result + "\n<color=" + value2 + ">Too many in stack to hatch!</color>";
				return;
			}
			if (!__instance.CanGrow())
			{
				__result = __result + "\n<color=" + value2 + ">Needs warmth to hatch</color>";
				return;
			}
			long num = __instance.m_nview.GetZDO().GetLong(ZDOVars.s_growStart, 0L);
			if (num != 0L)
			{
				double totalSeconds = (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds;
				float num2 = __instance.m_growTime - (float)totalSeconds;
				if (num2 > 0f)
				{
					__result = __result + "\n<color=" + value + ">Hatches in: " + TimeUtility.Format(num2) + "</color>";
				}
			}
		}
	}
	[HarmonyPatch(typeof(Fermenter), "GetHoverText")]
	public static class FermenterPatch
	{
		public static void Postfix(Fermenter __instance, ref string __result)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			if (!BatchTimersPlugin.EnableFermenter.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid())
			{
				return;
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			if ((int)__instance.GetStatus() != 1)
			{
				return;
			}
			long num = __instance.m_nview.GetZDO().GetLong(ZDOVars.s_startTime, 0L);
			if (num != 0L)
			{
				double totalSeconds = (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds;
				float num2 = __instance.m_fermentationDuration - (float)totalSeconds;
				if (num2 > 0f)
				{
					__result = __result + "\n<color=" + value + ">Fermenting done in: " + TimeUtility.Format(num2) + "</color>";
				}
			}
		}
	}
	[HarmonyPatch(typeof(Fireplace), "GetHoverText")]
	public static class FireplacePatch
	{
		public static void Postfix(Fireplace __instance, ref string __result)
		{
			if (!BatchTimersPlugin.EnableFireplaces.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || __instance.m_infiniteFuel)
			{
				return;
			}
			float num = __instance.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.WarningColor.Value;
			if (num <= 0f)
			{
				__result = __result + "\n<color=" + value2 + ">Extinguished (Needs fuel)</color>";
			}
			else if (__instance.IsBurning())
			{
				float num2 = num * __instance.m_secPerFuel;
				long num3 = __instance.m_nview.GetZDO().GetLong(ZDOVars.s_lastTime, 0L);
				if (num3 != 0L)
				{
					float num4 = (float)(ZNet.instance.GetTime() - new DateTime(num3)).TotalSeconds;
					if (num4 > 0f)
					{
						num2 = Mathf.Max(0f, num2 - num4);
					}
				}
				if (num2 > 0f)
				{
					__result = __result + "\n<color=" + value + ">Burns out in: " + TimeUtility.Format(num2) + "</color>";
				}
			}
			else if (__instance.m_wet)
			{
				__result = __result + "\n<color=" + value2 + ">Doused by water/rain (Paused)</color>";
			}
			else if (__instance.m_blocked)
			{
				__result = __result + "\n<color=" + value2 + ">Blocked by smoke (Paused)</color>";
			}
		}
	}
	[HarmonyPatch(typeof(Plant), "GetHoverText")]
	public static class PlantPatch
	{
		public static void Postfix(Plant __instance, ref string __result)
		{
			if (!BatchTimersPlugin.EnablePlants.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid())
			{
				return;
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.WarningColor.Value;
			if (!__instance.HaveGrowSpace())
			{
				__result = __result + "\n<color=" + value2 + ">Needs more space to grow!</color>";
				return;
			}
			float num = __instance.m_growTime + __instance.m_growTimeMax;
			double num2 = __instance.TimeSincePlanted();
			float num3 = num - (float)num2;
			if (num3 > 0f)
			{
				__result = __result + "\n<color=" + value + ">Grows in: " + TimeUtility.Format(num3) + "</color>";
			}
		}
	}
	[HarmonyPatch(typeof(SapCollector), "GetHoverText")]
	public static class SapCollectorPatch
	{
		public static void Postfix(SapCollector __instance, ref string __result)
		{
			if (!BatchTimersPlugin.EnableSapCollector.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || (Object)(object)__instance.m_root == (Object)null)
			{
				return;
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.InfoColor.Value;
			int num = __instance.m_nview.GetZDO().GetInt(ZDOVars.s_level, 0);
			if (num >= __instance.m_maxLevel)
			{
				return;
			}
			long num2 = __instance.m_nview.GetZDO().GetLong(ZDOVars.s_startTime, 0L);
			if (num2 == 0L)
			{
				return;
			}
			double totalSeconds = (ZNet.instance.GetTime() - new DateTime(num2)).TotalSeconds;
			float num3 = __instance.m_secPerUnit - (float)(totalSeconds % (double)__instance.m_secPerUnit);
			if (!(num3 > 0f))
			{
				return;
			}
			__result = __result + "\n<color=" + value + ">Next sap in: " + TimeUtility.Format(num3) + "</color>";
			if (BatchTimersPlugin.ShowFullCapacityTime.Value)
			{
				int num4 = __instance.m_maxLevel - num;
				if (num4 > 1)
				{
					float seconds = num3 + __instance.m_secPerUnit * (float)(num4 - 1);
					__result += $"\n<color={value2}>Full ({__instance.m_maxLevel}/{__instance.m_maxLevel}) in: {TimeUtility.Format(seconds)}</color>";
				}
			}
		}
	}
	[HarmonyPatch(typeof(Switch), "GetHoverText")]
	public static class SmelterPatch
	{
		public static void Postfix(Switch __instance, ref string __result)
		{
			Smelter componentInParent = ((Component)__instance).GetComponentInParent<Smelter>();
			if ((Object)(object)componentInParent == (Object)null || !BatchTimersPlugin.EnableSmelters.Value || (Object)(object)componentInParent.m_nview == (Object)null || !componentInParent.m_nview.IsValid())
			{
				return;
			}
			int num = componentInParent.m_nview.GetZDO().GetInt(ZDOVars.s_queued, 0);
			if (num <= 0)
			{
				return;
			}
			float secPerProduct = componentInParent.m_secPerProduct;
			float bakeTimer = componentInParent.GetBakeTimer();
			float num2 = 1f;
			bool num3 = (Object)(object)componentInParent.m_windmill != (Object)null;
			if (num3)
			{
				num2 = componentInParent.m_windmill.GetPowerOutput();
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.WarningColor.Value;
			string value3 = BatchTimersPlugin.InfoColor.Value;
			int num4 = ((componentInParent.m_maxFuel > 0) ? Mathf.CeilToInt(componentInParent.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f)) : 0);
			if (num3 && num2 <= 0.02f)
			{
				__result = __result + "\n<color=" + value2 + ">Windmill: Paused (No wind)</color>";
			}
			else if (componentInParent.IsActive())
			{
				float num5 = Mathf.Max(0f, (secPerProduct - bakeTimer) / num2);
				__result = __result + "\n<color=" + value + ">Current item: " + TimeUtility.Format(num5) + "</color>";
				if (num > 1)
				{
					float seconds = num5 + secPerProduct * (float)(num - 1) / num2;
					string text = $"Queue ({num} items)";
					if (BatchTimersPlugin.EnableQueueInventoryPreview.Value)
					{
						string queueBreakdown = GetQueueBreakdown(componentInParent, num);
						if (!string.IsNullOrEmpty(queueBreakdown))
						{
							text = "Queue (" + queueBreakdown + ")";
						}
					}
					__result = __result + "\n<color=" + value3 + ">" + text + ": " + TimeUtility.Format(seconds) + "</color>";
				}
			}
			else if (componentInParent.m_requiresRoof && !componentInParent.m_haveRoof)
			{
				__result = __result + "\n<color=" + value2 + ">Warning: Needs a roof to operate!</color>";
			}
			else if (componentInParent.m_blockedSmoke)
			{
				__result = __result + "\n<color=" + value2 + ">Warning: Smoke is blocked!</color>";
			}
			else if (componentInParent.m_maxFuel > 0 && num4 == 0)
			{
				string text2 = (((Object)(object)componentInParent.m_fuelItem != (Object)null) ? componentInParent.m_fuelItem.m_itemData.m_shared.m_name : "Fuel");
				text2 = Localization.instance.Localize(text2);
				__result = __result + "\n<color=" + value2 + ">Out of " + text2 + "! Cannot smelt.</color>";
			}
			if (componentInParent.m_maxFuel > 0 && componentInParent.m_fuelPerProduct > 0 && componentInParent.IsActive())
			{
				int num6 = Mathf.CeilToInt((float)(num * componentInParent.m_fuelPerProduct));
				if (num4 < num6)
				{
					int num7 = num6 - num4;
					string text3 = (((Object)(object)componentInParent.m_fuelItem != (Object)null) ? componentInParent.m_fuelItem.m_itemData.m_shared.m_name : "Fuel");
					text3 = Localization.instance.Localize(text3);
					__result += $"\n<color={value2}>Warning: Needs {num7} more {text3}</color>";
				}
			}
		}

		private static string GetQueueBreakdown(Smelter smelter, int queueSize)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			for (int i = 0; i < queueSize; i++)
			{
				string text = smelter.m_nview.GetZDO().GetString("item" + i, "");
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				string text2 = text;
				if (smelter.m_conversion != null)
				{
					foreach (ItemConversion item in smelter.m_conversion)
					{
						if (item != null && (Object)(object)item.m_from != (Object)null && ((Object)((Component)item.m_from).gameObject).name == text)
						{
							text2 = item.m_from.m_itemData.m_shared.m_name;
							break;
						}
					}
				}
				text2 = Localization.instance.Localize(text2);
				if (dictionary.ContainsKey(text2))
				{
					dictionary[text2]++;
				}
				else
				{
					dictionary[text2] = 1;
				}
			}
			if (dictionary.Count == 0)
			{
				return "";
			}
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				list.Add($"{item2.Value}x {item2.Key}");
			}
			return string.Join(", ", list.ToArray());
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	public static class TameablePatch
	{
		private struct Tracker
		{
			public float LastZdoTime;

			public float RecordTime;
		}

		private static readonly Dictionary<ZDOID, Tracker> s_trackers = new Dictionary<ZDOID, Tracker>();

		public static void Postfix(Tameable __instance, ref string __result)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			if (!BatchTimersPlugin.EnableTaming.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || __instance.IsTamed())
			{
				return;
			}
			float num = __instance.GetRemainingTime();
			if (num <= 0f || (__instance.GetTameness() <= 0 && num >= __instance.m_tamingTime))
			{
				return;
			}
			string value = BatchTimersPlugin.TimerColor.Value;
			string value2 = BatchTimersPlugin.WarningColor.Value;
			bool flag = (Object)(object)__instance.m_monsterAI != (Object)null && ((BaseAI)__instance.m_monsterAI).IsAlerted();
			bool flag2 = __instance.IsHungry();
			bool flag3 = flag || flag2;
			ZDOID uid = __instance.m_nview.GetZDO().m_uid;
			float time = Time.time;
			if (!s_trackers.TryGetValue(uid, out var value3) || Mathf.Abs(value3.LastZdoTime - num) > 0.05f)
			{
				value3 = new Tracker
				{
					LastZdoTime = num,
					RecordTime = time
				};
				s_trackers[uid] = value3;
				if (s_trackers.Count > 100)
				{
					List<ZDOID> list = new List<ZDOID>();
					foreach (KeyValuePair<ZDOID, Tracker> s_tracker in s_trackers)
					{
						if (time - s_tracker.Value.RecordTime > 60f)
						{
							list.Add(s_tracker.Key);
						}
					}
					foreach (ZDOID item in list)
					{
						s_trackers.Remove(item);
					}
				}
			}
			float num2;
			if (flag3)
			{
				value3.RecordTime = time;
				s_trackers[uid] = value3;
				num2 = value3.LastZdoTime;
			}
			else
			{
				float num3 = time - value3.RecordTime;
				num2 = Mathf.Max(0f, value3.LastZdoTime - num3);
				if (num2 < value3.LastZdoTime - 3.5f)
				{
					num2 = value3.LastZdoTime - 3.5f;
				}
			}
			if (flag)
			{
				__result = __result + "\n<color=" + value2 + ">Tamed in: " + TimeUtility.Format(num2) + " (Paused - Frightened)</color>";
			}
			else if (flag2)
			{
				__result = __result + "\n<color=" + value2 + ">Tamed in: " + TimeUtility.Format(num2) + " (Paused - Hungry)</color>";
			}
			else
			{
				__result = __result + "\n<color=" + value + ">Tamed in: " + TimeUtility.Format(num2) + "</color>";
			}
		}
	}
}