diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj index b4f026b0..44931cfa 100644 --- a/QSB/QSB.csproj +++ b/QSB/QSB.csproj @@ -15,7 +15,7 @@ pdbonly - + @@ -69,7 +69,7 @@ copy /y "$(OwmlDir)\OWML.Abstractions.dll" "$(UnityAssetsDir)" - + diff --git a/QSB/Syncs/QSBNetworkTransform.cs b/QSB/Syncs/QSBNetworkTransform.cs new file mode 100644 index 00000000..2af73244 --- /dev/null +++ b/QSB/Syncs/QSBNetworkTransform.cs @@ -0,0 +1,36 @@ +using Mirror; +using QSB.Utility; +using UnityEngine; + +namespace QSB.Syncs +{ + public class QSBNetworkTransform : QSBNetworkBehaviour + { + protected override float SendInterval => 0.05f; + + protected Vector3 _prevPosition; + protected Quaternion _prevRotation; + + protected override void UpdatePrevData() + { + _prevPosition = transform.position; + _prevRotation = transform.rotation; + } + + protected override bool HasChanged() => + Vector3.Distance(transform.position, _prevPosition) > 1E-05f || + Quaternion.Angle(transform.rotation, _prevRotation) > 1E-05f; + + protected override void Serialize(NetworkWriter writer, bool initialState) + { + writer.Write(transform.position); + writer.Write(transform.rotation); + } + + protected override void Deserialize(NetworkReader reader, bool initialState) + { + transform.position = reader.ReadVector3(); + transform.rotation = reader.ReadQuaternion(); + } + } +} diff --git a/QSB/Utility/QSBNetworkBehaviour.cs b/QSB/Utility/QSBNetworkBehaviour.cs new file mode 100644 index 00000000..36a4233b --- /dev/null +++ b/QSB/Utility/QSBNetworkBehaviour.cs @@ -0,0 +1,102 @@ +using Mirror; +using System; + +namespace QSB.Utility +{ + public abstract class QSBNetworkBehaviour : NetworkBehaviour + { + protected virtual float SendInterval => 0.1f; + protected virtual bool Unreliable => true; + + private double _lastSendTime; + + protected abstract bool HasChanged(); + protected abstract void UpdatePrevData(); + protected abstract void Serialize(NetworkWriter writer, bool initialState); + protected abstract void Deserialize(NetworkReader reader, bool initialState); + + public override bool OnSerialize(NetworkWriter writer, bool initialState) + { + var changed = base.OnSerialize(writer, initialState); + if (initialState && isServer) + { + Serialize(writer, true); + } + + return changed; + } + + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + base.OnDeserialize(reader, initialState); + if (initialState && !isServer) + { + UpdatePrevData(); + Deserialize(reader, true); + } + } + + protected virtual void Awake() => UpdatePrevData(); + + protected virtual void Update() + { + if (!isClient) + { + return; + } + + if (!hasAuthority) + { + return; + } + + if (!NetworkClient.ready) + { + return; + } + + if (NetworkTime.localTime >= _lastSendTime + SendInterval) + { + _lastSendTime = NetworkTime.localTime; + + if (!HasChanged()) + { + return; + } + + UpdatePrevData(); + using var writer = NetworkWriterPool.GetWriter(); + Serialize(writer, false); + + var data = writer.ToArraySegment(); + if (Unreliable) + { + CmdSendDataUnreliable(data); + } + else + { + CmdSendDataReliable(data); + } + } + } + + [Command(channel = Channels.Unreliable, requiresAuthority = true)] + private void CmdSendDataUnreliable(ArraySegment data) => RpcSendDataUnreliable(data); + + [ClientRpc(channel = Channels.Unreliable, includeOwner = false)] + private void RpcSendDataUnreliable(ArraySegment data) => OnData(data); + + [Command(channel = Channels.Reliable, requiresAuthority = true)] + private void CmdSendDataReliable(ArraySegment data) => RpcSendDataReliable(data); + + [ClientRpc(channel = Channels.Reliable, includeOwner = false)] + private void RpcSendDataReliable(ArraySegment data) => OnData(data); + + private void OnData(ArraySegment data) + { + UpdatePrevData(); + using var reader = NetworkReaderPool.GetReader(data); + Deserialize(reader, false); + } + } +}