The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of SpeedrunTimer v0.2.6
BepInEx/plugins/pharmacomaniac-SpeedrunTimer/SpeedrunTimer.dll
Decompiled 2 weeks agousing System; using System.Collections; 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.6.0")] [assembly: AssemblyInformationalVersion("0.2.6")] [assembly: AssemblyProduct("com.pharmacomaniac.SpeedrunTimer")] [assembly: AssemblyTitle("SpeedrunTimer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.6.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.6")] [BepInProcess("Peak.exe")] public class Plugin : BaseUnityPlugin { internal enum FontFamily { CourierNew, Consolas, LucidaConsole } 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 36f; } 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 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 result) { return (Mathf.Round(result / 0.05f) * 0.05f).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(SteamLobbyHandler), "LeaveLobby")] private static class LeaveLobbyPatch { private static bool Prefix() { Unbind(); return true; } } [HarmonyPatch(typeof(RunManager), "StartRun")] private static class StartRunPatch { private static void Postfix() { Bind(); } } [HarmonyPatch(typeof(GlobalEvents), "TriggerRunEnded")] private static class RunEndedPatch { private static void Postfix() { Log.LogInfo((object)"Run Ended"); StopTimers(); } } [HarmonyPatch(typeof(RunManager), "RPC_SyncTime")] private static class RPC_SyncTime_Patch { private static void Postfix(RunManager __instance, float time, bool timerActive) { if (timerActive && !timing) { float realtimeSinceStartup = Time.realtimeSinceStartup; ((MonoBehaviour)Instance).StartCoroutine(WatchLoadingScreenDestruction()); ((MonoBehaviour)Instance).StartCoroutine(StartAfterRealLoad(time)); } } private static IEnumerator WatchLoadingScreenDestruction() { while ((Object)(object)Object.FindObjectOfType<LoadingScreen>() != (Object)null) { yield return null; } _ = Time.realtimeSinceStartup; _ = RunManager.Instance.timeSinceRunStarted; } private static IEnumerator StartAfterRealLoad(float igtStartValue) { LoadingScreen val; while ((Object)(object)(val = Object.FindObjectOfType<LoadingScreen>()) != (Object)null && val.group.blocksRaycasts) { yield return null; } while ((Object)(object)GameObject.Find("MountainProgress") == (Object)null) { yield return null; } StartTimers(igtStartValue); } } internal static ManualLogSource Log; internal static ShowSplitsSetting showSplitsSetting; internal static ShowCurrentLevelSetting showCurrentLevelSetting; internal static FontSizeSetting fontSizeSetting; 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 float lastIgtValue; private static readonly TimerData igtTimer = new TimerData("IGT"); private const int defaultFontSize = 36; private const float STROKE_MIN = 0.05f; private const float STROKE_MAX = 0.5f; private static readonly int ID_OutlineWidth = ShaderUtilities.ID_OutlineWidth; private static readonly int ID_OutlineSoft = ShaderUtilities.ID_OutlineSoftness; private static readonly int ID_FaceDilate = ShaderUtilities.ID_FaceDilate; 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 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.5 initialized"); } private void Start() { //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_023f: 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(); 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)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) + " (IGT)"; } } catch (Exception arg) { Log.LogError((object)$"Failed to load Timer HUD: {arg}"); } } private void Update() { if (!timing || (Object)(object)mountainProgress == (Object)null) { return; } RunManager instance = RunManager.Instance; if ((Object)(object)instance != (Object)null) { igtTimer.totalTime = instance.timeSinceRunStarted; CheckSplitsOnly(igtTimer); lastIgtValue = igtTimer.totalTime; } TimerData timerData = igtTimer; if ((Object)(object)hud == (Object)null) { return; } 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) + " (IGT)"; ((TMP_Text)levelTxt).text = (ShowCurrentLevel ? currentLevelName : ""); } public void ApplySettings() { //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: 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 : 36f); ((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 = Mathf.Lerp(0.05f, 0.5f, Mathf.Clamp01(num)); TextMeshProUGUI[] array2 = (TextMeshProUGUI[])(object)new TextMeshProUGUI[3] { mainTxt, splitsTxt, levelTxt }; foreach (TextMeshProUGUI val2 in array2) { Material fontMaterial = ((TMP_Text)val2).fontMaterial; fontMaterial.SetFloat(ID_OutlineWidth, num2); fontMaterial.SetFloat(ID_FaceDilate, num2); fontMaterial.SetFloat(ID_OutlineSoft, 0.05f); ((TMP_Text)val2).UpdateMeshPadding(); } TextMeshProUGUI[] array3 = (TextMeshProUGUI[])(object)new TextMeshProUGUI[3] { mainTxt, splitsTxt, levelTxt }; foreach (TextMeshProUGUI val3 in array3) { ((TMP_Text)val3).characterSpacing = 1f; } float num3 = 1f - TopMarginRatio; RectTransform val4 = (RectTransform)hud.transform; val4.anchorMin = new Vector2(0.99f, num3); val4.anchorMax = new Vector2(0.99f, num3); val4.anchoredPosition = Vector2.zero; ((Component)splitsTxt).gameObject.SetActive(ShowSplits); TimerData timerData = igtTimer; ((TMP_Text)mainTxt).text = FormatTime(timerData.totalTime) + " (IGT)"; if ((Object)(object)backgroundImg != (Object)null) { ((Component)backgroundImg).gameObject.SetActive(ShowBackground); } } private static void CheckSplitsOnly(TimerData timer) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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) 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 StartTimers(float igtStartValue) { igtTimer.Reset(); LoadCampfires(); timing = true; Log.LogInfo((object)"[SRT] IGT timer started"); } private static void StopTimers() { timing = false; Log.LogInfo((object)("[SRT] IGT timer stopped. Final Time: " + FormatTime(igtTimer.totalTime))); } 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; } } 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; igtTimer.Reset(); currentLevelName = ""; } private static void Bind() { mountainProgress = GameObject.Find("MountainProgress"); if ((Object)(object)mountainProgress == (Object)null) { Log.LogWarning((object)"[SRT] Bind(): no MountainProgress in scene"); return; } Log.LogInfo((object)"[SRT] Bound MountainProgress"); progressScript = mountainProgress.GetComponentAtIndex(1); LoadCampfires(); } private static void Unbind() { timing = false; currentLevelName = ""; Log.LogInfo((object)"Unbound RunManager"); } private static void LoadCampfires() { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected I4, but got Unknown 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; } Campfire[] componentsInChildren = ((Component)val).GetComponentsInChildren<Campfire>(true); if (componentsInChildren.Length == 0) { Log.LogError((object)"No Campfire components found under Map."); return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; Campfire[] array = componentsInChildren; foreach (Campfire val2 in array) { if ((Object)(object)val2 == (Object)null || IsBlacklisted(((Component)val2).transform, val)) { continue; } int num5 = (HasBoolPropTrue(val2, "didAwake") ? 1 : 0) + (HasBoolPropTrue(val2, "didStart") ? 1 : 0); if (num5 == 0) { continue; } Segment advanceToSegment = val2.advanceToSegment; switch (advanceToSegment - 1) { case 0: if (num5 > num) { beachCampfire = val2; num = num5; } break; case 1: if (num5 > num2) { jungleCampfire = val2; num2 = num5; } break; case 2: if (num5 > num3) { snowCampfire = val2; num3 = num5; } break; case 3: if (num5 > num4) { volcanoCampfire = val2; num4 = num5; } break; } } if (!Object.op_Implicit((Object)(object)beachCampfire)) { Log.LogWarning((object)"Beach campfire not assigned."); } if (!Object.op_Implicit((Object)(object)jungleCampfire)) { Log.LogWarning((object)"Jungle campfire not assigned."); } if (!Object.op_Implicit((Object)(object)snowCampfire)) { Log.LogWarning((object)"Snow campfire not assigned."); } if (!Object.op_Implicit((Object)(object)volcanoCampfire)) { Log.LogWarning((object)"Volcano campfire not assigned."); } } private static bool IsBlacklisted(Transform t, Transform root) { string pathRelativeTo = GetPathRelativeTo(t, root); return pathRelativeTo.IndexOf("crashed plane", StringComparison.OrdinalIgnoreCase) >= 0; } private static string GetPathRelativeTo(Transform t, Transform root) { Stack<string> stack = new Stack<string>(); Transform val = t; while ((Object)(object)val != (Object)null) { stack.Push(((Object)val).name); if ((Object)(object)val == (Object)(object)root) { break; } val = val.parent; } return string.Join("/", stack); } private static bool HasBoolPropTrue(object obj, string propName) { try { PropertyInfo property = obj.GetType().GetProperty(propName, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanRead && property.PropertyType == typeof(bool)) { return (bool)property.GetValue(obj, null); } } catch { } return false; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }