mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-02-20 15:41:01 +00:00
Alek/sleep sync (#29)
* syncing time * clients auto-sleep or pause to reach server's time * disabled manual sleep/pause for clients
This commit is contained in:
parent
d6f8112bbb
commit
188bbad5e7
@ -11,7 +11,7 @@ namespace QSB.Animation
|
||||
{
|
||||
private Animator _anim;
|
||||
private Animator _bodyAnim;
|
||||
private NetworkAnimator _netAnim;
|
||||
private QSBNetAnim _netAnim;
|
||||
private MessageHandler<AnimTriggerMessage> _triggerHandler;
|
||||
|
||||
private RuntimeAnimatorController _suitedAnimController;
|
||||
@ -23,9 +23,15 @@ namespace QSB.Animation
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_anim = gameObject.AddComponent<Animator>();
|
||||
_netAnim = gameObject.AddComponent<NetworkAnimator>();
|
||||
_netAnim.animator = _anim;
|
||||
if (_anim == null)
|
||||
{
|
||||
_anim = gameObject.AddComponent<Animator>();
|
||||
}
|
||||
if (_netAnim == null)
|
||||
{
|
||||
_netAnim = gameObject.AddComponent<QSBNetAnim>();
|
||||
_netAnim.animator = _anim;
|
||||
}
|
||||
}
|
||||
|
||||
public void InitLocal(Transform body)
|
||||
@ -50,6 +56,7 @@ namespace QSB.Animation
|
||||
|
||||
public void InitRemote(Transform body)
|
||||
{
|
||||
Awake();
|
||||
_bodyAnim = body.GetComponent<Animator>();
|
||||
body.gameObject.AddComponent<AnimatorMirror>().Init(_anim, _bodyAnim);
|
||||
|
||||
@ -106,8 +113,7 @@ namespace QSB.Animation
|
||||
|
||||
private void OnClientReceiveMessage(AnimTriggerMessage message)
|
||||
{
|
||||
var animSync = PlayerAnimSyncs[message.SenderId];
|
||||
if (animSync != this)
|
||||
if (PlayerAnimSyncs.TryGetValue(message.SenderId, out var animSync) && animSync != this)
|
||||
{
|
||||
animSync.HandleTrigger((AnimTrigger)message.TriggerId);
|
||||
}
|
||||
|
@ -39,6 +39,10 @@ namespace QSB.Animation
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_to.runtimeAnimatorController != _from.runtimeAnimatorController)
|
||||
{
|
||||
_to.runtimeAnimatorController = _from.runtimeAnimatorController;
|
||||
}
|
||||
SyncParams();
|
||||
SmoothFloats();
|
||||
}
|
||||
@ -52,9 +56,6 @@ namespace QSB.Animation
|
||||
case AnimatorControllerParameterType.Float:
|
||||
_floatParams[fromParam.name].Target = _from.GetFloat(fromParam.name);
|
||||
break;
|
||||
case AnimatorControllerParameterType.Int:
|
||||
_to.SetInteger(fromParam.name, _from.GetInteger(fromParam.name));
|
||||
break;
|
||||
case AnimatorControllerParameterType.Bool:
|
||||
_to.SetBool(fromParam.name, _from.GetBool(fromParam.name));
|
||||
break;
|
||||
|
67
QSB/Animation/QSBNetAnim.cs
Normal file
67
QSB/Animation/QSBNetAnim.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using OWML.ModHelper.Events;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace QSB.Animation
|
||||
{
|
||||
public class QSBNetAnim : NetworkAnimator
|
||||
{
|
||||
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||||
{
|
||||
var anim = this.GetValue<Animator>("m_Animator");
|
||||
if (anim == null)
|
||||
{
|
||||
DebugLog.Screen("anim is null");
|
||||
return;
|
||||
}
|
||||
if (anim.parameters == null)
|
||||
{
|
||||
DebugLog.Screen("anim.parameters is null");
|
||||
return;
|
||||
}
|
||||
if (anim.parameters.Length == 0)
|
||||
{
|
||||
DebugLog.Screen("anim.parameters.Length == 0");
|
||||
return;
|
||||
}
|
||||
for (int index = 0; index < anim.parameters.Length; ++index)
|
||||
{
|
||||
if (!this.GetValue<bool>("autoSend") || this.GetParameterAutoSend(index))
|
||||
{
|
||||
AnimatorControllerParameter parameter = anim.parameters[index];
|
||||
if (parameter.type == AnimatorControllerParameterType.Int)
|
||||
{
|
||||
int num = (int)reader.ReadPackedUInt32();
|
||||
anim.SetInteger(parameter.nameHash, num);
|
||||
this.Invoke("SetRecvTrackingParam", parameter.name + ":" + (object)num, index);
|
||||
}
|
||||
|
||||
if (parameter.type == AnimatorControllerParameterType.Float)
|
||||
{
|
||||
float num;
|
||||
try
|
||||
{
|
||||
num = reader.ReadSingle();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//DebugLog.Screen($"Error when reading float {parameter.name}: " + ex);
|
||||
return;
|
||||
}
|
||||
anim.SetFloat(parameter.nameHash, num);
|
||||
this.Invoke("SetRecvTrackingParam", parameter.name + ":" + (object)num, index);
|
||||
}
|
||||
|
||||
if (parameter.type == AnimatorControllerParameterType.Bool)
|
||||
{
|
||||
bool flag = reader.ReadBoolean();
|
||||
anim.SetBool(parameter.nameHash, flag);
|
||||
this.Invoke("SetRecvTrackingParam", parameter.name + ":" + (object)flag, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
using OWML.Common;
|
||||
using OWML.ModHelper;
|
||||
using QSB.TimeSync;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
@ -22,7 +21,6 @@ namespace QSB
|
||||
gameObject.AddComponent<DebugLog>();
|
||||
gameObject.AddComponent<QSBNetworkManager>();
|
||||
gameObject.AddComponent<NetworkManagerHUD>();
|
||||
gameObject.AddComponent<PreserveTimeScale>();
|
||||
gameObject.AddComponent<RespawnOnDeath>();
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,7 @@
|
||||
<Compile Include="Animation\AnimFloatParam.cs" />
|
||||
<Compile Include="Animation\AnimTriggerMessage.cs" />
|
||||
<Compile Include="Animation\AnimTrigger.cs" />
|
||||
<Compile Include="Animation\QSBNetAnim.cs" />
|
||||
<Compile Include="DebugLog.cs" />
|
||||
<Compile Include="Messaging\MessageHandler.cs" />
|
||||
<Compile Include="Messaging\MessageType.cs" />
|
||||
|
@ -1,15 +1,25 @@
|
||||
using UnityEngine;
|
||||
using OWML.ModHelper.Events;
|
||||
using UnityEngine;
|
||||
|
||||
namespace QSB.TimeSync
|
||||
{
|
||||
public class PreserveTimeScale : QSBBehaviour
|
||||
public class PreserveTimeScale : MonoBehaviour
|
||||
{
|
||||
private void Update()
|
||||
private void Start()
|
||||
{
|
||||
if (IsPlayerAwake)
|
||||
GlobalMessenger.AddListener("GamePaused", OnPause);
|
||||
|
||||
var campfires = GameObject.FindObjectsOfType<Campfire>();
|
||||
foreach (var campfire in campfires)
|
||||
{
|
||||
Time.timeScale = 1;
|
||||
campfire.SetValue("_canSleepHere", false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPause()
|
||||
{
|
||||
Time.timeScale = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,16 @@ namespace QSB.TimeSync
|
||||
{
|
||||
public override MessageType MessageType => MessageType.WakeUp;
|
||||
|
||||
private bool _wakeUp = true;
|
||||
public float ServerTime { get; set; }
|
||||
|
||||
public override void Deserialize(NetworkReader reader)
|
||||
{
|
||||
_wakeUp = reader.ReadBoolean();
|
||||
ServerTime = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public override void Serialize(NetworkWriter writer)
|
||||
{
|
||||
writer.Write(_wakeUp);
|
||||
writer.Write(ServerTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,24 @@
|
||||
using OWML.ModHelper.Events;
|
||||
using System.Linq;
|
||||
using OWML.ModHelper.Events;
|
||||
using QSB.Messaging;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace QSB.TimeSync
|
||||
{
|
||||
public class WakeUpSync : NetworkBehaviour
|
||||
{
|
||||
private const float TimeThreshold = 0.5f;
|
||||
|
||||
private enum State { NotLoaded, EyesClosed, Awake, Sleeping, Pausing }
|
||||
private State _state = State.NotLoaded;
|
||||
|
||||
private MessageHandler<WakeUpMessage> _wakeUpHandler;
|
||||
private Campfire _campfire;
|
||||
|
||||
private float _sendTimer;
|
||||
private float _serverTime;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
@ -14,20 +26,46 @@ namespace QSB.TimeSync
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DebugLog.Screen("Start WakeUpSync");
|
||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
|
||||
_wakeUpHandler = new MessageHandler<WakeUpMessage>();
|
||||
_wakeUpHandler.OnClientReceiveMessage += OnClientReceiveMessage;
|
||||
}
|
||||
|
||||
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
if (scene.name == "SolarSystem")
|
||||
{
|
||||
_campfire = GameObject.FindObjectsOfType<Campfire>().Single(x => x.GetValue<Sector>("_sector").name == "Sector_Village");
|
||||
_state = State.EyesClosed;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWakeUp()
|
||||
{
|
||||
if (!isServer)
|
||||
_state = State.Awake;
|
||||
if (isServer)
|
||||
{
|
||||
return;
|
||||
SendServerTime();
|
||||
}
|
||||
DebugLog.Screen("Sending wakeup to all my friends");
|
||||
_wakeUpHandler.SendToAll(new WakeUpMessage());
|
||||
else
|
||||
{
|
||||
gameObject.AddComponent<PreserveTimeScale>();
|
||||
WakeUpOrSleep();
|
||||
}
|
||||
}
|
||||
|
||||
private void SendServerTime()
|
||||
{
|
||||
DebugLog.Screen("Sending server time to all my friends: " + Time.timeSinceLevelLoad);
|
||||
var message = new WakeUpMessage
|
||||
{
|
||||
ServerTime = Time.timeSinceLevelLoad
|
||||
};
|
||||
_wakeUpHandler.SendToAll(message);
|
||||
}
|
||||
|
||||
private void OnClientReceiveMessage(WakeUpMessage message)
|
||||
@ -36,7 +74,45 @@ namespace QSB.TimeSync
|
||||
{
|
||||
return;
|
||||
}
|
||||
_serverTime = message.ServerTime;
|
||||
WakeUpOrSleep();
|
||||
}
|
||||
|
||||
private void WakeUpOrSleep()
|
||||
{
|
||||
if (_state == State.NotLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_state == State.EyesClosed)
|
||||
{
|
||||
OpenEyes();
|
||||
_state = State.Awake;
|
||||
}
|
||||
|
||||
var myTime = Time.timeSinceLevelLoad;
|
||||
var diff = myTime - _serverTime;
|
||||
|
||||
if (diff > TimeThreshold)
|
||||
{
|
||||
DebugLog.Screen($"My time ({myTime}) is {diff} ahead server ({_serverTime})");
|
||||
StartPausing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (diff < -TimeThreshold)
|
||||
{
|
||||
DebugLog.Screen($"My time ({myTime}) is {-diff} behind server ({_serverTime})");
|
||||
StartSleeping();
|
||||
return;
|
||||
}
|
||||
|
||||
DebugLog.Screen($"My time ({myTime}) is within threshold of server time ({_serverTime})");
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@ -59,5 +135,94 @@ namespace QSB.TimeSync
|
||||
GlobalMessenger.FireEvent("TakeFirstFlashbackSnapshot");
|
||||
}
|
||||
|
||||
private void StartSleeping()
|
||||
{
|
||||
if (_state == State.Sleeping)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DebugLog.Screen("Starting sleeping");
|
||||
_campfire.Invoke("StartSleeping");
|
||||
_state = State.Sleeping;
|
||||
}
|
||||
|
||||
private void StopSleeping()
|
||||
{
|
||||
if (_state != State.Sleeping)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DebugLog.Screen("Stopping sleeping");
|
||||
_campfire.StopSleeping();
|
||||
_state = State.Awake;
|
||||
}
|
||||
|
||||
private void StartPausing()
|
||||
{
|
||||
if (_state == State.Pausing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
OWTime.Pause(OWTime.PauseType.Menu);
|
||||
Time.timeScale = 0f;
|
||||
_state = State.Pausing;
|
||||
}
|
||||
|
||||
private void StopPausing()
|
||||
{
|
||||
if (_state != State.Pausing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
OWTime.Unpause(OWTime.PauseType.Menu);
|
||||
_state = State.Awake;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (_state == State.Sleeping && Time.timeSinceLevelLoad >= _serverTime)
|
||||
{
|
||||
StopSleeping();
|
||||
}
|
||||
else if (_state == State.Pausing && Time.timeSinceLevelLoad < _serverTime)
|
||||
{
|
||||
StopPausing();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ namespace QSB.TransformSync
|
||||
public abstract class TransformSync : NetworkBehaviour
|
||||
{
|
||||
private const float SmoothTime = 0.1f;
|
||||
private static bool _isAwake;
|
||||
|
||||
private Transform _syncedTransform;
|
||||
private bool _isSectorSetUp;
|
||||
@ -15,7 +16,14 @@ namespace QSB.TransformSync
|
||||
protected virtual void Awake()
|
||||
{
|
||||
DontDestroyOnLoad(this);
|
||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||
if (_isAwake)
|
||||
{
|
||||
OnWakeUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Transform InitLocalTransform();
|
||||
@ -23,6 +31,7 @@ namespace QSB.TransformSync
|
||||
|
||||
private void OnWakeUp()
|
||||
{
|
||||
_isAwake = true;
|
||||
DebugLog.Screen("Start TransformSync", netId.Value);
|
||||
Invoke(nameof(SetFirstSector), 1);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user