mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-04-16 05:42:52 +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 _anim;
|
||||||
private Animator _bodyAnim;
|
private Animator _bodyAnim;
|
||||||
private NetworkAnimator _netAnim;
|
private QSBNetAnim _netAnim;
|
||||||
private MessageHandler<AnimTriggerMessage> _triggerHandler;
|
private MessageHandler<AnimTriggerMessage> _triggerHandler;
|
||||||
|
|
||||||
private RuntimeAnimatorController _suitedAnimController;
|
private RuntimeAnimatorController _suitedAnimController;
|
||||||
@ -23,9 +23,15 @@ namespace QSB.Animation
|
|||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
_anim = gameObject.AddComponent<Animator>();
|
if (_anim == null)
|
||||||
_netAnim = gameObject.AddComponent<NetworkAnimator>();
|
{
|
||||||
_netAnim.animator = _anim;
|
_anim = gameObject.AddComponent<Animator>();
|
||||||
|
}
|
||||||
|
if (_netAnim == null)
|
||||||
|
{
|
||||||
|
_netAnim = gameObject.AddComponent<QSBNetAnim>();
|
||||||
|
_netAnim.animator = _anim;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitLocal(Transform body)
|
public void InitLocal(Transform body)
|
||||||
@ -50,6 +56,7 @@ namespace QSB.Animation
|
|||||||
|
|
||||||
public void InitRemote(Transform body)
|
public void InitRemote(Transform body)
|
||||||
{
|
{
|
||||||
|
Awake();
|
||||||
_bodyAnim = body.GetComponent<Animator>();
|
_bodyAnim = body.GetComponent<Animator>();
|
||||||
body.gameObject.AddComponent<AnimatorMirror>().Init(_anim, _bodyAnim);
|
body.gameObject.AddComponent<AnimatorMirror>().Init(_anim, _bodyAnim);
|
||||||
|
|
||||||
@ -106,8 +113,7 @@ namespace QSB.Animation
|
|||||||
|
|
||||||
private void OnClientReceiveMessage(AnimTriggerMessage message)
|
private void OnClientReceiveMessage(AnimTriggerMessage message)
|
||||||
{
|
{
|
||||||
var animSync = PlayerAnimSyncs[message.SenderId];
|
if (PlayerAnimSyncs.TryGetValue(message.SenderId, out var animSync) && animSync != this)
|
||||||
if (animSync != this)
|
|
||||||
{
|
{
|
||||||
animSync.HandleTrigger((AnimTrigger)message.TriggerId);
|
animSync.HandleTrigger((AnimTrigger)message.TriggerId);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,10 @@ namespace QSB.Animation
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (_to.runtimeAnimatorController != _from.runtimeAnimatorController)
|
||||||
|
{
|
||||||
|
_to.runtimeAnimatorController = _from.runtimeAnimatorController;
|
||||||
|
}
|
||||||
SyncParams();
|
SyncParams();
|
||||||
SmoothFloats();
|
SmoothFloats();
|
||||||
}
|
}
|
||||||
@ -52,9 +56,6 @@ namespace QSB.Animation
|
|||||||
case AnimatorControllerParameterType.Float:
|
case AnimatorControllerParameterType.Float:
|
||||||
_floatParams[fromParam.name].Target = _from.GetFloat(fromParam.name);
|
_floatParams[fromParam.name].Target = _from.GetFloat(fromParam.name);
|
||||||
break;
|
break;
|
||||||
case AnimatorControllerParameterType.Int:
|
|
||||||
_to.SetInteger(fromParam.name, _from.GetInteger(fromParam.name));
|
|
||||||
break;
|
|
||||||
case AnimatorControllerParameterType.Bool:
|
case AnimatorControllerParameterType.Bool:
|
||||||
_to.SetBool(fromParam.name, _from.GetBool(fromParam.name));
|
_to.SetBool(fromParam.name, _from.GetBool(fromParam.name));
|
||||||
break;
|
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.Common;
|
||||||
using OWML.ModHelper;
|
using OWML.ModHelper;
|
||||||
using QSB.TimeSync;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
|
|
||||||
@ -22,7 +21,6 @@ namespace QSB
|
|||||||
gameObject.AddComponent<DebugLog>();
|
gameObject.AddComponent<DebugLog>();
|
||||||
gameObject.AddComponent<QSBNetworkManager>();
|
gameObject.AddComponent<QSBNetworkManager>();
|
||||||
gameObject.AddComponent<NetworkManagerHUD>();
|
gameObject.AddComponent<NetworkManagerHUD>();
|
||||||
gameObject.AddComponent<PreserveTimeScale>();
|
|
||||||
gameObject.AddComponent<RespawnOnDeath>();
|
gameObject.AddComponent<RespawnOnDeath>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
<Compile Include="Animation\AnimFloatParam.cs" />
|
<Compile Include="Animation\AnimFloatParam.cs" />
|
||||||
<Compile Include="Animation\AnimTriggerMessage.cs" />
|
<Compile Include="Animation\AnimTriggerMessage.cs" />
|
||||||
<Compile Include="Animation\AnimTrigger.cs" />
|
<Compile Include="Animation\AnimTrigger.cs" />
|
||||||
|
<Compile Include="Animation\QSBNetAnim.cs" />
|
||||||
<Compile Include="DebugLog.cs" />
|
<Compile Include="DebugLog.cs" />
|
||||||
<Compile Include="Messaging\MessageHandler.cs" />
|
<Compile Include="Messaging\MessageHandler.cs" />
|
||||||
<Compile Include="Messaging\MessageType.cs" />
|
<Compile Include="Messaging\MessageType.cs" />
|
||||||
|
@ -1,15 +1,25 @@
|
|||||||
using UnityEngine;
|
using OWML.ModHelper.Events;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.TimeSync
|
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;
|
public override MessageType MessageType => MessageType.WakeUp;
|
||||||
|
|
||||||
private bool _wakeUp = true;
|
public float ServerTime { get; set; }
|
||||||
|
|
||||||
public override void Deserialize(NetworkReader reader)
|
public override void Deserialize(NetworkReader reader)
|
||||||
{
|
{
|
||||||
_wakeUp = reader.ReadBoolean();
|
ServerTime = reader.ReadSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Serialize(NetworkWriter writer)
|
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 QSB.Messaging;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
namespace QSB.TimeSync
|
namespace QSB.TimeSync
|
||||||
{
|
{
|
||||||
public class WakeUpSync : NetworkBehaviour
|
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 MessageHandler<WakeUpMessage> _wakeUpHandler;
|
||||||
|
private Campfire _campfire;
|
||||||
|
|
||||||
|
private float _sendTimer;
|
||||||
|
private float _serverTime;
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
@ -14,20 +26,46 @@ namespace QSB.TimeSync
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugLog.Screen("Start WakeUpSync");
|
DebugLog.Screen("Start WakeUpSync");
|
||||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||||
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||||
|
|
||||||
_wakeUpHandler = new MessageHandler<WakeUpMessage>();
|
_wakeUpHandler = new MessageHandler<WakeUpMessage>();
|
||||||
_wakeUpHandler.OnClientReceiveMessage += OnClientReceiveMessage;
|
_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()
|
private void OnWakeUp()
|
||||||
{
|
{
|
||||||
if (!isServer)
|
_state = State.Awake;
|
||||||
|
if (isServer)
|
||||||
{
|
{
|
||||||
return;
|
SendServerTime();
|
||||||
}
|
}
|
||||||
DebugLog.Screen("Sending wakeup to all my friends");
|
else
|
||||||
_wakeUpHandler.SendToAll(new WakeUpMessage());
|
{
|
||||||
|
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)
|
private void OnClientReceiveMessage(WakeUpMessage message)
|
||||||
@ -36,7 +74,45 @@ namespace QSB.TimeSync
|
|||||||
{
|
{
|
||||||
return;
|
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.
|
// 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.
|
// 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");
|
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
|
public abstract class TransformSync : NetworkBehaviour
|
||||||
{
|
{
|
||||||
private const float SmoothTime = 0.1f;
|
private const float SmoothTime = 0.1f;
|
||||||
|
private static bool _isAwake;
|
||||||
|
|
||||||
private Transform _syncedTransform;
|
private Transform _syncedTransform;
|
||||||
private bool _isSectorSetUp;
|
private bool _isSectorSetUp;
|
||||||
@ -15,7 +16,14 @@ namespace QSB.TransformSync
|
|||||||
protected virtual void Awake()
|
protected virtual void Awake()
|
||||||
{
|
{
|
||||||
DontDestroyOnLoad(this);
|
DontDestroyOnLoad(this);
|
||||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
if (_isAwake)
|
||||||
|
{
|
||||||
|
OnWakeUp();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Transform InitLocalTransform();
|
protected abstract Transform InitLocalTransform();
|
||||||
@ -23,6 +31,7 @@ namespace QSB.TransformSync
|
|||||||
|
|
||||||
private void OnWakeUp()
|
private void OnWakeUp()
|
||||||
{
|
{
|
||||||
|
_isAwake = true;
|
||||||
DebugLog.Screen("Start TransformSync", netId.Value);
|
DebugLog.Screen("Start TransformSync", netId.Value);
|
||||||
Invoke(nameof(SetFirstSector), 1);
|
Invoke(nameof(SetFirstSector), 1);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user