using System; using System.Collections; 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 System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CustomTimer.Config; using CustomTimer.Core; using CustomTimer.Detect; using CustomTimer.Net; using CustomTimer.Patch; using CustomTimer.UI; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Kai")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d9182f8f23da47ea970b38df06f64abb63ec16f9")] [assembly: AssemblyProduct("CustomTimer")] [assembly: AssemblyTitle("CustomTimer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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 CustomTimer { [BepInPlugin("Kai.CustomTimer", "CustomTimer", "0.2.0")] public class CustomTimer : BaseUnityPlugin { private float _syncElapsed; private const float SYNC_INTERVAL = 10f; internal static CustomTimer Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Patch(); new TimerManager(); TimerConfig.Bind(((BaseUnityPlugin)this).Config); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); } internal void Patch() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0025: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); } private void Update() { TimerManager instance = TimerManager.Instance; if (instance == null || !instance.IsActive || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } instance.Tick(Time.deltaTime); RoundDirector instance2 = RoundDirector.instance; if (Object.op_Implicit((Object)(object)instance2) && instance2.allExtractionPointsCompleted && !TimerState.BlackoutHandled) { if (TimerConfigValues.EnableBlackoutOverride) { instance.ApplyForcedTime(TimerConfigValues.BlackoutOverrideSeconds); if (SemiFunc.IsMultiplayer()) { CustomTimerNet.Instance.SyncTimer(instance.CurrentTime); } } TimerState.BlackoutHandled = true; } _syncElapsed += Time.deltaTime; if (_syncElapsed >= 10f) { _syncElapsed = 0f; CustomTimerNet.Instance.SyncTimer(instance.CurrentTime); } } } internal static class TimerLog { private static ManualLogSource _log => CustomTimer.Logger; public static void Info(string message) { _log.LogInfo((object)message); } public static void Warn(string message) { _log.LogWarning((object)message); } public static void Error(string message) { _log.LogError((object)message); } public static void Debug(string message) { if (TimerConfigValues.DebugLog) { _log.LogInfo((object)("[Debug] " + message)); } } } } namespace CustomTimer.UI { internal class CustomTimerUI : SemiUI { [CompilerGenerated] private sealed class d__4 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public CustomTimerUI <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; CustomTimerUI customTimerUI = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)AssetManager.instance == (Object)null) { <>2__current = null; <>1__state = 1; return true; } customTimerUI.text = ((Component)customTimerUI).GetComponent(); if ((Object)(object)customTimerUI.text == (Object)null) { customTimerUI.text = ((Component)customTimerUI).GetComponentInChildren(true); } if ((Object)(object)customTimerUI.text == (Object)null) { CustomTimer.Logger.LogWarning((object)"[CustomTimerUI] TextMeshProUGUI not found"); ((Behaviour)customTimerUI).enabled = false; return false; } ((SemiUI)customTimerUI).uiText = customTimerUI.text; ((SemiUI)customTimerUI).textRectTransform = (Transform)(object)((Component)customTimerUI.text).GetComponent(); if (((SemiUI)customTimerUI).doNotDisable == null) { ((SemiUI)customTimerUI).doNotDisable = new List(); } customTimerUI.<>n__0(); ((TMP_Text)customTimerUI.text).richText = true; TextMeshProUGUI text = customTimerUI.text; ((TMP_Text)text).margin = ((TMP_Text)text).margin + new Vector4(0f, 0f, -500f, 0f); TextMeshProUGUI text2 = customTimerUI.text; ((TMP_Text)text2).fontSize = ((TMP_Text)text2).fontSize * 0.833f; if ((Object)(object)BigMessageUI.instance != (Object)null) { TextMeshProUGUI value = Traverse.Create((object)BigMessageUI.instance).Field("emojiText").GetValue(); if ((Object)(object)value != (Object)null) { ((TMP_Text)customTimerUI.text).spriteAsset = ((TMP_Text)value).spriteAsset; TimerLog.Debug("[CustomTimerUI] SpriteAsset linked (BigMessageUI)"); } else { CustomTimer.Logger.LogWarning((object)"[CustomTimerUI] BigMessageUI emojiText is null"); } } ((SemiUI)customTimerUI).Hide(); customTimerUI.ready = true; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private TextMeshProUGUI text; private float lastTime = -1f; private bool ready; public override void Start() { ((MonoBehaviour)this).StartCoroutine(StartRoutine()); } [IteratorStateMachine(typeof(d__4))] private IEnumerator StartRoutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__4(0) { <>4__this = this }; } public override void Update() { if (!ready || (Object)(object)text == (Object)null) { return; } ((SemiUI)this).Update(); TimerManager instance = TimerManager.Instance; bool flag = instance?.IsActive ?? false; bool flag2 = (Object)(object)StatsUI.instance != (Object)null && ((SemiUI)StatsUI.instance).showTimer > 0f; if (!flag || !TimerConfigValues.EnableHUD || flag2) { ((TMP_Text)text).text = ""; ((SemiUI)this).Hide(); return; } ((SemiUI)this).Show(); float num = Mathf.Max(0f, instance.CurrentTime); if (!(Mathf.Abs(num - lastTime) < 0.01f)) { lastTime = num; int num2 = Mathf.FloorToInt(num / 60f); int num3 = Mathf.FloorToInt(num % 60f); int num4 = Mathf.FloorToInt(num * 1000f % 1000f); string timeColorTag = GetTimeColorTag(num); ((TMP_Text)text).text = " " + timeColorTag + $"{num2:00}:{num3:00}.{num4:000}" + (string.IsNullOrEmpty(timeColorTag) ? "" : ""); } } private string GetTimeColorTag(float time) { TimerManager instance = TimerManager.Instance; if (instance != null && instance.IsPaused) { return ""; } if (time <= 30f) { return ""; } if (time <= 60f) { return ""; } return ""; } private void OnEnable() { if (TimerManager.Instance != null) { TimerManager.Instance.TimeUpEvent += OnTimeUp; } } private void OnDisable() { if (TimerManager.Instance != null) { TimerManager.Instance.TimeUpEvent -= OnTimeUp; } } private void OnTimeUp() { ForceZero(); } private void ForceZero() { if (!((Object)(object)text == (Object)null)) { ((TMP_Text)text).text = " 00:00.000"; } } [CompilerGenerated] [DebuggerHidden] private void <>n__0() { ((SemiUI)this).Start(); } } internal static class TimerUIFactory { private const string UI_NAME = "CustomTimerTimerUI"; public static GameObject CreateOrGet() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("CustomTimerTimerUI"); if ((Object)(object)val != (Object)null) { TimerLog.Debug("[CustomTimer] Timer UI already exists"); return val; } GameObject val2 = GameObject.Find("Energy"); if ((Object)(object)val2 == (Object)null) { CustomTimer.Logger.LogWarning((object)"[CustomTimer] Energy UI not found"); return null; } GameObject val3 = Object.Instantiate(val2, val2.transform.parent); ((Object)val3).name = "CustomTimerTimerUI"; Transform transform = val3.transform; transform.localPosition -= new Vector3(25f, 80f, 0f); EnergyUI val4 = default(EnergyUI); if (val3.TryGetComponent(ref val4)) { ((Behaviour)val4).enabled = false; } Transform val5 = val3.transform.Find("EnergyMax"); if ((Object)(object)val5 != (Object)null) { TextMeshProUGUI component = ((Component)val5).GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } } Image componentInChildren = val3.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { ((Behaviour)componentInChildren).enabled = false; } TextMeshProUGUI[] componentsInChildren = val3.GetComponentsInChildren(true); foreach (TextMeshProUGUI val6 in componentsInChildren) { ((Graphic)val6).color = Color.white; } val3.AddComponent(); TimerLog.Debug("[CustomTimer] Timer UI created"); return val3; } } } namespace CustomTimer.Patch { [HarmonyPatch(typeof(ChatManager), "MessageSend")] internal static class ChatManager_MessageSend_Patch { [HarmonyPrefix] private static bool Prefix(ChatManager __instance, bool _possessed) { string chatMessage = __instance.chatMessage; if (string.IsNullOrWhiteSpace(chatMessage) || !chatMessage.StartsWith("/")) { return true; } if (CustomTimerCommand.TryHandle(chatMessage)) { __instance.chatMessage = ""; return false; } return true; } } internal static class CustomTimerCommand { public static bool TryHandle(string message) { string[] array = message.Split(' '); switch (array[0].ToLowerInvariant()) { case "/time": HandleTime(); return true; case "/timeset": HandleTimeSet(array); return true; case "/timemapset": HandleTimeMapSet(array); return true; default: return false; } } private static void HandleTime() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { CustomTimer.Logger.LogInfo((object)"[Timer] Host only command"); return; } TimerManager.Instance.TogglePause(); CustomTimerNet.Instance.SyncTimer(TimerManager.Instance.CurrentTime); CustomTimerNet.Instance.BroadcastPause(TimerManager.Instance.IsPaused); } private static void HandleTimeSet(string[] args) { int result; if (!SemiFunc.IsMasterClientOrSingleplayer()) { CustomTimer.Logger.LogInfo((object)"[Timer] Host only command"); } else if (args.Length >= 2 && int.TryParse(args[1], out result)) { TimerManager.Instance.ApplyForcedTime(result); CustomTimerNet.Instance.SyncTimer(TimerManager.Instance.CurrentTime); } } private static void HandleTimeMapSet(string[] args) { int result; if (!SemiFunc.IsMasterClientOrSingleplayer()) { CustomTimer.Logger.LogInfo((object)"[Timer] Host only command"); } else if (args.Length >= 2 && int.TryParse(args[1], out result)) { string currentLevelName = LevelContext.CurrentLevelName; if (StageCategoryResolver.Resolve(currentLevelName) == StageCategory.Other) { TimerConfig.AddOrUpdateStageOverride(currentLevelName, result); } } } } [HarmonyPatch(typeof(ExtractionPoint), "StateSet")] internal static class ExtractionPoint_StateSet_Patch { [CompilerGenerated] private sealed class d__1 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(5f); <>1__state = 1; return true; case 1: <>1__state = -1; if (TimerState.BlackoutHandled) { TimerLog.Debug("[Timer] TimeUpComplete ignored: blackout already handled"); TimerState.TimeUpOccurred = false; return false; } if (AnyPlayerAlive()) { TimerManager.Instance.ApplySurvivorBonusTime(TimerConfigValues.ExtractionBonusTime); CustomTimerNet.Instance.SyncTimer(TimerManager.Instance.CurrentTime); TimerLog.Debug("[Timer] TimeUpComplete: survivor found → resume with bonus"); } else { TimerLog.Debug("[Timer] TimeUpComplete: no survivor"); } TimerState.TimeUpOccurred = false; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static void Prefix(ExtractionPoint __instance, State newState) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Invalid comparison between Unknown and I4 if ((int)newState == 2) { if (!TimerState.Started && SemiFunc.IsMasterClientOrSingleplayer() && StageFilter.IsPlayableStage()) { TimerState.Started = true; TimerState.Finished = false; ExtractionBonusTracker.Reset(); TimerLog.Debug("[Timer] Started on level: " + LevelContext.CurrentLevelName); int initialSeconds = InitialTimeCalculator.Calculate(); TimerManager.Instance.Initialize(initialSeconds); CustomTimerNet.Instance.SyncTimer(TimerManager.Instance.CurrentTime); TimerChatNotifier.Instance.NotifyTimerStart(TimerManager.Instance.CurrentTime); } return; } if ((int)newState == 3) { TimerState.ExtractionInProgress = true; } if ((int)newState == 5) { if (TimerState.Started) { TimerState.ExtractionInProgress = false; if (TimerState.TimeUpPenalty) { TimerState.TimeUpPenalty = false; TimerLog.Debug("[Timer] TimeUp triggered on Cancel"); TimerManager.Instance.ForceTimeUp(); } } } else if ((int)newState == 7) { if (TimerState.TimeUpOccurred && SemiFunc.IsMasterClientOrSingleplayer()) { ((MonoBehaviour)CustomTimer.Instance).StartCoroutine(TimeUpCompleteCheckFlow()); } if (TimerState.Started && ExtractionBonusTracker.TryMark(__instance)) { TimerManager.Instance.SetPaused(paused: false); TimerState.ExtractionInProgress = false; TimerState.TimeUpPenalty = false; float num = TimerConfigValues.ExtractionBonusTime; TimerManager.Instance.AddTime(num); CustomTimerNet.Instance.SyncTimer(TimerManager.Instance.CurrentTime); TimerLog.Debug($"[Timer] COMPLETE → +{num}s & RESUME"); } } } [IteratorStateMachine(typeof(d__1))] private static IEnumerator TimeUpCompleteCheckFlow() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0); } private static bool AnyPlayerAlive() { foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (!((Object)(object)player == (Object)null) && !player.deadSet) { return true; } } return false; } } internal static class ExtractionBonusTracker { private static HashSet _processed = new HashSet(); public static bool TryMark(ExtractionPoint ep) { int instanceID = ((Object)ep).GetInstanceID(); if (_processed.Contains(instanceID)) { return false; } _processed.Add(instanceID); return true; } public static void Reset() { _processed.Clear(); } } [HarmonyPatch(typeof(GoalUI), "Start")] internal static class GoalUI_Start_Patch { [HarmonyPostfix] private static void Postfix() { if (SemiFunc.RunIsLevel() && TimerConfigValues.Enabled) { TimerLog.Debug("[CustomTimer] GoalUI.Start → create Timer UI"); TimerReset.ResetAll(); TimerUIFactory.CreateOrGet(); } } } [HarmonyPatch(typeof(PunManager), "Awake")] internal class PunManager_Awake_Patch { private static void Postfix(PunManager __instance) { if (!((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); TimerLog.Debug("[CustomTimer] CustomTimerNet attached to PunManager"); } } } } namespace CustomTimer.Net { public class CustomTimerNet : MonoBehaviourPun { public static CustomTimerNet Instance { get; private set; } private void Awake() { Instance = this; } public void SyncTimer(float currentTime) { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.IsMultiplayer()) { ((MonoBehaviourPun)this).photonView.RPC("RPC_CustomTimer_SyncTime", (RpcTarget)1, new object[2] { currentTime, PhotonNetwork.Time }); } } [PunRPC] private void RPC_CustomTimer_SyncTime(float serverTime, double sentAt) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { TimerManager.Instance.ApplyRemoteSync(serverTime, sentAt); } } public void BroadcastSetTime(float newTime) { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.IsMultiplayer()) { ((MonoBehaviourPun)this).photonView.RPC("RPC_CustomTimer_SetTime", (RpcTarget)0, new object[1] { newTime }); } } [PunRPC] private void RPC_CustomTimer_SetTime(float newTime) { TimerManager.Instance.ApplyForcedTime(newTime); } public void BroadcastPause(bool paused) { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.IsMultiplayer()) { ((MonoBehaviourPun)this).photonView.RPC("RPC_CustomTimer_SetPause", (RpcTarget)1, new object[1] { paused }); } } [PunRPC] private void RPC_CustomTimer_SetPause(bool paused) { TimerManager.Instance.SetPaused(paused); } } } namespace CustomTimer.Detect { internal static class LevelDetector { private static string _lastLevel = ""; public static bool DetectLevelChange() { LevelContext.UpdateCurrentLevel(); if (LevelContext.CurrentLevelName != _lastLevel) { _lastLevel = LevelContext.CurrentLevelName; return true; } return false; } } [HarmonyPatch(typeof(SemiFunc), "OnLevelGenDone")] internal static class LevelGenDonePatch { private static void Postfix() { if (SemiFunc.IsMasterClientOrSingleplayer()) { LevelContext.UpdateCurrentLevel(); TimerLog.Debug("[Timer] LevelGenDone → level='" + LevelContext.CurrentLevelName + "'"); TimerReset.ResetAll(); } } } internal static class StageFilter { public static bool IsPlayableStage() { if (SemiFunc.IsMainMenu()) { return false; } if (!SemiFunc.RunIsLevel()) { return false; } return true; } } } namespace CustomTimer.Config { internal enum TimeUpAction { KillAll, ReloadImmediate, KillNonTruckPlayers } internal static class TimerConfig { public static ConfigEntry Enabled; public static ConfigEntry BaseInitialTime; public static ConfigEntry ExtractionBonusTime; public static ConfigEntry TimeUpActionMode; public static ConfigEntry EnableHUD; public static ConfigEntry DebugLog; public static ConfigEntry StageBonus_Museum; public static ConfigEntry StageBonus_Manor; public static ConfigEntry StageBonus_Arctic; public static ConfigEntry StageBonus_Wizard; public static ConfigEntry StageBonus_Other; public static ConfigEntry StageTimeOverrides; public static ConfigEntry EnablePlayerScaling; public static ConfigEntry PlayerScalingThreshold; public static ConfigEntry PlayerScalingSecondsPerPlayer; public static ConfigEntry EnableBlackoutOverride; public static ConfigEntry BlackoutOverrideSeconds; public static ConfigEntry EnableTimeCap; public static ConfigEntry MaxTimeSeconds; public static ConfigEntry EnableChatNotify; public static ConfigEntry EnableTruckNotify; public static ConfigEntry EnableChatThreshold; public static ConfigEntry ChatNotifyThresholdSeconds; public static ConfigEntry EnableChatCountdown; public static ConfigEntry EnableChatBonusNotify; public static ConfigEntry ChatNotifyCooldownSeconds; internal static void Bind(ConfigFile config) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Expected O, but got Unknown //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Expected O, but got Unknown //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Expected O, but got Unknown //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Expected O, but got Unknown //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Expected O, but got Unknown Enabled = config.Bind("General", "Enabled", true, "Enable or disable CustomTimer"); BaseInitialTime = config.Bind("Timer", "BaseInitialTime", 600, new ConfigDescription("Initial timer value (seconds). Must be >= 0", (AcceptableValueBase)(object)new AcceptableValueRange(0, 3600), Array.Empty())); ExtractionBonusTime = config.Bind("Timer", "ExtractionBonusTime", 300, new ConfigDescription("Bonus time added when extraction is completed (seconds). Must be >= 0", (AcceptableValueBase)(object)new AcceptableValueRange(0, 3600), Array.Empty())); TimeUpActionMode = config.Bind("TimeUp", "Action", TimeUpAction.KillNonTruckPlayers, "Behavior when timer reaches zero"); EnableBlackoutOverride = config.Bind("Blackout", "EnableBlackoutOverride", true, "When stage becomes blackout, force timer to a specific value (host authoritative)."); BlackoutOverrideSeconds = config.Bind("Blackout", "BlackoutOverrideSeconds", 60, new ConfigDescription("Forced timer value (seconds) applied when blackout starts.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 3600), Array.Empty())); EnableTimeCap = config.Bind("Timer", "EnableTimeCap", false, "Clamp timer so it never exceeds MaxTimeSeconds (affects AddTime / forced time)."); MaxTimeSeconds = config.Bind("Timer", "MaxTimeSeconds", 600, new ConfigDescription("Maximum timer value (seconds) when EnableTimeCap is true.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 3600), Array.Empty())); EnablePlayerScaling = config.Bind("Player Scaling", "Enable", true, "Enable time bonus based on player count"); PlayerScalingThreshold = config.Bind("Player Scaling", "Threshold", 6, new ConfigDescription("Player count threshold. No bonus when current players >= this value.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 16), Array.Empty())); PlayerScalingSecondsPerPlayer = config.Bind("Player Scaling", "SecondsPerMissingPlayer", 30, new ConfigDescription("Bonus seconds added per missing player below threshold.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 600), Array.Empty())); StageBonus_Museum = config.Bind("Stage Bonus", "Museum", 0, new ConfigDescription("Additional time (seconds) for Museum stages", (AcceptableValueBase)(object)new AcceptableValueRange(-3600, 3600), Array.Empty())); StageBonus_Manor = config.Bind("Stage Bonus", "Manor", 0, new ConfigDescription("Additional time (seconds) for Manor stages", (AcceptableValueBase)(object)new AcceptableValueRange(-3600, 3600), Array.Empty())); StageBonus_Arctic = config.Bind("Stage Bonus", "Arctic", 0, new ConfigDescription("Additional time (seconds) for Arctic stages", (AcceptableValueBase)(object)new AcceptableValueRange(-3600, 3600), Array.Empty())); StageBonus_Wizard = config.Bind("Stage Bonus", "Wizard", 0, new ConfigDescription("Additional time (seconds) for Wizard stages", (AcceptableValueBase)(object)new AcceptableValueRange(-3600, 3600), Array.Empty())); StageBonus_Other = config.Bind("Stage Bonus", "Other", 0, new ConfigDescription("Additional time (seconds) for other or modded stages", (AcceptableValueBase)(object)new AcceptableValueRange(-3600, 3600), Array.Empty())); StageTimeOverrides = config.Bind("Stage Override", "StageTimeOverrides", "", "Custom stage time overrides added to BaseInitialTime. Format: stageName:seconds,stageName:seconds"); EnableChatNotify = config.Bind("Chat Notify", "Enable", true, "Enable host-authoritative chat notifications for timer events."); EnableTruckNotify = config.Bind("Truck Notify", "Enable", true, "Enable timer notifications on the truck screen display."); EnableChatCountdown = config.Bind("Chat Notify", "EnableCountdown", true, "Enable chat countdown notifications from 10 to 1 seconds."); EnableChatBonusNotify = config.Bind("Chat Notify", "EnableBonusChat", true, "Enable chat notifications when bonus time is added or time is modified."); EnableChatThreshold = config.Bind("Chat Notify", "EnableThresholdChat", false, "Enable chat notifications when remaining time crosses threshold seconds."); ChatNotifyThresholdSeconds = config.Bind("Chat Notify", "ThresholdSeconds", "60,30,20,10", "Seconds at which threshold notifications are triggered (comma-separated)."); ChatNotifyCooldownSeconds = config.Bind("Chat Notify", "CooldownSeconds", 5f, new ConfigDescription("Minimum interval (seconds) between chat notifications.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 60f), Array.Empty())); EnableHUD = config.Bind("HUD", "EnableHUD", true, "Show timer HUD"); DebugLog = config.Bind("Debug", "DebugLog", false, "Enable debug logging"); } public static void AddOrUpdateStageOverride(string stageName, int seconds) { if (!string.IsNullOrEmpty(stageName)) { string text = stageName.ToLowerInvariant(); Dictionary allOverridesMutable = StageOverrideResolver.GetAllOverridesMutable(); allOverridesMutable[text] = seconds; StageOverrideResolver.WriteBack(allOverridesMutable); CustomTimer.Logger.LogInfo((object)$"[Timer] Stage override updated: {text} → {seconds}s"); } } } internal static class TimerConfigValues { public static bool Enabled => TimerConfig.Enabled.Value; public static int BaseInitialTime => TimerConfig.BaseInitialTime.Value; public static int ExtractionBonusTime => TimerConfig.ExtractionBonusTime.Value; public static TimeUpAction TimeUpAction => TimerConfig.TimeUpActionMode.Value; public static bool EnableHUD => TimerConfig.EnableHUD.Value; public static bool DebugLog => TimerConfig.DebugLog.Value; public static bool EnablePlayerScaling => TimerConfig.EnablePlayerScaling.Value; public static int PlayerScalingThreshold => TimerConfig.PlayerScalingThreshold.Value; public static int PlayerScalingSecondsPerPlayer => TimerConfig.PlayerScalingSecondsPerPlayer.Value; public static bool EnableBlackoutOverride => TimerConfig.EnableBlackoutOverride.Value; public static int BlackoutOverrideSeconds => TimerConfig.BlackoutOverrideSeconds.Value; public static bool EnableTimeCap => TimerConfig.EnableTimeCap.Value; public static int MaxTimeSeconds => TimerConfig.MaxTimeSeconds.Value; public static int StageBonus_Museum => TimerConfig.StageBonus_Museum.Value; public static int StageBonus_Manor => TimerConfig.StageBonus_Manor.Value; public static int StageBonus_Arctic => TimerConfig.StageBonus_Arctic.Value; public static int StageBonus_Wizard => TimerConfig.StageBonus_Wizard.Value; public static int StageBonus_Other => TimerConfig.StageBonus_Other.Value; public static string StageTimeOverrides => TimerConfig.StageTimeOverrides.Value; public static bool EnableChatNotify => TimerConfig.EnableChatNotify.Value; public static bool EnableChatCountdown => TimerConfig.EnableChatCountdown.Value; public static bool EnableChatThreshold => TimerConfig.EnableChatThreshold.Value; public static bool EnableChatBonusNotify => TimerConfig.EnableChatBonusNotify.Value; public static string ChatNotifyThresholdSeconds => TimerConfig.ChatNotifyThresholdSeconds.Value; public static float ChatNotifyCooldownSeconds => TimerConfig.ChatNotifyCooldownSeconds.Value; public static bool EnableTruckNotify => TimerConfig.EnableTruckNotify.Value; } } namespace CustomTimer.Bootstrap { internal class TimerBootstrap { } } namespace CustomTimer.Core { internal static class LevelContext { public static string CurrentLevelName { get; private set; } = ""; public static void UpdateCurrentLevel() { RunManager instance = RunManager.instance; object obj; if (instance == null) { obj = null; } else { Level levelCurrent = instance.levelCurrent; obj = ((levelCurrent != null) ? ((Object)levelCurrent).name : null); } if (obj == null) { obj = ""; } CurrentLevelName = (string)obj; } } internal enum StageCategory { Museum, Manor, Arctic, Wizard, Other } internal static class InitialTimeCalculator { public static int Calculate() { string currentLevelName = LevelContext.CurrentLevelName; int baseInitialTime = TimerConfigValues.BaseInitialTime; int num = 0; int num2 = 0; int num3 = 0; if (StageOverrideResolver.TryGetOverride(currentLevelName, out var seconds)) { num3 = seconds; TimerLog.Debug($"[Timer] Stage override bonus matched ({currentLevelName}) → +{num3}s"); } num2 = StageCategoryResolver.Resolve(currentLevelName) switch { StageCategory.Museum => TimerConfigValues.StageBonus_Museum, StageCategory.Manor => TimerConfigValues.StageBonus_Manor, StageCategory.Arctic => TimerConfigValues.StageBonus_Arctic, StageCategory.Wizard => TimerConfigValues.StageBonus_Wizard, _ => TimerConfigValues.StageBonus_Other, }; if (TimerConfigValues.EnablePlayerScaling) { int playerScalingThreshold = TimerConfigValues.PlayerScalingThreshold; int playerScalingSecondsPerPlayer = TimerConfigValues.PlayerScalingSecondsPerPlayer; int count = SemiFunc.PlayerGetAll().Count; int num4 = Mathf.Max(0, playerScalingThreshold - count); num = num4 * playerScalingSecondsPerPlayer; } baseInitialTime += num2 + num3 + num; TimerLog.Debug($"[Timer] InitialTime = Base({TimerConfigValues.BaseInitialTime})" + $" + Stage({num2})" + $" + Override({num3})" + $" + Player({num})" + $" = {baseInitialTime}s"); int num5 = baseInitialTime; if (TimerConfigValues.EnableTimeCap) { num5 = Mathf.Min(baseInitialTime, TimerConfigValues.MaxTimeSeconds); if (num5 != baseInitialTime) { TimerLog.Debug($"[Timer] InitialTime capped: {baseInitialTime}s → {num5}s" + $" (−{baseInitialTime - num5}s)"); } } return Mathf.Max(0, num5); } } internal static class StageCategoryResolver { public static StageCategory Resolve(string levelName) { if (string.IsNullOrEmpty(levelName)) { return StageCategory.Other; } string text = levelName.ToLowerInvariant(); if (text.Contains("museum")) { return StageCategory.Museum; } if (text.Contains("manor")) { return StageCategory.Manor; } if (text.Contains("arctic")) { return StageCategory.Arctic; } if (text.Contains("wizard")) { return StageCategory.Wizard; } return StageCategory.Other; } } internal static class StageOverrideResolver { private static Dictionary? _cache; public static bool TryGetOverride(string levelName, out int seconds) { seconds = 0; if (string.IsNullOrEmpty(levelName)) { return false; } EnsureParsed(); string text = levelName.ToLowerInvariant(); foreach (KeyValuePair item in _cache) { if (text.Contains(item.Key)) { seconds = item.Value; return true; } } return false; } private static void EnsureParsed() { if (_cache != null) { return; } _cache = new Dictionary(); string stageTimeOverrides = TimerConfigValues.StageTimeOverrides; if (string.IsNullOrWhiteSpace(stageTimeOverrides)) { return; } string[] array = stageTimeOverrides.Split(','); string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(':'); if (array3.Length == 2) { string text2 = array3[0].Trim().ToLowerInvariant(); if (!string.IsNullOrEmpty(text2) && int.TryParse(array3[1], out var result)) { _cache[text2] = result; } } } } public static Dictionary GetAllOverridesMutable() { EnsureParsed(); return new Dictionary(_cache); } public static void WriteBack(Dictionary dict) { _cache = dict ?? new Dictionary(); StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair item in _cache) { if (stringBuilder.Length > 0) { stringBuilder.Append(","); } string value = (item.Key ?? "").Trim().ToLowerInvariant(); if (!string.IsNullOrEmpty(value)) { stringBuilder.Append(value); stringBuilder.Append(":"); stringBuilder.Append(item.Value); } } TimerConfig.StageTimeOverrides.Value = stringBuilder.ToString(); ((ConfigEntryBase)TimerConfig.StageTimeOverrides).ConfigFile.Save(); TimerLog.Debug("[Timer] StageTimeOverrides saved: " + TimerConfig.StageTimeOverrides.Value); } } internal sealed class TimerChatNotifier { private int _lastCountdownSecond = -1; private float _lastBonusNotifyTime = -999f; private HashSet _thresholds; private float _lastThresholdNotifyTime = -999f; public static TimerChatNotifier Instance { get; } = new TimerChatNotifier(); private TimerChatNotifier() { } public void Tick(float previousTime, float currentTime) { if (SemiFunc.IsMasterClient() && !(currentTime <= 0f)) { HandleThreshold(previousTime, currentTime); HandleCountdown(currentTime); } } private void SendChatToAllPlayers(string message) { if (!TimerConfigValues.EnableChatNotify) { return; } List playerList = GameDirector.instance.PlayerList; if (playerList == null) { return; } foreach (PlayerAvatar item in playerList) { if (!((Object)(object)item == (Object)null)) { item.ChatMessageSend(message); } } } private void SendChatToAlivePlayers(string message) { if (!TimerConfigValues.EnableChatNotify) { return; } List playerList = GameDirector.instance.PlayerList; if (playerList == null) { return; } foreach (PlayerAvatar item in playerList) { if (!((Object)(object)item == (Object)null) && !item.deadSet) { item.ChatMessageSend(message); } } } private void SendTruckMessage(string message) { if (TimerConfigValues.EnableTruckNotify && !((Object)(object)TruckScreenText.instance == (Object)null)) { TruckScreenText.instance.MessageSendCustom("", message, 0); } } public void NotifyTimerStart(float startTime) { if (SemiFunc.IsMasterClient()) { if (TimerConfigValues.EnableTruckNotify) { string message = "[TIMER] Start: " + TimerTextFormatter.FormatTime(startTime, withMilliseconds: false); SendTruckMessage(message); } if (TimerConfigValues.EnableChatNotify) { string message2 = "Timer started with " + TimerTextFormatter.FormatTimeForTTS(startTime); SendChatToAllPlayers(message2); } } } public void NotifyTimerStop(float time) { if (SemiFunc.IsMasterClient()) { if (TimerConfigValues.EnableTruckNotify) { SendTruckMessage("[TIMER] Timer paused"); } if (TimerConfigValues.EnableChatNotify) { SendChatToAllPlayers("Timer paused"); } } } public void NotifyTimerResume(float time) { if (SemiFunc.IsMasterClient()) { if (TimerConfigValues.EnableTruckNotify) { SendTruckMessage("[TIMER] Time: " + TimerTextFormatter.FormatTime(time, withMilliseconds: false)); } if (TimerConfigValues.EnableChatNotify) { SendChatToAllPlayers("Timer resumed with " + TimerTextFormatter.FormatTimeForTTS(time)); } } } public void NotifyTimeUp() { if (SemiFunc.IsMasterClient()) { if (TimerConfigValues.EnableTruckNotify) { SendTruckMessage("[TIMER] Time up"); } if (TimerConfigValues.EnableChatNotify) { SendChatToAllPlayers("Time up"); } } } private void HandleCountdown(float currentTime) { if (!TimerConfigValues.EnableChatCountdown) { return; } if (currentTime > 10f) { _lastCountdownSecond = -1; return; } int num = Mathf.CeilToInt(currentTime); if (num != _lastCountdownSecond && num >= 1 && num <= 10) { _lastCountdownSecond = num; string message = num.ToString(); string message2 = "[TIMER] Time: " + TimerTextFormatter.FormatTime(currentTime, withMilliseconds: false); SendChatToAllPlayers(message); SendTruckMessage(message2); } } private void EnsureThresholdsParsed() { if (_thresholds != null) { return; } _thresholds = new HashSet(); string chatNotifyThresholdSeconds = TimerConfigValues.ChatNotifyThresholdSeconds; if (string.IsNullOrWhiteSpace(chatNotifyThresholdSeconds)) { return; } string[] array = chatNotifyThresholdSeconds.Split(','); foreach (string text in array) { if (int.TryParse(text.Trim(), out var result) && result > 0) { _thresholds.Add(result); } } } private void HandleThreshold(float previousTime, float currentTime) { EnsureThresholdsParsed(); if (_thresholds == null || _thresholds.Count == 0 || currentTime <= 10f || currentTime <= 3f || Time.time - _lastThresholdNotifyTime < TimerConfigValues.ChatNotifyCooldownSeconds) { return; } int num = -1; foreach (int threshold in _thresholds) { if (previousTime > (float)threshold && currentTime <= (float)threshold && num < threshold) { num = threshold; } } if (num >= 0) { _lastThresholdNotifyTime = Time.time; string message = "[TIMER] Time: " + TimerTextFormatter.FormatTime(num, withMilliseconds: false); string message2 = num.ToString(); if (TimerConfigValues.EnableChatNotify && TimerConfigValues.EnableChatThreshold) { SendChatToAllPlayers(message2); } SendTruckMessage(message); } } public void NotifyBonusTime(float newTime) { if (SemiFunc.IsMasterClient()) { if (TimerConfigValues.EnableTruckNotify) { string message = "[TIMER] Time: " + TimerTextFormatter.FormatTime(newTime, withMilliseconds: false); SendTruckMessage(message); } if (TimerConfigValues.EnableChatNotify && TimerConfigValues.EnableChatBonusNotify) { string message2 = "Timer " + TimerTextFormatter.FormatTimeForTTS(newTime); SendChatToAllPlayers(message2); } } } public void NotifySurvivor(float newTime) { if (SemiFunc.IsMasterClient() && TimerConfigValues.EnableChatNotify) { string message = "You survived. " + TimerTextFormatter.FormatTimeForTTS(newTime); SendChatToAlivePlayers(message); } } } internal class TimerManager { private float _authoritativeTime; private float _remoteBaseTime; private double _remoteSyncTime; private bool _isRemote; private float _prevTime; public static TimerManager Instance { get; private set; } public float CurrentTime { get { if (_isRemote) { if (IsPaused) { return _remoteBaseTime; } double num = PhotonNetwork.Time - _remoteSyncTime; return Mathf.Max(0f, _remoteBaseTime - (float)num); } return _authoritativeTime; } } public bool IsActive { get; private set; } public bool IsPaused { get; private set; } public event Action TimeUpEvent; public TimerManager() { Instance = this; } public void Initialize(int initialSeconds) { if (!TimerConfigValues.Enabled) { IsActive = false; return; } _authoritativeTime = Mathf.Max(0, initialSeconds); IsActive = true; IsPaused = false; TimerLog.Debug($"[Timer] Initialized: {_authoritativeTime}s"); if (_authoritativeTime <= 0f) { OnTimeUp(); } } public void Tick(float deltaTime) { if (!IsActive || IsPaused) { return; } _prevTime = CurrentTime; _authoritativeTime -= deltaTime; if (_authoritativeTime <= 0f) { _authoritativeTime = 0f; if (TimerState.ExtractionInProgress) { TimerState.TimeUpPenalty = true; TimerLog.Debug("[Timer] TimeUp deferred (Extraction)"); return; } OnTimeUp(); } TimerChatNotifier.Instance.Tick(_prevTime, CurrentTime); } public void Stop() { IsActive = false; IsPaused = false; } private void OnTimeUp() { IsActive = false; IsPaused = false; TimerState.TimeUpOccurred = true; TimerLog.Debug("[Timer] Time up!"); TimerChatNotifier.Instance.NotifyTimeUp(); this.TimeUpEvent?.Invoke(); TimeUpExecutor.Execute(TimerConfigValues.TimeUpAction); } public void AddTime(float seconds) { if (IsActive && !IsPaused && !TimerState.BlackoutHandled) { _authoritativeTime += seconds; if (TimerConfigValues.EnableTimeCap) { _authoritativeTime = Mathf.Min(_authoritativeTime, (float)TimerConfigValues.MaxTimeSeconds); } TimerChatNotifier.Instance.NotifyBonusTime(_authoritativeTime); TimerLog.Debug($"[Timer] +{seconds}s (now {_authoritativeTime:F1}s)"); } } public void ApplyRemoteSync(float serverTime, double sentAt) { _remoteBaseTime = serverTime; _remoteSyncTime = sentAt; _isRemote = true; IsActive = true; } public void ApplyForcedTime(float time) { time = Mathf.Max(0f, time); if (TimerConfigValues.EnableTimeCap) { time = Mathf.Min(time, (float)TimerConfigValues.MaxTimeSeconds); } _authoritativeTime = time; _remoteBaseTime = time; _remoteSyncTime = PhotonNetwork.Time; _isRemote = !SemiFunc.IsMasterClientOrSingleplayer(); IsActive = true; TimerChatNotifier.Instance.NotifyBonusTime(_authoritativeTime); TimerLog.Debug($"[Timer] Forced time applied: {time}s"); } public void ApplySurvivorBonusTime(float time) { time = Mathf.Max(0f, time); if (TimerConfigValues.EnableTimeCap) { time = Mathf.Min(time, (float)TimerConfigValues.MaxTimeSeconds); } _authoritativeTime = time; _remoteBaseTime = time; _remoteSyncTime = PhotonNetwork.Time; _isRemote = !SemiFunc.IsMasterClientOrSingleplayer(); IsActive = true; TimerChatNotifier.Instance.NotifySurvivor(_authoritativeTime); TimerLog.Debug($"[Timer] Forced time (silent): {time}s"); } public void ForceTimeUp() { if (IsActive) { OnTimeUp(); } } public void TogglePause() { if (IsActive) { IsPaused = !IsPaused; if (IsPaused) { TimerChatNotifier.Instance.NotifyTimerStop(CurrentTime); } else { TimerChatNotifier.Instance.NotifyTimerResume(CurrentTime); } TimerLog.Debug("[Timer] Pause toggled → " + (IsPaused ? "PAUSED" : "RUNNING")); } } public void SetPaused(bool paused) { IsPaused = paused; } } internal static class TimerReset { public static void ResetAll() { TimerState.Reset(); ExtractionBonusTracker.Reset(); TimerManager.Instance.Stop(); TimerLog.Debug("[Timer] Reset all"); } } internal static class TimerState { public static bool Started; public static bool Finished; public static bool BlackoutHandled; public static bool ExtractionInProgress; public static bool TimeUpPenalty; public static bool TimeUpOccurred; public static void Reset() { Started = false; Finished = false; BlackoutHandled = false; ExtractionInProgress = false; TimeUpPenalty = false; TimeUpOccurred = false; } } internal static class TimerTextFormatter { public static string FormatTime(float time, bool withMilliseconds = true) { time = Mathf.Max(0f, time); int num = Mathf.FloorToInt(time / 60f); int num2 = Mathf.FloorToInt(time % 60f); if (!withMilliseconds) { return $"{num:00}:{num2:00}"; } int num3 = Mathf.FloorToInt(time * 1000f % 1000f); return $"{num:00}:{num2:00}.{num3:000}"; } public static string FormatTimeForTTS(float time) { time = Mathf.Max(0f, time); int num = Mathf.CeilToInt(time); int num2 = num / 60; int num3 = num % 60; if (num2 > 0 && num3 > 0) { return string.Format("{0} minute{1} {2} second{3}", num2, (num2 > 1) ? "s" : "", num3, (num3 > 1) ? "s" : ""); } if (num2 > 0) { return string.Format("{0} minute{1}", num2, (num2 > 1) ? "s" : ""); } return string.Format("{0} second{1}", num3, (num3 > 1) ? "s" : ""); } } internal static class TimeUpExecutor { [CompilerGenerated] private sealed class d__5 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float delay; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; Reload(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static void Execute(TimeUpAction action) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } if (SemiFunc.RunIsShop()) { CustomTimer.Logger.LogInfo((object)"Skip shop TimeUp"); return; } switch (action) { case TimeUpAction.KillAll: KillAll(); break; case TimeUpAction.KillNonTruckPlayers: KillNonTruckPlayers(); break; case TimeUpAction.ReloadImmediate: Reload(); break; } } private static void KillAll() { foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (!((Object)(object)player == (Object)null) && !player.deadSet) { player.PlayerDeath(-1); } } } private static void KillNonTruckPlayers() { foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (!((Object)(object)player == (Object)null) && !player.deadSet) { bool flag = (Object)(object)player.RoomVolumeCheck != (Object)null && player.RoomVolumeCheck.inTruck; if (!player.finalHeal) { player.PlayerDeath(-1); } } } } private static void Reload() { TimerLog.Debug("[TimeUpExecutor] RestartScene"); RunManager.instance.RestartScene(); } private static void DelayedReload(float delay) { ((MonoBehaviour)CustomTimer.Instance).StartCoroutine(ReloadCoroutine(delay)); } [IteratorStateMachine(typeof(d__5))] private static IEnumerator ReloadCoroutine(float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(0) { delay = delay }; } } }