230 lines
6.0 KiB
C#
Raw Normal View History

using OWML.ModHelper.Events;
2020-02-15 20:48:02 +01:00
using QSB.Messaging;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
namespace QSB.TimeSync
2020-02-15 20:48:02 +01:00
{
public class WakeUpSync : NetworkBehaviour
2020-02-15 20:48:02 +01:00
{
private const float TimeThreshold = 0.5f;
private const float FastForwardSpeed = 10f;
private enum State { NotLoaded, EyesClosed, Awake, FastForwarding, Pausing }
private State _state = State.NotLoaded;
2020-02-21 23:36:07 +01:00
private MessageHandler<WakeUpMessage> _wakeUpHandler;
private float _sendTimer;
private float _serverTime;
private float _timeScale;
private bool _isInputEnabled = true;
2020-02-15 20:48:02 +01:00
private void Start()
{
if (!isLocalPlayer)
{
return;
}
DebugLog.Screen("Start WakeUpSync");
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
SceneManager.sceneLoaded += OnSceneLoaded;
2020-02-21 23:36:07 +01:00
_wakeUpHandler = new MessageHandler<WakeUpMessage>();
_wakeUpHandler.OnClientReceiveMessage += OnClientReceiveMessage;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (scene.name == "SolarSystem")
{
_state = State.EyesClosed;
}
}
2020-02-15 20:48:02 +01:00
private void OnWakeUp()
{
_state = State.Awake;
gameObject.AddComponent<PreserveTimeScale>();
if (isServer)
2020-02-15 20:48:02 +01:00
{
SendServerTime();
}
else
{
WakeUpOrSleep();
}
}
private void SendServerTime()
{
var message = new WakeUpMessage
{
ServerTime = Time.timeSinceLevelLoad
};
_wakeUpHandler.SendToAll(message);
}
2020-02-21 23:36:07 +01:00
private void OnClientReceiveMessage(WakeUpMessage message)
2020-02-15 20:48:02 +01:00
{
if (isServer)
2020-02-15 20:48:02 +01:00
{
return;
}
_serverTime = message.ServerTime;
WakeUpOrSleep();
}
private void WakeUpOrSleep()
{
if (_state == State.NotLoaded)
{
return;
}
if (_state == State.EyesClosed)
{
OpenEyes();
_state = State.Awake;
if (!isServer)
{
DisableInput();
}
}
var myTime = Time.timeSinceLevelLoad;
var diff = myTime - _serverTime;
if (diff > TimeThreshold)
{
StartPausing();
return;
}
if (diff < -TimeThreshold)
{
StartFastForwarding();
return;
}
}
private void OpenEyes()
{
// I copied all of this from my AutoResume mod, since that already wakes up the player instantly.
// There must be a simpler way to do this though, I just couldn't find it.
// Skip wake up animation.
var cameraEffectController = FindObjectOfType<PlayerCameraEffectController>();
cameraEffectController.OpenEyes(0, true);
cameraEffectController.SetValue("_wakeLength", 0f);
cameraEffectController.SetValue("_waitForWakeInput", false);
// Skip wake up prompt.
LateInitializerManager.pauseOnInitialization = false;
Locator.GetPauseCommandListener().RemovePauseCommandLock();
Locator.GetPromptManager().RemoveScreenPrompt(cameraEffectController.GetValue<ScreenPrompt>("_wakePrompt"));
OWTime.Unpause(OWTime.PauseType.Sleeping);
cameraEffectController.Invoke("WakeUp");
}
private void StartFastForwarding()
{
if (_state == State.FastForwarding)
{
return;
}
_timeScale = FastForwardSpeed;
_state = State.FastForwarding;
}
private void StartPausing()
{
if (_state == State.Pausing)
{
return;
}
_timeScale = 0f;
_state = State.Pausing;
}
private void ResetTimeScale()
{
_timeScale = 1f;
_state = State.Awake;
if (!_isInputEnabled)
{
EnableInput();
}
}
private void DisableInput()
{
_isInputEnabled = false;
OWInput.ChangeInputMode(InputMode.None);
}
private void EnableInput()
{
_isInputEnabled = true;
OWInput.ChangeInputMode(InputMode.Character);
}
private void Update()
{
if (isServer)
{
UpdateServer();
}
else if (isLocalPlayer)
{
UpdateLocal();
}
}
private void UpdateServer()
{
if (_state != State.Awake)
{
return;
}
_sendTimer += Time.unscaledDeltaTime;
if (_sendTimer > 1)
{
SendServerTime();
_sendTimer = 0;
}
}
private void UpdateLocal()
{
_serverTime += Time.unscaledDeltaTime;
if (_state == State.NotLoaded || _state == State.EyesClosed)
{
return;
}
bool isDoneFastForwarding = _state == State.FastForwarding && Time.timeSinceLevelLoad >= _serverTime;
bool isDonePausing = _state == State.Pausing && Time.timeSinceLevelLoad < _serverTime;
if (isDoneFastForwarding || isDonePausing)
{
ResetTimeScale();
}
Time.timeScale = _timeScale;
if (!_isInputEnabled && OWInput.GetInputMode() != InputMode.None)
{
DisableInput();
}
}
}
}