mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-01-08 09:41:07 +00:00
275 lines
6.3 KiB
C#
275 lines
6.3 KiB
C#
using OWML.Common;
|
|
using QSB.DeathSync;
|
|
using QSB.Events;
|
|
using QSB.TimeSync.Events;
|
|
using QSB.Utility;
|
|
using QuantumUNET;
|
|
using UnityEngine;
|
|
|
|
namespace QSB.TimeSync
|
|
{
|
|
public class WakeUpSync : QNetworkBehaviour
|
|
{
|
|
public static WakeUpSync LocalInstance { get; private set; }
|
|
|
|
private const float TimeThreshold = 0.5f;
|
|
private const float MaxFastForwardSpeed = 60f;
|
|
private const float MaxFastForwardDiff = 20f;
|
|
private const float MinFastForwardSpeed = 2f;
|
|
|
|
private enum State { NotLoaded, Loaded, FastForwarding, Pausing }
|
|
|
|
private State _state = State.NotLoaded;
|
|
|
|
private float _sendTimer;
|
|
private float _serverTime;
|
|
private float _timeScale;
|
|
private bool _isInputEnabled = true;
|
|
private bool _isFirstFastForward = true;
|
|
private int _localLoopCount;
|
|
private int _serverLoopCount;
|
|
private InputMode _storedMode;
|
|
|
|
public override void OnStartLocalPlayer() => LocalInstance = this;
|
|
|
|
public void Start()
|
|
{
|
|
if (!IsLocalPlayer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (QSBSceneManager.IsInUniverse)
|
|
{
|
|
Init();
|
|
}
|
|
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
|
|
|
|
GlobalMessenger.AddListener(EventNames.RestartTimeLoop, OnLoopStart);
|
|
GlobalMessenger.AddListener(EventNames.WakeUp, OnWakeUp);
|
|
}
|
|
|
|
private void OnWakeUp()
|
|
{
|
|
DebugLog.DebugWrite($"OnWakeUp", MessageType.Info);
|
|
if (QNetworkServer.active)
|
|
{
|
|
QSBCore.HasWokenUp = true;
|
|
RespawnOnDeath.Instance.Init();
|
|
}
|
|
}
|
|
|
|
public void OnDestroy()
|
|
{
|
|
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
|
|
GlobalMessenger.RemoveListener(EventNames.RestartTimeLoop, OnLoopStart);
|
|
GlobalMessenger.RemoveListener(EventNames.WakeUp, OnWakeUp);
|
|
}
|
|
|
|
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
|
|
{
|
|
if (isInUniverse)
|
|
{
|
|
Init();
|
|
}
|
|
else
|
|
{
|
|
_state = State.NotLoaded;
|
|
}
|
|
}
|
|
|
|
private void OnLoopStart() => _localLoopCount++;
|
|
|
|
private void Init()
|
|
{
|
|
QSBEventManager.FireEvent(EventNames.QSBPlayerStatesRequest);
|
|
_state = State.Loaded;
|
|
gameObject.AddComponent<PreserveTimeScale>();
|
|
if (IsServer)
|
|
{
|
|
SendServerTime();
|
|
}
|
|
else
|
|
{
|
|
WakeUpOrSleep();
|
|
}
|
|
}
|
|
|
|
private void SendServerTime() => QSBEventManager.FireEvent(EventNames.QSBServerTime, Time.timeSinceLevelLoad, _localLoopCount);
|
|
|
|
public void OnClientReceiveMessage(ServerTimeMessage message)
|
|
{
|
|
_serverTime = message.ServerTime;
|
|
_serverLoopCount = message.LoopCount;
|
|
WakeUpOrSleep();
|
|
}
|
|
|
|
private void WakeUpOrSleep()
|
|
{
|
|
if (_state == State.NotLoaded || _localLoopCount != _serverLoopCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var myTime = Time.timeSinceLevelLoad;
|
|
var diff = myTime - _serverTime;
|
|
|
|
if (diff > TimeThreshold)
|
|
{
|
|
StartPausing();
|
|
return;
|
|
}
|
|
|
|
if (diff < -TimeThreshold)
|
|
{
|
|
StartFastForwarding();
|
|
}
|
|
}
|
|
|
|
private void StartFastForwarding()
|
|
{
|
|
if (_state == State.FastForwarding)
|
|
{
|
|
TimeSyncUI.TargetTime = _serverTime;
|
|
return;
|
|
}
|
|
DebugLog.DebugWrite($"START FASTFORWARD (Target:{_serverTime} Current:{Time.timeSinceLevelLoad})", MessageType.Info);
|
|
if (Locator.GetPlayerCamera() != null)
|
|
{
|
|
Locator.GetPlayerCamera().enabled = false;
|
|
}
|
|
_timeScale = MaxFastForwardSpeed;
|
|
_state = State.FastForwarding;
|
|
OWTime.SetMaxDeltaTime(0.033333335f);
|
|
TimeSyncUI.TargetTime = _serverTime;
|
|
TimeSyncUI.Start(TimeSyncType.Fastforwarding);
|
|
DisableInput();
|
|
}
|
|
|
|
private void StartPausing()
|
|
{
|
|
if (_state == State.Pausing)
|
|
{
|
|
return;
|
|
}
|
|
DebugLog.DebugWrite($"START PAUSING (Target:{_serverTime} Current:{Time.timeSinceLevelLoad})", MessageType.Info);
|
|
Locator.GetPlayerCamera().enabled = false;
|
|
_timeScale = 0f;
|
|
_state = State.Pausing;
|
|
SpinnerUI.Show();
|
|
TimeSyncUI.Start(TimeSyncType.Pausing);
|
|
DisableInput();
|
|
}
|
|
|
|
private void ResetTimeScale()
|
|
{
|
|
_timeScale = 1f;
|
|
OWTime.SetMaxDeltaTime(0.06666667f);
|
|
Locator.GetPlayerCamera().enabled = true;
|
|
_state = State.Loaded;
|
|
|
|
if (!_isInputEnabled)
|
|
{
|
|
EnableInput();
|
|
}
|
|
DebugLog.DebugWrite($"RESET TIMESCALE", MessageType.Info);
|
|
_isFirstFastForward = false;
|
|
QSBCore.HasWokenUp = true;
|
|
Physics.SyncTransforms();
|
|
SpinnerUI.Hide();
|
|
TimeSyncUI.Stop();
|
|
QSBEventManager.FireEvent(EventNames.QSBPlayerStatesRequest);
|
|
RespawnOnDeath.Instance.Init();
|
|
}
|
|
|
|
private void DisableInput()
|
|
{
|
|
DebugLog.DebugWrite($"disable input - current:{OWInput.GetInputMode()}");
|
|
_isInputEnabled = false;
|
|
_storedMode = OWInput.GetInputMode();
|
|
OWInput.ChangeInputMode(InputMode.None);
|
|
}
|
|
|
|
private void EnableInput()
|
|
{
|
|
DebugLog.DebugWrite($"enable input - stored:{_storedMode}");
|
|
_isInputEnabled = true;
|
|
OWInput.ChangeInputMode(
|
|
_storedMode != InputMode.None
|
|
? _storedMode
|
|
: InputMode.Character);
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (IsServer)
|
|
{
|
|
UpdateServer();
|
|
}
|
|
else if (IsLocalPlayer)
|
|
{
|
|
UpdateLocal();
|
|
}
|
|
}
|
|
|
|
private void UpdateServer()
|
|
{
|
|
if (_state != State.Loaded)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_sendTimer += Time.unscaledDeltaTime;
|
|
if (_sendTimer > 1)
|
|
{
|
|
SendServerTime();
|
|
_sendTimer = 0;
|
|
}
|
|
}
|
|
|
|
private void UpdateLocal()
|
|
{
|
|
_serverTime += Time.unscaledDeltaTime;
|
|
|
|
if (!_isInputEnabled && OWInput.GetInputMode() != InputMode.None)
|
|
{
|
|
DisableInput();
|
|
}
|
|
|
|
if (_state == State.NotLoaded)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_state == State.FastForwarding)
|
|
{
|
|
if (Locator.GetPlayerCamera() != null && !Locator.GetPlayerCamera().enabled)
|
|
{
|
|
Locator.GetPlayerCamera().enabled = false;
|
|
}
|
|
var diff = _serverTime - Time.timeSinceLevelLoad;
|
|
Time.timeScale = Mathf.SmoothStep(MinFastForwardSpeed, MaxFastForwardSpeed, Mathf.Abs(diff) / MaxFastForwardDiff);
|
|
|
|
if (QSBSceneManager.CurrentScene == OWScene.SolarSystem && _isFirstFastForward)
|
|
{
|
|
var spawnPoint = Locator.GetPlayerBody().GetComponent<PlayerSpawner>().GetInitialSpawnPoint().transform;
|
|
Locator.GetPlayerTransform().position = spawnPoint.position;
|
|
Locator.GetPlayerTransform().rotation = spawnPoint.rotation;
|
|
Physics.SyncTransforms();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Time.timeScale = _timeScale;
|
|
}
|
|
|
|
var isDoneFastForwarding = _state == State.FastForwarding && Time.timeSinceLevelLoad >= _serverTime;
|
|
var isDonePausing = _state == State.Pausing && Time.timeSinceLevelLoad < _serverTime;
|
|
|
|
if (isDoneFastForwarding || isDonePausing)
|
|
{
|
|
ResetTimeScale();
|
|
}
|
|
}
|
|
}
|
|
} |