Compare commits

..

9 Commits

Author SHA1 Message Date
miwarnec
8e83da26b4 cleanup: remove ContructSnapshot 2024-11-05 13:03:06 +01:00
miwarnec
ae1edff268 comments 2024-11-05 12:59:36 +01:00
miwarnec
e70be519e7 cleanups 2024-11-05 12:57:36 +01:00
miwarnec
6e71c5e918 cleanup 2024-11-05 12:03:40 +01:00
miwarnec
51947ba9b5 comments 2024-11-05 11:55:09 +01:00
miwarnec
4eb1a62f18 remove unused 2024-11-05 11:54:45 +01:00
miwarnec
741efbd227 don't pass Vector3? and QUaternion? 2024-11-05 11:50:54 +01:00
miwarnec
c55e8731c8 syntax 2024-11-05 11:49:49 +01:00
miwarnec
3af336f665 icon 2024-11-05 11:07:39 +01:00
2 changed files with 21 additions and 86 deletions

View File

@ -54,8 +54,8 @@ public class NetworkTransformHybrid2022 : NetworkBehaviour
// save last deserialized baseline to delta decompress against // save last deserialized baseline to delta decompress against
byte lastDeserializedBaselineTick = 0; byte lastDeserializedBaselineTick = 0;
Vector3 lastDeserializedBaselinePosition = Vector3.zero; Vector3 lastDeserializedBaselinePosition = Vector3.zero; // unused, but keep for delta
Quaternion lastDeserializedBaselineRotation = Quaternion.identity; Quaternion lastDeserializedBaselineRotation = Quaternion.identity; // unused, but keep for delta
// only sync when changed hack ///////////////////////////////////////// // only sync when changed hack /////////////////////////////////////////
[Header("Sync Only If Changed")] [Header("Sync Only If Changed")]
@ -107,14 +107,6 @@ public class NetworkTransformHybrid2022 : NetworkBehaviour
public bool showOverlay; public bool showOverlay;
public Color overlayColor = new Color(0, 0, 0, 0.5f); public Color overlayColor = new Color(0, 0, 0, 0.5f);
// caching /////////////////////////////////////////////////////////////
// squared values for faster distance checks
// float positionPrecisionSqr;
// float scalePrecisionSqr;
// dedicated writer to avoid Pool.Get calls. NT is in hot path.
readonly NetworkWriter writer = new NetworkWriter();
// initialization ////////////////////////////////////////////////////// // initialization //////////////////////////////////////////////////////
// make sure to call this when inheriting too! // make sure to call this when inheriting too!
protected virtual void Awake() {} protected virtual void Awake() {}
@ -130,26 +122,6 @@ protected override void OnValidate()
syncInterval = 0; syncInterval = 0;
} }
// snapshot functions //////////////////////////////////////////////////
// construct a snapshot of the current state
// => internal for testing
protected virtual TransformSnapshot ConstructSnapshot()
{
// perf
target.GetLocalPositionAndRotation(out Vector3 localPosition, out Quaternion localRotation);
// NetworkTime.localTime for double precision until Unity has it too
return new TransformSnapshot(
// our local time is what the other end uses as remote time
Time.timeAsDouble,
// the other end fills out local time itself
0,
localPosition, // target.localPosition,
localRotation, // target.localRotation,
Vector3.zero // target.localScale
);
}
// apply a snapshot to the Transform. // apply a snapshot to the Transform.
// -> start, end, interpolated are all passed in caes they are needed // -> start, end, interpolated are all passed in caes they are needed
// -> a regular game would apply the 'interpolated' snapshot // -> a regular game would apply the 'interpolated' snapshot
@ -183,8 +155,6 @@ bool Changed(Vector3 currentPosition, Quaternion currentRotation)//, Vector3 cur
{ {
float positionDelta = Vector3.Distance(currentPosition, lastSerializedBaselinePosition); float positionDelta = Vector3.Distance(currentPosition, lastSerializedBaselinePosition);
if (positionDelta >= positionSensitivity) if (positionDelta >= positionSensitivity)
// float positionChange = (currentPosition - lastPosition).sqrMagnitude;
// if (positionChange >= positionPrecisionSqr)
{ {
return true; return true;
} }
@ -276,7 +246,7 @@ void CmdClientToServerDelta_PositionRotation(byte baselineTick, Vector3 position
} }
// local authority client sends sync message to server for broadcasting // local authority client sends sync message to server for broadcasting
protected virtual void OnClientToServerDeltaSync(byte baselineTick, Vector3? position, Quaternion? rotation)//, Vector3? scale) protected virtual void OnClientToServerDeltaSync(byte baselineTick, Vector3 position, Quaternion rotation)//, Vector3 scale)
{ {
// only apply if in client authority mode // only apply if in client authority mode
if (syncDirection != SyncDirection.ClientToServer) return; if (syncDirection != SyncDirection.ClientToServer) return;
@ -286,10 +256,7 @@ protected virtual void OnClientToServerDeltaSync(byte baselineTick, Vector3? pos
if (baselineTick != lastDeserializedBaselineTick) if (baselineTick != lastDeserializedBaselineTick)
{ {
// debug draw: drop // debug draw: drop
if (debugDraw) if (debugDraw) Debug.DrawLine(position, position + Vector3.up, Color.red, 10f);
{
if (position.HasValue) Debug.DrawLine(position.Value, position.Value + Vector3.up, Color.red, 10f);
}
// this can happen if unreliable arrives before reliable etc. // this can happen if unreliable arrives before reliable etc.
// no need to log this except when debugging. // no need to log this except when debugging.
@ -304,19 +271,6 @@ protected virtual void OnClientToServerDeltaSync(byte baselineTick, Vector3? pos
// server. we can get the timestamp from the connection. // server. we can get the timestamp from the connection.
double timestamp = connectionToClient.remoteTimeStamp; double timestamp = connectionToClient.remoteTimeStamp;
// position, rotation, scale can have no value if same as last time.
// saves bandwidth.
// but we still need to feed it to snapshot interpolation. we can't
// just have gaps in there if nothing has changed. for example, if
// client sends snapshot at t=0
// client sends nothing for 10s because not moved
// client sends snapshot at t=10
// then the server would assume that it's one super slow move and
// replay it for 10 seconds.
if (!position.HasValue) position = serverSnapshots.Count > 0 ? serverSnapshots.Values[serverSnapshots.Count - 1].position : target.localPosition;
if (!rotation.HasValue) rotation = serverSnapshots.Count > 0 ? serverSnapshots.Values[serverSnapshots.Count - 1].rotation : target.localRotation;
// if (!scale.HasValue) scale = serverSnapshots.Count > 0 ? serverSnapshots.Values[serverSnapshots.Count - 1].scale : target.localScale;
// insert transform snapshot // insert transform snapshot
SnapshotInterpolation.InsertIfNotExists( SnapshotInterpolation.InsertIfNotExists(
serverSnapshots, serverSnapshots,
@ -324,8 +278,8 @@ protected virtual void OnClientToServerDeltaSync(byte baselineTick, Vector3? pos
new TransformSnapshot( new TransformSnapshot(
timestamp, // arrival remote timestamp. NOT remote time. timestamp, // arrival remote timestamp. NOT remote time.
Time.timeAsDouble, Time.timeAsDouble,
position.Value, position,
rotation.Value, rotation,
Vector3.one // scale Vector3.one // scale
)); ));
} }
@ -474,10 +428,7 @@ protected virtual void OnServerToClientDeltaSync(byte baselineTick, Vector3 posi
if (baselineTick != lastDeserializedBaselineTick) if (baselineTick != lastDeserializedBaselineTick)
{ {
// debug draw: drop // debug draw: drop
if (debugDraw) if (debugDraw) Debug.DrawLine(position, position + Vector3.up, Color.red, 10f);
{
Debug.DrawLine(position, position + Vector3.up, Color.red, 10f);
}
// this can happen if unreliable arrives before reliable etc. // this can happen if unreliable arrives before reliable etc.
// no need to log this except when debugging. // no need to log this except when debugging.
@ -540,20 +491,17 @@ void UpdateServerBaseline(double localTime)
byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once! byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once!
if (syncPosition && syncRotation) if (syncPosition && syncRotation)
{ {
// send snapshot without timestamp. // no unreliable redundancy: baseline is reliable
// receiver gets it from batch timestamp to save bandwidth.
RpcServerToClientBaseline_PositionRotation(frameCount, position, rotation); RpcServerToClientBaseline_PositionRotation(frameCount, position, rotation);
} }
else if (syncPosition) else if (syncPosition)
{ {
// send snapshot without timestamp. // no unreliable redundancy: baseline is reliable
// receiver gets it from batch timestamp to save bandwidth.
RpcServerToClientBaseline_Position(frameCount, position); RpcServerToClientBaseline_Position(frameCount, position);
} }
else if (syncRotation) else if (syncRotation)
{ {
// send snapshot without timestamp. // no unreliable redundancy: baseline is reliable
// receiver gets it from batch timestamp to save bandwidth.
RpcServerToClientBaseline_Rotation(frameCount, rotation); RpcServerToClientBaseline_Rotation(frameCount, rotation);
} }
@ -640,8 +588,6 @@ void UpdateServerDelta(double localTime)
// -> Vector3? and Quaternion? nullables takes more bandwidth // -> Vector3? and Quaternion? nullables takes more bandwidth
if (syncPosition && syncRotation) if (syncPosition && syncRotation)
{ {
// send snapshot without timestamp.
// receiver gets it from batch timestamp to save bandwidth.
// unreliable redundancy to make up for potential message drops // unreliable redundancy to make up for potential message drops
RpcServerToClientDelta_PositionRotation(lastSerializedBaselineTick, position, rotation); RpcServerToClientDelta_PositionRotation(lastSerializedBaselineTick, position, rotation);
if (unreliableRedundancy) if (unreliableRedundancy)
@ -649,8 +595,6 @@ void UpdateServerDelta(double localTime)
} }
else if (syncPosition) else if (syncPosition)
{ {
// send snapshot without timestamp.
// receiver gets it from batch timestamp to save bandwidth.
// unreliable redundancy to make up for potential message drops // unreliable redundancy to make up for potential message drops
RpcServerToClientDelta_Position(lastSerializedBaselineTick, position); RpcServerToClientDelta_Position(lastSerializedBaselineTick, position);
if (unreliableRedundancy) if (unreliableRedundancy)
@ -658,8 +602,6 @@ void UpdateServerDelta(double localTime)
} }
else if (syncRotation) else if (syncRotation)
{ {
// send snapshot without timestamp.
// receiver gets it from batch timestamp to save bandwidth.
// unreliable redundancy to make up for potential message drops // unreliable redundancy to make up for potential message drops
RpcServerToClientDelta_Rotation(lastSerializedBaselineTick, rotation); RpcServerToClientDelta_Rotation(lastSerializedBaselineTick, rotation);
if (unreliableRedundancy) if (unreliableRedundancy)
@ -741,20 +683,17 @@ void UpdateClientBaseline(double localTime)
byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once! byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once!
if (syncPosition && syncRotation) if (syncPosition && syncRotation)
{ {
// send snapshot without timestamp. // no unreliable redundancy: baseline is reliable
// receiver gets it from batch timestamp to save bandwidth.
CmdClientToServerBaseline_PositionRotation(frameCount, position, rotation); CmdClientToServerBaseline_PositionRotation(frameCount, position, rotation);
} }
else if (syncPosition) else if (syncPosition)
{ {
// send snapshot without timestamp. // no unreliable redundancy: baseline is reliable
// receiver gets it from batch timestamp to save bandwidth.
CmdClientToServerBaseline_Position(frameCount, position); CmdClientToServerBaseline_Position(frameCount, position);
} }
else if (syncRotation) else if (syncRotation)
{ {
// send snapshot without timestamp. // no unreliable redundancy: baseline is reliable
// receiver gets it from batch timestamp to save bandwidth.
CmdClientToServerBaseline_Rotation(frameCount, rotation); CmdClientToServerBaseline_Rotation(frameCount, rotation);
} }
@ -831,8 +770,6 @@ void UpdateClientDelta(double localTime)
// -> Vector3? and Quaternion? nullables takes more bandwidth // -> Vector3? and Quaternion? nullables takes more bandwidth
if (syncPosition && syncRotation) if (syncPosition && syncRotation)
{ {
// send snapshot without timestamp.
// receiver gets it from batch timestamp to save bandwidth.
// unreliable redundancy to make up for potential message drops // unreliable redundancy to make up for potential message drops
CmdClientToServerDelta_PositionRotation(lastSerializedBaselineTick, position, rotation); CmdClientToServerDelta_PositionRotation(lastSerializedBaselineTick, position, rotation);
if (unreliableRedundancy) if (unreliableRedundancy)
@ -841,8 +778,6 @@ void UpdateClientDelta(double localTime)
} }
else if (syncPosition) else if (syncPosition)
{ {
// send snapshot without timestamp.
// receiver gets it from batch timestamp to save bandwidth.
// unreliable redundancy to make up for potential message drops // unreliable redundancy to make up for potential message drops
CmdClientToServerDelta_Position(lastSerializedBaselineTick, position); CmdClientToServerDelta_Position(lastSerializedBaselineTick, position);
if (unreliableRedundancy) if (unreliableRedundancy)
@ -850,8 +785,6 @@ void UpdateClientDelta(double localTime)
} }
else if (syncRotation) else if (syncRotation)
{ {
// send snapshot without timestamp.
// receiver gets it from batch timestamp to save bandwidth.
// unreliable redundancy to make up for potential message drops // unreliable redundancy to make up for potential message drops
CmdClientToServerDelta_Rotation(lastSerializedBaselineTick, rotation); CmdClientToServerDelta_Rotation(lastSerializedBaselineTick, rotation);
if (unreliableRedundancy) if (unreliableRedundancy)
@ -1067,14 +1000,16 @@ public override void OnSerialize(NetworkWriter writer, bool initialState)
if (initialState) if (initialState)
{ {
// spawn message is used as first baseline. // spawn message is used as first baseline.
TransformSnapshot snapshot = ConstructSnapshot(); // perf: get position/rotation directly. TransformSnapshot is too expensive.
// TransformSnapshot snapshot = ConstructSnapshot();
target.GetLocalPositionAndRotation(out Vector3 position, out Quaternion rotation);
// always include the tick for deltas to compare against. // always include the tick for deltas to compare against.
byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once! byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once!
writer.WriteByte(frameCount); writer.WriteByte(frameCount);
if (syncPosition) writer.WriteVector3(snapshot.position); if (syncPosition) writer.WriteVector3(position);
if (syncRotation) writer.WriteQuaternion(snapshot.rotation); if (syncRotation) writer.WriteQuaternion(rotation);
// IMPORTANT // IMPORTANT
// OnSerialize(initial) is called for the spawn payload whenever // OnSerialize(initial) is called for the spawn payload whenever
@ -1088,8 +1023,8 @@ public override void OnSerialize(NetworkWriter writer, bool initialState)
// => client's baseline is t=2 but receives delta for t=1 _!_ // => client's baseline is t=2 but receives delta for t=1 _!_
lastSerializedBaselineTick = frameCount; lastSerializedBaselineTick = frameCount;
lastBaselineTime = NetworkTime.localTime; lastBaselineTime = NetworkTime.localTime;
lastSerializedBaselinePosition = snapshot.position; lastSerializedBaselinePosition = position;
lastSerializedBaselineRotation = snapshot.rotation; lastSerializedBaselineRotation = rotation;
} }
} }

View File

@ -5,7 +5,7 @@ MonoImporter:
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0
icon: {instanceID: 0} icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant: