Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ReadyWhen v1.0.0
ReadyWhen.dll
Decompiled a day agousing 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>"; } } } }