The BepInEx console will not appear when launching like it does for other games on Thunderstore. This is normal (and helps prevent crashes during startup). You can turn it back on in your BepInEx.cfg file.
Decompiled source of SpeedrunTimer v0.2.3
BepInEx/plugins/pharmacomaniac-SpeedrunTimer/SpeedrunTimer.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SettingsExtender; using TMPro; using Unity.Mathematics; using UnityEngine; using UnityEngine.Localization; using UnityEngine.UI; using Zorro.Core; using Zorro.Settings; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.pharmacomaniac.SpeedrunTimer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.3.0")] [assembly: AssemblyInformationalVersion("0.2.3")] [assembly: AssemblyProduct("com.pharmacomaniac.SpeedrunTimer")] [assembly: AssemblyTitle("SpeedrunTimer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace SpeedrunTimer { [BepInPlugin("com.pharmacomaniac.speedruntimer", "SpeedrunTimer", "0.2.2")] [BepInProcess("Peak.exe")] public class Plugin : BaseUnityPlugin { internal enum FontFamily { CourierNew, Consolas, LucidaConsole } internal enum TimingMethod { RTA, IGT } private enum Biome { Shore, Tropics, Alpine, Kiln } private class TimerData { public readonly string Name; public float totalTime; public float shoreTime; public float tropicsTime; public float alpineTime; public float kilnTime; public TimerData(string name) { Name = name; Reset(); } public void Reset() { totalTime = 0f; shoreTime = (tropicsTime = (alpineTime = (kilnTime = -1f))); } } private static class PTCategory { public static string Id => SettingsRegistry.GetPageId("SpeedrunTimer"); } internal class ShowSplitsSetting : BoolSetting, IExposedSetting { public override LocalizedString OnString => null; public override LocalizedString OffString => null; public string GetDisplayName() { return "Show Biome Splits"; } public string GetCategory() { return PTCategory.Id; } protected override bool GetDefaultValue() { return true; } public override void ApplyValue() { Instance?.ApplySettings(); } } internal class ShowCurrentLevelSetting : BoolSetting, IExposedSetting { public override LocalizedString OnString => null; public override LocalizedString OffString => null; public string GetDisplayName() { return "Show Current Level"; } public string GetCategory() { return PTCategory.Id; } protected override bool GetDefaultValue() { return true; } public override void ApplyValue() { Instance?.ApplySettings(); } } internal class FontSizeSetting : FloatSetting, IExposedSetting { public string GetDisplayName() { return "Font Size"; } public string GetCategory() { return PTCategory.Id; } protected override float GetDefaultValue() { return 30f; } protected override float2 GetMinMaxValue() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return new float2(12f, 72f); } public override void ApplyValue() { Instance?.ApplySettings(); } public override float Clamp(float value) { float num = Mathf.Round(value / 2f) * 2f; return Mathf.Clamp(num, ((FloatSetting)this).MinValue, ((FloatSetting)this).MaxValue); } public override string Expose(float result) { return (Mathf.Round(result / 2f) * 2f).ToString("F0"); } } internal class TopMarginSetting : FloatSetting, IExposedSetting { private const float Step = 0.02f; public string GetDisplayName() { return "Vertical Position"; } public string GetCategory() { return PTCategory.Id; } protected override float GetDefaultValue() { return 0.1f; } protected override float2 GetMinMaxValue() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return new float2(0f, 1f); } public override void ApplyValue() { Instance?.ApplySettings(); } public override float Clamp(float value) { float num = Mathf.Round(value / 0.02f) * 0.02f; return Mathf.Clamp(num, ((FloatSetting)this).MinValue, ((FloatSetting)this).MaxValue); } public override string Expose(float result) { float num = Mathf.Round(result / 0.02f) * 0.02f; return (num * 100f).ToString("F0") + "%"; } } internal class TimingMethodSetting : IntSetting, IEnumSetting, IExposedSetting { private readonly List<string> options = new List<string> { "RTA (Real Time)", "IGT (In-Game Time)" }; public string GetDisplayName() { return "Timing Method"; } public string GetCategory() { return PTCategory.Id; } protected override int GetDefaultValue() { return 0; } public override void ApplyValue() { Instance?.ApplySettings(); } public int GetValue() { return ((IntSetting)this).Value; } public void SetValue(int idx, ISettingHandler handler, bool fromUI) { ((IntSetting)this).SetValue(idx, handler); } public List<LocalizedString> GetLocalizedChoices() { return null; } public List<string> GetUnlocalizedChoices() { return options; } public override GameObject GetSettingUICell() { return SingletonAsset<InputCellMapper>.Instance.EnumSettingCell; } } internal class OutlineThicknessSetting : FloatSetting, IExposedSetting { private const float Step = 0.05f; public string GetDisplayName() { return "Outline Thickness"; } public string GetCategory() { return PTCategory.Id; } protected override float GetDefaultValue() { return 0.1f; } protected override float2 GetMinMaxValue() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return new float2(0f, 1f); } public override float Clamp(float value) { float num = Mathf.Round(value / 0.05f) * 0.05f; return Mathf.Clamp(num, ((FloatSetting)this).MinValue, ((FloatSetting)this).MaxValue); } public override string Expose(float value) { return value.ToString("F2"); } public override void ApplyValue() { Instance?.ApplySettings(); } } internal class FontFamilySetting : IntSetting, IEnumSetting, IExposedSetting { private static readonly List<string> options = new List<string> { "Courier New", "Consolas", "Lucida Console" }; public string GetDisplayName() { return "Font"; } public string GetCategory() { return PTCategory.Id; } protected override int GetDefaultValue() { return 1; } public int GetValue() { return ((IntSetting)this).Value; } public void SetValue(int idx, ISettingHandler h, bool ui) { ((IntSetting)this).SetValue(idx, h); } public List<LocalizedString> GetLocalizedChoices() { return null; } public List<string> GetUnlocalizedChoices() { return options; } public override GameObject GetSettingUICell() { return SingletonAsset<InputCellMapper>.Instance.EnumSettingCell; } public override void ApplyValue() { Instance?.ApplySettings(); } } internal class BackgroundToggleSetting : BoolSetting, IExposedSetting { public override LocalizedString OnString => null; public override LocalizedString OffString => null; public string GetDisplayName() { return "Show Timer Background"; } public string GetCategory() { return PTCategory.Id; } protected override bool GetDefaultValue() { return true; } public override void ApplyValue() { Instance?.ApplySettings(); } } internal class TotalTimeSplitSetting : BoolSetting, IExposedSetting { public override LocalizedString OnString => null; public override LocalizedString OffString => null; public string GetDisplayName() { return "Cumulative Split Timing"; } public string GetCategory() { return PTCategory.Id; } protected override bool GetDefaultValue() { return true; } public override void ApplyValue() { Instance?.ApplySettings(); } } [HarmonyPatch(typeof(MapBaker), "GetLevel")] private static class MapBaker_GetLevel_Patch { private static void Postfix(ref string __result) { if (!string.IsNullOrEmpty(__result)) { currentLevelName = __result; Log.LogInfo((object)("Final level name from MapBaker set to: " + currentLevelName)); } } } [HarmonyPatch(typeof(PauseOptionsMenu), "OnOpen")] private static class PauseOpenPatch { private static void Postfix() { Log.LogInfo((object)"IGT timer paused."); isIgtPaused = true; } } [HarmonyPatch(typeof(PauseOptionsMenu), "OnClose")] private static class PauseClosePatch { private static void Postfix() { Log.LogInfo((object)"IGT timer unpaused."); isIgtPaused = false; } } [HarmonyPatch(typeof(SteamLobbyHandler), "LeaveLobby")] private static class LeaveLobbyPatch { private static bool Prefix() { Unbind(); return true; } } [HarmonyPatch(typeof(RunManager), "StartRun")] private static class StartRunPatch { private static bool Prefix() { Bind(); return true; } } [HarmonyPatch(typeof(GlobalEvents), "TriggerRunEnded")] private static class RunEndedPatch { private static bool Prefix() { Log.LogInfo((object)"Run Ended"); timing = false; return true; } } internal static ManualLogSource Log; internal static ShowSplitsSetting showSplitsSetting; internal static ShowCurrentLevelSetting showCurrentLevelSetting; internal static FontSizeSetting fontSizeSetting; internal static TimingMethodSetting timingMethodSetting; internal static TopMarginSetting topMarginSetting; internal static OutlineThicknessSetting outlineThicknessSetting; internal static FontFamilySetting fontFamilySetting; internal static BackgroundToggleSetting backgroundToggleSetting; internal static TotalTimeSplitSetting totalTimeSplitSetting; private static GameObject mountainProgress; private static Component progressScript; private static Campfire beachCampfire; private static Campfire jungleCampfire; private static Campfire snowCampfire; private static Campfire volcanoCampfire; private static string currentLevelName = ""; private static bool timing; private static bool isIgtPaused; private static float timerStartDelay; private static readonly TimerData rtaTimer = new TimerData("RTA"); private static readonly TimerData igtTimer = new TimerData("IGT"); private const int defaultFontSize = 30; private GameObject hud; private TextMeshProUGUI mainTxt; private TextMeshProUGUI splitsTxt; private TextMeshProUGUI levelTxt; private Image backgroundImg; private static readonly Dictionary<FontFamily, TMP_FontAsset> fontAssets = new Dictionary<FontFamily, TMP_FontAsset>(); public static Plugin Instance { get; private set; } internal static bool ShowSplits { get { ShowSplitsSetting obj = showSplitsSetting; if (obj == null) { return true; } return ((BoolSetting)obj).Value; } } internal static bool ShowCurrentLevel { get { ShowCurrentLevelSetting obj = showCurrentLevelSetting; if (obj == null) { return true; } return ((BoolSetting)obj).Value; } } internal static float TopMarginRatio { get { TopMarginSetting obj = topMarginSetting; if (obj == null) { return 0.1f; } return ((FloatSetting)obj).Value; } } internal static TimingMethod CurrentTimingMethod { get { TimingMethodSetting obj = timingMethodSetting; if (obj == null) { return TimingMethod.RTA; } return (TimingMethod)((IntSetting)obj).Value; } } internal static FontFamily CurrentFont { get { FontFamilySetting obj = fontFamilySetting; if (obj == null) { return FontFamily.Consolas; } return (FontFamily)((IntSetting)obj).Value; } } internal static bool ShowBackground { get { BackgroundToggleSetting obj = backgroundToggleSetting; if (obj == null) { return true; } return ((BoolSetting)obj).Value; } } internal static bool UseTotalTimeForSplits { get { TotalTimeSplitSetting obj = totalTimeSplitSetting; if (obj == null) { return true; } return ((BoolSetting)obj).Value; } } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) Instance = this; Init(); Log = ((BaseUnityPlugin)this).Logger; new Harmony("com.pharmacomaniac.speedruntimer").PatchAll(); SettingsRegistry.Register("SpeedrunTimer"); Log.LogInfo((object)"SpeedrunTimer 0.2.2 initialized"); } private void Start() { //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Expected O, but got Unknown //IL_0254: Unknown result type (might be due to invalid IL or missing references) if (SettingsHandler.Instance == null) { return; } showSplitsSetting = new ShowSplitsSetting(); showCurrentLevelSetting = new ShowCurrentLevelSetting(); fontSizeSetting = new FontSizeSetting(); fontFamilySetting = new FontFamilySetting(); timingMethodSetting = new TimingMethodSetting(); topMarginSetting = new TopMarginSetting(); outlineThicknessSetting = new OutlineThicknessSetting(); backgroundToggleSetting = new BackgroundToggleSetting(); totalTimeSplitSetting = new TotalTimeSplitSetting(); SettingsHandler instance = SettingsHandler.Instance; instance.AddSetting((Setting)(object)showSplitsSetting); instance.AddSetting((Setting)(object)showCurrentLevelSetting); instance.AddSetting((Setting)(object)fontSizeSetting); instance.AddSetting((Setting)(object)fontFamilySetting); instance.AddSetting((Setting)(object)timingMethodSetting); instance.AddSetting((Setting)(object)topMarginSetting); instance.AddSetting((Setting)(object)outlineThicknessSetting); instance.AddSetting((Setting)(object)backgroundToggleSetting); instance.AddSetting((Setting)(object)totalTimeSplitSetting); try { string location = Assembly.GetExecutingAssembly().Location; string directoryName = Path.GetDirectoryName(location); string text = Path.Combine(directoryName, "speedtimer_ui"); Log.LogInfo((object)("[DEBUG] Attempting to load AssetBundle at: " + text)); AssetBundle val = AssetBundle.LoadFromFile(text); if ((Object)(object)val == (Object)null) { Log.LogError((object)("UI bundle not found or invalid at " + text)); return; } fontAssets[FontFamily.CourierNew] = val.LoadAsset<TMP_FontAsset>("assets/fonts/cour_sdf.asset"); fontAssets[FontFamily.Consolas] = val.LoadAsset<TMP_FontAsset>("assets/fonts/consola_sdf.asset"); fontAssets[FontFamily.LucidaConsole] = val.LoadAsset<TMP_FontAsset>("assets/fonts/lucon_sdf.asset"); if (fontAssets.Values.Any((TMP_FontAsset a) => (Object)(object)a == (Object)null)) { Log.LogWarning((object)"One or more fontAssets failed to load; will use prefab default."); } GameObject val2 = val.LoadAsset<GameObject>("assets/speedtimerui/timerstack.prefab"); if ((Object)(object)val2 == (Object)null) { Log.LogError((object)"Prefab 'assets/speedtimerui/timerstack.prefab' not found inside bundle."); return; } GameObject val3 = new GameObject("SpeedrunTimerCanvas", new Type[3] { typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) }); Object.DontDestroyOnLoad((Object)(object)val3); Canvas component = val3.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 5000; CanvasScaler component2 = val3.GetComponent<CanvasScaler>(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1920f, 1080f); hud = Object.Instantiate<GameObject>(val2, val3.transform); ((Object)hud).name = "TimerStack"; Transform obj = hud.transform.Find("MainTimer"); mainTxt = ((obj != null) ? ((Component)obj).GetComponent<TextMeshProUGUI>() : null); Transform obj2 = hud.transform.Find("SplitsBlock"); splitsTxt = ((obj2 != null) ? ((Component)obj2).GetComponent<TextMeshProUGUI>() : null); Transform obj3 = hud.transform.Find("LevelName"); levelTxt = ((obj3 != null) ? ((Component)obj3).GetComponent<TextMeshProUGUI>() : null); Transform obj4 = hud.transform.Find("Background"); backgroundImg = ((obj4 != null) ? ((Component)obj4).GetComponent<Image>() : null); if ((Object)(object)backgroundImg == (Object)null) { Log.LogWarning((object)"[DEBUG] Background image not found – check prefab hierarchy."); } if ((Object)(object)mainTxt == (Object)null || (Object)(object)splitsTxt == (Object)null || (Object)(object)levelTxt == (Object)null) { Log.LogWarning((object)"[DEBUG] One or more TMP children not found; check names in prefab."); } ApplySettings(); if ((Object)(object)levelTxt != (Object)null) { ((TMP_Text)levelTxt).text = ""; } if ((Object)(object)mainTxt != (Object)null) { ((TMP_Text)mainTxt).text = $"{FormatTime(0f)} ({CurrentTimingMethod})"; } } catch (Exception arg) { Log.LogError((object)$"Failed to load Timer HUD: {arg}"); } } private void Update() { if (timerStartDelay > 0f) { timerStartDelay -= Time.unscaledDeltaTime; if (timerStartDelay <= 0f) { timerStartDelay = -1f; timing = true; } } if (!timing || (Object)(object)mountainProgress == (Object)null) { return; } UpdateTimerState(rtaTimer, Time.unscaledDeltaTime); if (!isIgtPaused) { UpdateTimerState(igtTimer, Time.deltaTime); } if ((Object)(object)hud == (Object)null) { return; } TimerData timerData = ((CurrentTimingMethod == TimingMethod.RTA) ? rtaTimer : igtTimer); if (ShowSplits) { if (UseTotalTimeForSplits) { ((TMP_Text)splitsTxt).text = "Shore " + FormatTime(timerData.shoreTime) + "\nTropics " + FormatTime(timerData.tropicsTime) + "\nAlpine " + FormatTime(timerData.alpineTime) + "\nThe Kiln " + FormatTime(timerData.kilnTime); } else { float shoreTime = timerData.shoreTime; float t = ((timerData.tropicsTime >= 0f) ? (timerData.tropicsTime - timerData.shoreTime) : (-1f)); float t2 = ((timerData.alpineTime >= 0f) ? (timerData.alpineTime - timerData.tropicsTime) : (-1f)); float t3 = ((timerData.kilnTime >= 0f) ? (timerData.kilnTime - timerData.alpineTime) : (-1f)); ((TMP_Text)splitsTxt).text = "Shore " + FormatTime(shoreTime) + "\nTropics " + FormatTime(t) + "\nAlpine " + FormatTime(t2) + "\nThe Kiln " + FormatTime(t3); } } else { ((TMP_Text)splitsTxt).text = ""; } ((TMP_Text)mainTxt).text = $"{FormatTime(timerData.totalTime)} ({CurrentTimingMethod})"; ((TMP_Text)levelTxt).text = (ShowCurrentLevel ? currentLevelName : ""); } public void ApplySettings() { //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hud == (Object)null) { return; } if (fontAssets.TryGetValue(CurrentFont, out var value)) { TextMeshProUGUI[] array = (TextMeshProUGUI[])(object)new TextMeshProUGUI[3] { mainTxt, splitsTxt, levelTxt }; foreach (TextMeshProUGUI val in array) { ((TMP_Text)val).font = value; } } FontSizeSetting obj = fontSizeSetting; float fontSize = ((obj != null) ? ((FloatSetting)obj).Value : 30f); ((TMP_Text)mainTxt).fontSize = fontSize; ((TMP_Text)splitsTxt).fontSize = fontSize; ((TMP_Text)levelTxt).fontSize = fontSize; OutlineThicknessSetting obj2 = outlineThicknessSetting; float num = ((obj2 != null) ? ((FloatSetting)obj2).Value : 0.1f); float num2 = num * 0.2f; TextMeshProUGUI[] array2 = (TextMeshProUGUI[])(object)new TextMeshProUGUI[3] { mainTxt, splitsTxt, levelTxt }; foreach (TextMeshProUGUI val2 in array2) { Material fontSharedMaterial = ((TMP_Text)val2).fontSharedMaterial; fontSharedMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, num2); fontSharedMaterial.SetFloat(ShaderUtilities.ID_OutlineSoftness, 0.05f); } float num3 = 1f - TopMarginRatio; RectTransform val3 = (RectTransform)hud.transform; val3.anchorMin = new Vector2(0.99f, num3); val3.anchorMax = new Vector2(0.99f, num3); val3.anchoredPosition = Vector2.zero; ((Component)splitsTxt).gameObject.SetActive(ShowSplits); TimerData timerData = ((CurrentTimingMethod == TimingMethod.RTA) ? rtaTimer : igtTimer); ((TMP_Text)mainTxt).text = $"{FormatTime(timerData.totalTime)} ({CurrentTimingMethod})"; if ((Object)(object)backgroundImg != (Object)null) { ((Component)backgroundImg).gameObject.SetActive(ShowBackground); } } private void UpdateTimerState(TimerData timer, float deltaTime) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) timer.totalTime += deltaTime; if (timer.shoreTime < 0f && (Object)(object)beachCampfire != (Object)null && (int)beachCampfire.state != 0) { RecordSplit(timer, Biome.Shore); } if (timer.tropicsTime < 0f && (Object)(object)jungleCampfire != (Object)null && (int)jungleCampfire.state != 0) { RecordSplit(timer, Biome.Tropics); } if (timer.alpineTime < 0f && (Object)(object)snowCampfire != (Object)null && (int)snowCampfire.state != 0) { RecordSplit(timer, Biome.Alpine); } if (timer.kilnTime < 0f && (Object)(object)volcanoCampfire != (Object)null && (int)volcanoCampfire.state != 0) { RecordSplit(timer, Biome.Kiln); } } private static void RecordSplit(TimerData timer, Biome biome) { float totalTime = timer.totalTime; switch (biome) { case Biome.Shore: timer.shoreTime = totalTime; break; case Biome.Tropics: timer.tropicsTime = totalTime; break; case Biome.Alpine: timer.alpineTime = totalTime; break; case Biome.Kiln: timer.kilnTime = totalTime; break; } Log.LogInfo((object)$"Split for {biome} ({timer.Name}) recorded: {FormatTime(totalTime)}"); } private static string FormatTime(float t) { if (t < 0f) { return "--:--:--.-"; } int num = (int)(t / 3600f); t -= (float)num * 3600f; int num2 = (int)(t / 60f); t -= (float)num2 * 60f; int num3 = (int)t; int num4 = (int)((t - (float)num3) * 10f); return $"{num:00}:{num2:00}:{num3:00}.{num4:0}"; } private void Init() { timing = false; isIgtPaused = false; rtaTimer.Reset(); igtTimer.Reset(); timerStartDelay = -1f; currentLevelName = ""; } private static void Bind() { mountainProgress = GameObject.Find("MountainProgress"); timing = false; if ((Object)(object)mountainProgress == (Object)null) { Log.LogWarning((object)"No MountainProgress"); return; } Log.LogInfo((object)"Bound MountainProgress"); progressScript = mountainProgress.GetComponentAtIndex(1); timerStartDelay = 6f; if ((Object)(object)progressScript == (Object)null) { Log.LogWarning((object)"No progressScript"); } LoadCampfires(); rtaTimer.Reset(); igtTimer.Reset(); } private static void Unbind() { mountainProgress = null; progressScript = null; timing = false; currentLevelName = ""; Log.LogInfo((object)"Unbound RunManager"); } private static void LoadCampfires() { beachCampfire = null; jungleCampfire = null; snowCampfire = null; volcanoCampfire = null; GameObject obj = GameObject.Find("Map"); Transform val = ((obj != null) ? obj.transform : null); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Map root GameObject not found. Cannot load campfires."); return; } Dictionary<Biome, string> dictionary = new Dictionary<Biome, string> { { Biome.Shore, "Beach_Campfire/Campfire/Campfire" }, { Biome.Tropics, "Jungle_Campfire/Campfire/Campfire" }, { Biome.Alpine, "Snow_Campfire/Campfire/Campfire" }, { Biome.Kiln, "Volcano/Volcano/Enterance/CampfireSpawner_Volcano/Campfire/Campfire" } }; foreach (KeyValuePair<Biome, string> item in dictionary) { Biome key = item.Key; string value = item.Value; Transform val2 = val.Find(value); if ((Object)(object)val2 == (Object)null) { Log.LogError((object)$"Campfire for {key} not found at path: Map/{value}"); continue; } Campfire[] components = ((Component)val2).GetComponents<Campfire>(); if (components.Length == 0) { Log.LogWarning((object)$"Campfire object for {key} found, but it has no Campfire components."); continue; } Campfire val3 = components[0]; switch (key) { case Biome.Shore: beachCampfire = val3; break; case Biome.Tropics: jungleCampfire = val3; break; case Biome.Alpine: snowCampfire = val3; break; case Biome.Kiln: volcanoCampfire = val3; break; } } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }