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 CDEV HoverInfo v0.1.0
plugins\CDEV.HoverInfo\CDEV.HoverInfo.dll
Decompiled 2 weeks agousing 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) { } } }