using QSB.Localization; using QSB.Utility; using QSB.WorldSync; using System; using System.Linq; using UnityEngine; using UnityEngine.UI; namespace QSB.TimeSync; public class TimeSyncUI : MonoBehaviour, IAddComponentOnStart { private static TimeSyncUI _instance; public static float TargetTime; private Canvas _canvas; private Text _text; private float _startTime; private bool _isSetUp; private TimeSyncType _currentType; private Enum _currentReason; private void Awake() { _instance = this; enabled = false; QSBSceneManager.OnUniverseSceneLoaded += OnUniverseSceneLoad; } private void OnUniverseSceneLoad(OWScene oldScene, OWScene newScene) { _isSetUp = true; var obj = QSBWorldSync.GetUnityObject(); _canvas = obj._canvas; _text = obj._text; _canvas.enabled = false; var langController = QSBWorldSync.GetUnityObject().transform.GetChild(0).GetComponent(); langController.AddTextElement(_text); } public void OnDestroy() { QSBSceneManager.OnUniverseSceneLoaded -= OnUniverseSceneLoad; if (_canvas != null && _canvas.enabled) { Canvas.willRenderCanvases -= OnWillRenderCanvases; } } public static void Start(TimeSyncType type, Enum reason) => Delay.RunWhen(() => _instance._isSetUp, () => _instance.StartTimeSync(type, reason)); public static void Stop() => Delay.RunWhen(() => _instance._isSetUp, () => _instance.EndTimeSync()); private void StartTimeSync(TimeSyncType type, Enum reason) { if (!QSBSceneManager.IsInUniverse) { DebugLog.ToConsole("Error - Tried to start time sync UI when not in universe!", OWML.Common.MessageType.Error); return; } _currentType = type; _currentReason = reason; _startTime = Time.timeSinceLevelLoad; enabled = true; _canvas.enabled = true; Canvas.willRenderCanvases += OnWillRenderCanvases; // silly hack that shouldnt be in the ui component but oh well Locator.GetPlayerTransform().GetComponent()._invincible = true; Locator.GetDeathManager()._invincible = true; var shipTransform = Locator.GetShipTransform(); if (shipTransform) { shipTransform.GetComponentInChildren()._invincible = true; } } private void EndTimeSync() { _currentType = TimeSyncType.None; enabled = false; _canvas.enabled = false; Canvas.willRenderCanvases -= OnWillRenderCanvases; // silly hack that shouldnt be in the ui component but oh well Locator.GetPlayerTransform().GetComponent()._invincible = false; Locator.GetDeathManager()._invincible = false; var shipTransform = Locator.GetShipTransform(); if (shipTransform) { shipTransform.GetComponentInChildren()._invincible = false; } } private void OnWillRenderCanvases() { if (!_isSetUp) { return; } var text = ""; switch (_currentType) { case TimeSyncType.FastForwarding: switch ((FastForwardReason)_currentReason) { case FastForwardReason.TooFarBehind: var totalSeconds = Mathf.Max(TargetTime - Time.timeSinceLevelLoad, 0f); var minutes = Mathf.FloorToInt(totalSeconds / 60f); var seconds = Mathf.FloorToInt(totalSeconds) % 60; var milliseconds = totalSeconds % 1 * 1000; text = string.Format(QSBLocalization.Current.TimeSyncTooFarBehind, $"{minutes:D2}:{seconds:D2}.{milliseconds:000}"); break; } break; case TimeSyncType.Pausing: switch ((PauseReason)_currentReason) { case PauseReason.ServerNotStarted: text = QSBLocalization.Current.TimeSyncWaitingForStartOfServer; break; case PauseReason.TooFarAhead: var totalSeconds = Mathf.Max(Time.timeSinceLevelLoad - TargetTime, 0f); var minutes = Mathf.FloorToInt(totalSeconds / 60f); var seconds = Mathf.FloorToInt(totalSeconds) % 60; var milliseconds = totalSeconds % 1 * 1000; text = string.Format(QSBLocalization.Current.TimeSyncTooFarAhead, $"{minutes:D2}:{seconds:D2}.{milliseconds:000}"); break; case PauseReason.WaitingForAllPlayersToBeReady: text = QSBLocalization.Current.TimeSyncWaitForAllToReady; break; case PauseReason.WaitingForAllPlayersToDie: text = QSBLocalization.Current.TimeSyncWaitForAllToDie; break; } break; } _text.text = text; } }