From 234d13501eec5638b9dae8a184815d6130b5c51a Mon Sep 17 00:00:00 2001 From: Yurihaia <17830663+Yurihaia@users.noreply.github.com> Date: Thu, 29 Apr 2021 16:25:56 -0400 Subject: [PATCH] fix a trigger bug and make the timer use a Stopwatch to prevent desync --- src/Timer.cs | 63 +++++++++++++++++++++++++++++++++---------- src/TriggerManager.cs | 55 ++++++++++++++++++------------------- 2 files changed, 77 insertions(+), 41 deletions(-) diff --git a/src/Timer.cs b/src/Timer.cs index 6a9f10a..242f9a1 100644 --- a/src/Timer.cs +++ b/src/Timer.cs @@ -4,11 +4,13 @@ using GlobalEnums; using System; using System.Reflection; +using System.Diagnostics; namespace HKTimer { public class Timer : MonoBehaviour { - public TimeSpan time { get; set; } = TimeSpan.Zero; - public bool timerActive { get; set; } = false; + public TimeSpan time { get => this.stopwatch.Elapsed; } + public TimerState state { get; private set; } = TimerState.STOPPED; + public Stopwatch stopwatch { get; private set; } = new Stopwatch(); public GameObject timerCanvas { get; private set; } @@ -58,33 +60,60 @@ public void OnDestroy() { GameObject.Destroy(timerCanvas); } + public void StartTimer() { + this.OnTimerStart?.Invoke(); + this.state = TimerState.RUNNING; + this.stopwatch.Start(); + } + + public void PauseTimer() { + this.OnTimerPause?.Invoke(); + this.state = TimerState.STOPPED; + this.stopwatch.Stop(); + } + + public void ResetTimer() { + this.OnTimerReset?.Invoke(); + this.state = TimerState.STOPPED; + this.stopwatch.Reset(); + frameDisplay.text = this.TimerText(); + } + + public void RestartTimer() { + this.state = TimerState.RUNNING; + this.stopwatch.Reset(); + frameDisplay.text = this.TimerText(); + this.stopwatch.Start(); + } + + public event Action OnTimerStart; public event Action OnTimerPause; public event Action OnTimerReset; public void Update() { - var updateTimer = false; if(StringInputManager.GetKeyDown(HKTimer.settings.pause)) { - timerActive ^= true; - OnTimerPause?.Invoke(); + if(this.state != TimerState.STOPPED) this.PauseTimer(); + else if(this.state == TimerState.STOPPED) this.StartTimer(); } if(StringInputManager.GetKeyDown(HKTimer.settings.reset)) { - time = TimeSpan.Zero; - timerActive = false; - updateTimer = true; - OnTimerReset?.Invoke(); + this.ResetTimer(); + } + if(this.state == TimerState.RUNNING && this.TimerShouldBePaused()) { + this.PauseTimer(); + this.state = TimerState.IN_LOAD; + } else if(this.state == TimerState.IN_LOAD && !this.TimerShouldBePaused()) { + this.StartTimer(); } - if(timerActive && !TimerShouldBePaused()) { - time += System.TimeSpan.FromSeconds(Time.unscaledDeltaTime); - if(Time.unscaledDeltaTime > 0) updateTimer = true; + if(this.state == TimerState.RUNNING) { + frameDisplay.text = this.TimerText(); } - if(updateTimer) frameDisplay.text = this.TimerText(); } - // This uses the same disgusting logic as the autosplitter private bool lookForTeleporting; private GameState lastGameState = GameState.INACTIVE; + // TODO remove the reflection in favor of something actually fast private static FieldInfo cameraControlTeleporting = typeof(CameraController).GetField( "teleporting", BindingFlags.NonPublic | BindingFlags.Instance @@ -161,5 +190,11 @@ private bool TimerShouldBePaused() { return shouldPause; } + + public enum TimerState { + STOPPED, + RUNNING, + IN_LOAD + } } } \ No newline at end of file diff --git a/src/TriggerManager.cs b/src/TriggerManager.cs index 2d0fe0e..998244f 100644 --- a/src/TriggerManager.cs +++ b/src/TriggerManager.cs @@ -78,7 +78,7 @@ public void InitDisplay() { } } - private IEnumerator ShowAlert(string text) { + public IEnumerator ShowAlert(string text) { var canvas = CanvasUtil.CreateCanvas(RenderMode.ScreenSpaceOverlay, 100); var tp = CanvasUtil.CreateTextPanel( canvas, @@ -130,23 +130,21 @@ public void UpdatePB() { var time = this.timer.time; var pbText = this.pbDisplay.GetComponent(); var pbDeltaText = this.pbDeltaDisplay.GetComponent(); - if(this.timer.timerActive) { - if(this.pb == null || this.pb == TimeSpan.Zero) { - this.pb = time; - pbText.text = this.PbText(); - this.pbDelta = TimeSpan.Zero; - this.pbDeltaDisplay.SetActive(false); - } else if(this.pb > time) { - this.pbDelta = time - this.pb; - this.pb = time; - pbText.text = this.PbText(); - pbDeltaText.text = this.PbDeltaText(); - this.pbDeltaDisplay.SetActive(true); - } else { - this.pbDelta = time - this.pb; - pbDeltaText.text = this.PbDeltaText(); - this.pbDeltaDisplay.SetActive(true); - } + if(this.pb == null || this.pb == TimeSpan.Zero) { + this.pb = time; + pbText.text = this.PbText(); + this.pbDelta = TimeSpan.Zero; + this.pbDeltaDisplay.SetActive(false); + } else if(this.pb > time) { + this.pbDelta = time - this.pb; + this.pb = time; + pbText.text = this.PbText(); + pbDeltaText.text = this.PbDeltaText(); + this.pbDeltaDisplay.SetActive(true); + } else { + this.pbDelta = time - this.pb; + pbDeltaText.text = this.PbDeltaText(); + this.pbDeltaDisplay.SetActive(true); } } @@ -167,27 +165,30 @@ public void Awake() { var o = true; switch(p) { case "segment_start": - if(!this.timer.timerActive) { + if(this.timer.state == Timer.TimerState.STOPPED) { + this.timer.ResetTimer(); + this.timer.StartTimer(); this.runningSegment = true; - this.timer.time = TimeSpan.Zero; - this.timer.timerActive = true; } break; case "segment_end": if(this.runningSegment) { this.UpdatePB(); - this.timer.timerActive = false; + this.timer.PauseTimer(); this.runningSegment = false; } break; + case "timer_restart": + this.timer.RestartTimer(); + break; case "timer_reset": - this.timer.time = TimeSpan.Zero; + this.timer.ResetTimer(); break; case "timer_pause": - this.timer.timerActive = false; + this.timer.PauseTimer(); break; - case "timer_resume": - this.timer.timerActive = true; + case "timer_start": + this.timer.StartTimer(); break; default: o = false; @@ -232,7 +233,7 @@ public void Update() { case TriggerPlaceType.Scene: this.start = new SceneTrigger() { scene = GameManager.instance.sceneName, - logic = new JValue("segment_end") + logic = new JValue("segment_start") }; this.StartCoroutine(this.ShowAlert("Created scene trigger")); break;