mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
perf: only send necessary baseline parameters
This commit is contained in:
parent
195bd087ed
commit
bc7d8cdf72
@ -232,90 +232,38 @@ bool Changed(Vector3 currentPosition, Quaternion currentRotation)//, Vector3 cur
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialization ///////////////////////////////////////////////////////
|
// cmd baseline ////////////////////////////////////////////////////////
|
||||||
// serialize server->client baseline into a NetworkWriter.
|
|
||||||
// for use in RpcSync and OnSerialize for spawn message.
|
|
||||||
void SerializeBaseline(NetworkWriter writer, Vector3 position, Quaternion rotation)//, Vector3 scale)
|
|
||||||
{
|
|
||||||
// always include the tick for deltas to compare against.
|
|
||||||
byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once!
|
|
||||||
writer.WriteByte(frameCount);
|
|
||||||
|
|
||||||
if (syncPosition)
|
|
||||||
{
|
|
||||||
writer.WriteVector3(position);
|
|
||||||
|
|
||||||
// save serialized as 'last' for next delta compression.
|
|
||||||
// Compression.ScaleToLong(position, positionPrecision, out lastSerializedPosition);
|
|
||||||
}
|
|
||||||
if (syncRotation)
|
|
||||||
{
|
|
||||||
writer.WriteQuaternion(rotation);
|
|
||||||
|
|
||||||
// save serialized as 'last' for next delta compression.
|
|
||||||
// Compression.ScaleToLong(rotation, rotationPrecision, out lastSerializedRotation);
|
|
||||||
}
|
|
||||||
// if (syncScale)
|
|
||||||
// {
|
|
||||||
// writer.WriteVector3(target.localScale);
|
|
||||||
//
|
|
||||||
// // save serialized as 'last' for next delta compression.
|
|
||||||
// if (syncScale) Compression.ScaleToLong(scale, scalePrecision, out lastSerializedScale);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// save the last baseline's tick number.
|
|
||||||
// included in baseline to identify which one it was on client
|
|
||||||
// included in deltas to ensure they are on top of the correct baseline
|
|
||||||
lastSerializedBaselineTick = frameCount;
|
|
||||||
lastBaselineTime = NetworkTime.localTime;
|
|
||||||
|
|
||||||
// set 'last'
|
|
||||||
lastPosition = position;
|
|
||||||
lastRotation = rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeserializeBaseline(NetworkReader reader, out byte baselineTick, out Vector3 position, out Quaternion rotation)
|
|
||||||
{
|
|
||||||
// save last deserialized baseline tick number to compare deltas against
|
|
||||||
lastDeserializedBaselineTick = baselineTick = reader.ReadByte();
|
|
||||||
position = default;
|
|
||||||
rotation = default;
|
|
||||||
|
|
||||||
if (syncPosition)
|
|
||||||
{
|
|
||||||
position = reader.ReadVector3();
|
|
||||||
// save deserialized as 'last' for next delta compression.
|
|
||||||
// Compression.ScaleToLong(position, positionPrecision, out lastDeserializedPosition);
|
|
||||||
}
|
|
||||||
if (syncRotation)
|
|
||||||
{
|
|
||||||
rotation = reader.ReadQuaternion();
|
|
||||||
// save deserialized as 'last' for next delta compression.
|
|
||||||
// Compression.ScaleToLong(rotation, rotationPrecision, out lastDeserializedRotation);
|
|
||||||
}
|
|
||||||
// if (syncScale)
|
|
||||||
// {
|
|
||||||
// Vector3 scale = reader.ReadVector3();
|
|
||||||
// // save deserialized as 'last' for next delta compression.
|
|
||||||
// Compression.ScaleToLong(scale, scalePrecision, out lastDeserializedScale);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// cmd /////////////////////////////////////////////////////////////////
|
|
||||||
[Command(channel = Channels.Reliable)] // reliable baseline
|
[Command(channel = Channels.Reliable)] // reliable baseline
|
||||||
void CmdClientToServerBaselineSync(ArraySegment<byte> message)
|
void CmdClientToServerBaseline_PositionRotation(byte baselineTick, Vector3 position, Quaternion rotation)
|
||||||
{
|
{
|
||||||
using (NetworkReaderPooled reader = NetworkReaderPool.Get(message))
|
lastDeserializedBaselineTick = baselineTick;
|
||||||
{
|
|
||||||
DeserializeBaseline(reader, out byte baselineTick, out Vector3 position, out Quaternion rotation);
|
|
||||||
// Debug.Log($"[{name}] server received baseline #{lastDeserializedBaselineTick}");
|
|
||||||
|
|
||||||
// if baseline counts as delta, insert it into snapshot buffer too
|
// if baseline counts as delta, insert it into snapshot buffer too
|
||||||
if (baselineIsDelta)
|
if (baselineIsDelta)
|
||||||
OnClientToServerDeltaSync(baselineTick, position, rotation);//, scale);
|
OnClientToServerDeltaSync(baselineTick, position, rotation);//, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Command(channel = Channels.Reliable)] // reliable baseline
|
||||||
|
void CmdClientToServerBaseline_Position(byte baselineTick, Vector3 position)
|
||||||
|
{
|
||||||
|
lastDeserializedBaselineTick = baselineTick;
|
||||||
|
|
||||||
|
// if baseline counts as delta, insert it into snapshot buffer too
|
||||||
|
if (baselineIsDelta)
|
||||||
|
OnClientToServerDeltaSync(baselineTick, position, Quaternion.identity);//, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Command(channel = Channels.Reliable)] // reliable baseline
|
||||||
|
void CmdClientToServerBaseline_Rotation(byte baselineTick, Quaternion rotation)
|
||||||
|
{
|
||||||
|
lastDeserializedBaselineTick = baselineTick;
|
||||||
|
|
||||||
|
// if baseline counts as delta, insert it into snapshot buffer too
|
||||||
|
if (baselineIsDelta)
|
||||||
|
OnClientToServerDeltaSync(baselineTick, Vector3.zero, rotation);//, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cmd delta ///////////////////////////////////////////////////////////
|
||||||
[Command(channel = Channels.Unreliable)] // unreliable delta
|
[Command(channel = Channels.Unreliable)] // unreliable delta
|
||||||
void CmdClientToServerDelta_Position(byte baselineTick, Vector3 position)
|
void CmdClientToServerDelta_Position(byte baselineTick, Vector3 position)
|
||||||
{
|
{
|
||||||
@ -376,25 +324,53 @@ protected virtual void OnClientToServerDeltaSync(byte baselineTick, Vector3? pos
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// rpc /////////////////////////////////////////////////////////////////
|
// rpc baseline ////////////////////////////////////////////////////////
|
||||||
[ClientRpc(channel = Channels.Reliable)] // reliable baseline
|
[ClientRpc(channel = Channels.Reliable)] // reliable baseline
|
||||||
void RpcServerToClientBaselineSync(ArraySegment<byte> message)
|
void RpcServerToClientBaseline_PositionRotation(byte baselineTick, Vector3 position, Quaternion rotation)
|
||||||
{
|
{
|
||||||
// baseline is broadcast to all clients.
|
// baseline is broadcast to all clients.
|
||||||
// ignore if this object is owned by this client.
|
// ignore if this object is owned by this client.
|
||||||
if (IsClientWithAuthority) return;
|
if (IsClientWithAuthority) return;
|
||||||
|
|
||||||
using (NetworkReaderPooled reader = NetworkReaderPool.Get(message))
|
// save last deserialized baseline tick number to compare deltas against
|
||||||
{
|
lastDeserializedBaselineTick = baselineTick;
|
||||||
DeserializeBaseline(reader, out byte baselineTick, out Vector3 position, out Quaternion rotation);
|
|
||||||
// Debug.Log($"[{name}] client received baseline #{lastDeserializedBaselineTick} for {name}");
|
|
||||||
|
|
||||||
// if baseline counts as delta, insert it into snapshot buffer too
|
// if baseline counts as delta, insert it into snapshot buffer too
|
||||||
if (baselineIsDelta)
|
if (baselineIsDelta)
|
||||||
OnServerToClientDeltaSync(baselineTick, position, rotation);//, Vector3.zero);//, scale);
|
OnServerToClientDeltaSync(baselineTick, position, rotation);//, Vector3.zero);//, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ClientRpc(channel = Channels.Reliable)] // reliable baseline
|
||||||
|
void RpcServerToClientBaseline_Position(byte baselineTick, Vector3 position)
|
||||||
|
{
|
||||||
|
// baseline is broadcast to all clients.
|
||||||
|
// ignore if this object is owned by this client.
|
||||||
|
if (IsClientWithAuthority) return;
|
||||||
|
|
||||||
|
// save last deserialized baseline tick number to compare deltas against
|
||||||
|
lastDeserializedBaselineTick = baselineTick;
|
||||||
|
|
||||||
|
// if baseline counts as delta, insert it into snapshot buffer too
|
||||||
|
if (baselineIsDelta)
|
||||||
|
OnServerToClientDeltaSync(baselineTick, position, Quaternion.identity);//, Vector3.zero);//, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ClientRpc(channel = Channels.Reliable)] // reliable baseline
|
||||||
|
void RpcServerToClientBaseline_Rotation(byte baselineTick, Quaternion rotation)
|
||||||
|
{
|
||||||
|
// baseline is broadcast to all clients.
|
||||||
|
// ignore if this object is owned by this client.
|
||||||
|
if (IsClientWithAuthority) return;
|
||||||
|
|
||||||
|
// save last deserialized baseline tick number to compare deltas against
|
||||||
|
lastDeserializedBaselineTick = baselineTick;
|
||||||
|
|
||||||
|
// if baseline counts as delta, insert it into snapshot buffer too
|
||||||
|
if (baselineIsDelta)
|
||||||
|
OnServerToClientDeltaSync(baselineTick, Vector3.zero, rotation);//, Vector3.zero);//, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rpc delta ///////////////////////////////////////////////////////////
|
||||||
[ClientRpc(channel = Channels.Unreliable)] // unreliable delta
|
[ClientRpc(channel = Channels.Unreliable)] // unreliable delta
|
||||||
void RpcServerToClientDelta_PositionRotation(byte baselineTick, Vector3 position, Quaternion rotation)
|
void RpcServerToClientDelta_PositionRotation(byte baselineTick, Vector3 position, Quaternion rotation)
|
||||||
{
|
{
|
||||||
@ -497,15 +473,34 @@ void UpdateServerBaseline(double localTime)
|
|||||||
// reliable just changed. keep sending deltas until it's unchanged again.
|
// reliable just changed. keep sending deltas until it's unchanged again.
|
||||||
baselineDirty = true;
|
baselineDirty = true;
|
||||||
|
|
||||||
|
// save bandwidth by only transmitting what is needed.
|
||||||
|
// -> ArraySegment with random data is slower since byte[] copying
|
||||||
|
// -> Vector3? and Quaternion? nullables takes more bandwidth
|
||||||
|
byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once!
|
||||||
|
if (syncPosition && syncRotation)
|
||||||
|
{
|
||||||
// send snapshot without timestamp.
|
// send snapshot without timestamp.
|
||||||
// receiver gets it from batch timestamp to save bandwidth.
|
// receiver gets it from batch timestamp to save bandwidth.
|
||||||
// reuse cached writer for performance
|
RpcServerToClientBaseline_PositionRotation(frameCount, position, rotation);
|
||||||
// using (NetworkWriterPooled writer = NetworkWriterPool.Get())
|
|
||||||
writer.Position = 0;
|
|
||||||
{
|
|
||||||
SerializeBaseline(writer, position, rotation);//, scale);
|
|
||||||
RpcServerToClientBaselineSync(writer);
|
|
||||||
}
|
}
|
||||||
|
else if (syncPosition)
|
||||||
|
{
|
||||||
|
// send snapshot without timestamp.
|
||||||
|
// receiver gets it from batch timestamp to save bandwidth.
|
||||||
|
RpcServerToClientBaseline_Position(frameCount, position);
|
||||||
|
}
|
||||||
|
else if (syncRotation)
|
||||||
|
{
|
||||||
|
// send snapshot without timestamp.
|
||||||
|
// receiver gets it from batch timestamp to save bandwidth.
|
||||||
|
RpcServerToClientBaseline_Rotation(frameCount, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the last baseline's tick number.
|
||||||
|
// included in baseline to identify which one it was on client
|
||||||
|
// included in deltas to ensure they are on top of the correct baseline
|
||||||
|
lastSerializedBaselineTick = frameCount;
|
||||||
|
lastBaselineTime = NetworkTime.localTime;
|
||||||
|
|
||||||
// perf. & bandwidth optimization:
|
// perf. & bandwidth optimization:
|
||||||
// send a delta right after baseline to avoid potential head of
|
// send a delta right after baseline to avoid potential head of
|
||||||
@ -673,15 +668,38 @@ void UpdateClientBaseline(double localTime)
|
|||||||
// reliable just changed. keep sending deltas until it's unchanged again.
|
// reliable just changed. keep sending deltas until it's unchanged again.
|
||||||
baselineDirty = true;
|
baselineDirty = true;
|
||||||
|
|
||||||
|
// save bandwidth by only transmitting what is needed.
|
||||||
|
// -> ArraySegment with random data is slower since byte[] copying
|
||||||
|
// -> Vector3? and Quaternion? nullables takes more bandwidth
|
||||||
|
byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once!
|
||||||
|
if (syncPosition && syncRotation)
|
||||||
|
{
|
||||||
// send snapshot without timestamp.
|
// send snapshot without timestamp.
|
||||||
// receiver gets it from batch timestamp to save bandwidth.
|
// receiver gets it from batch timestamp to save bandwidth.
|
||||||
// reuse cached writer for performance
|
CmdClientToServerBaseline_PositionRotation(frameCount, position, rotation);
|
||||||
// using (NetworkWriterPooled writer = NetworkWriterPool.Get())
|
|
||||||
writer.Position = 0;
|
|
||||||
{
|
|
||||||
SerializeBaseline(writer, position, rotation);//, scale);
|
|
||||||
CmdClientToServerBaselineSync(writer);
|
|
||||||
}
|
}
|
||||||
|
else if (syncPosition)
|
||||||
|
{
|
||||||
|
// send snapshot without timestamp.
|
||||||
|
// receiver gets it from batch timestamp to save bandwidth.
|
||||||
|
CmdClientToServerBaseline_Position(frameCount, position);
|
||||||
|
}
|
||||||
|
else if (syncRotation)
|
||||||
|
{
|
||||||
|
// send snapshot without timestamp.
|
||||||
|
// receiver gets it from batch timestamp to save bandwidth.
|
||||||
|
CmdClientToServerBaseline_Rotation(frameCount, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the last baseline's tick number.
|
||||||
|
// included in baseline to identify which one it was on client
|
||||||
|
// included in deltas to ensure they are on top of the correct baseline
|
||||||
|
lastSerializedBaselineTick = frameCount;
|
||||||
|
lastBaselineTime = NetworkTime.localTime;
|
||||||
|
|
||||||
|
// set 'last'
|
||||||
|
lastPosition = position;
|
||||||
|
lastRotation = rotation;
|
||||||
|
|
||||||
// perf. & bandwidth optimization:
|
// perf. & bandwidth optimization:
|
||||||
// send a delta right after baseline to avoid potential head of
|
// send a delta right after baseline to avoid potential head of
|
||||||
@ -978,7 +996,23 @@ public override void OnSerialize(NetworkWriter writer, bool initialState)
|
|||||||
{
|
{
|
||||||
// spawn message is used as first baseline.
|
// spawn message is used as first baseline.
|
||||||
TransformSnapshot snapshot = ConstructSnapshot();
|
TransformSnapshot snapshot = ConstructSnapshot();
|
||||||
SerializeBaseline(writer, snapshot.position, snapshot.rotation);//, snapshot.scale);
|
|
||||||
|
// always include the tick for deltas to compare against.
|
||||||
|
byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once!
|
||||||
|
writer.WriteByte(frameCount);
|
||||||
|
|
||||||
|
if (syncPosition) writer.WriteVector3(snapshot.position);
|
||||||
|
if (syncRotation) writer.WriteQuaternion(snapshot.rotation);
|
||||||
|
|
||||||
|
// save the last baseline's tick number.
|
||||||
|
// included in baseline to identify which one it was on client
|
||||||
|
// included in deltas to ensure they are on top of the correct baseline
|
||||||
|
lastSerializedBaselineTick = frameCount;
|
||||||
|
lastBaselineTime = NetworkTime.localTime;
|
||||||
|
|
||||||
|
// set 'last'
|
||||||
|
lastPosition = snapshot.position;
|
||||||
|
lastRotation = snapshot.rotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,13 +1023,17 @@ public override void OnDeserialize(NetworkReader reader, bool initialState)
|
|||||||
// (Spawn message wouldn't sync NTChild positions either)
|
// (Spawn message wouldn't sync NTChild positions either)
|
||||||
if (initialState)
|
if (initialState)
|
||||||
{
|
{
|
||||||
// save spawn message as baseline
|
// save last deserialized baseline tick number to compare deltas against
|
||||||
DeserializeBaseline(reader, out byte baselineTick, out Vector3 position, out Quaternion rotation);
|
lastDeserializedBaselineTick = reader.ReadByte();
|
||||||
// Debug.Log($"[{name}] Spawn is used as first baseline #{lastDeserializedBaselineTick}");
|
Vector3 position = Vector3.zero;
|
||||||
|
Quaternion rotation = Quaternion.identity;
|
||||||
|
|
||||||
|
if (syncPosition) position = reader.ReadVector3();
|
||||||
|
if (syncRotation) rotation = reader.ReadQuaternion();
|
||||||
|
|
||||||
// if baseline counts as delta, insert it into snapshot buffer too
|
// if baseline counts as delta, insert it into snapshot buffer too
|
||||||
if (baselineIsDelta)
|
if (baselineIsDelta)
|
||||||
OnServerToClientDeltaSync(baselineTick, position, rotation);//, scale);
|
OnServerToClientDeltaSync(lastDeserializedBaselineTick, position, rotation);//, scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// CUSTOM CHANGE ///////////////////////////////////////////////////////////
|
// CUSTOM CHANGE ///////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user