chore(CI): Old code removed from NetworkTransformUnreliable (#3867)

* NetworkTransformUnreliable, removed old code.

* NetworkTransformUnreliable, removed old code.

Missed some, sneaky bugger.

* NetworkTransformUnreliable, tests updated (badly).

Needs looking over.
This commit is contained in:
JesusLuvsYooh 2024-07-21 17:51:27 +01:00 committed by GitHub
parent 2bb1dc5792
commit d1a4b33370
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 48 additions and 244 deletions

View File

@ -14,8 +14,6 @@ public class NetworkTransformUnreliable : NetworkTransformBase
// Testing under really bad network conditions, 2%-5% packet loss and 250-1200ms ping, 5 proved to eliminate any twitching, however this should not be the default as it is a rare case Developers may want to cover. // Testing under really bad network conditions, 2%-5% packet loss and 250-1200ms ping, 5 proved to eliminate any twitching, however this should not be the default as it is a rare case Developers may want to cover.
[Tooltip("How much time, as a multiple of send interval, has passed before clearing buffers.\nA larger buffer means more delay, but results in smoother movement.\nExample: 1 for faster responses minimal smoothing, 5 covers bad pings but has noticable delay, 3 is recommended for balanced results,.")] [Tooltip("How much time, as a multiple of send interval, has passed before clearing buffers.\nA larger buffer means more delay, but results in smoother movement.\nExample: 1 for faster responses minimal smoothing, 5 covers bad pings but has noticable delay, 3 is recommended for balanced results,.")]
public float bufferResetMultiplier = 3; public float bufferResetMultiplier = 3;
[Tooltip("Detect and send only changed data, such as Position X and Z, not the full Vector3 of X Y Z. Lowers network data at cost of extra calculations.")]
public bool changedDetection = true;
[Header("Sensitivity"), Tooltip("Sensitivity of changes needed before an updated state is sent over the network")] [Header("Sensitivity"), Tooltip("Sensitivity of changes needed before an updated state is sent over the network")]
public float positionSensitivity = 0.01f; public float positionSensitivity = 0.01f;
@ -117,8 +115,6 @@ void UpdateServerBroadcast()
// receiver gets it from batch timestamp to save bandwidth. // receiver gets it from batch timestamp to save bandwidth.
TransformSnapshot snapshot = Construct(); TransformSnapshot snapshot = Construct();
if (changedDetection)
{
cachedChangedComparison = CompareChangedSnapshots(snapshot); cachedChangedComparison = CompareChangedSnapshots(snapshot);
if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; } if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; }
@ -137,49 +133,6 @@ void UpdateServerBroadcast()
UpdateLastSentSnapshot(cachedChangedComparison, snapshot); UpdateLastSentSnapshot(cachedChangedComparison, snapshot);
} }
} }
else
{
cachedSnapshotComparison = CompareSnapshots(snapshot);
if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; }
if (compressRotation)
{
RpcServerToClientSyncCompressRotation(
// only sync what the user wants to sync
syncPosition && positionChanged ? snapshot.position : default(Vector3?),
syncRotation && rotationChanged ? Compression.CompressQuaternion(snapshot.rotation) : default(uint?),
syncScale && scaleChanged ? snapshot.scale : default(Vector3?)
);
}
else
{
RpcServerToClientSync(
// only sync what the user wants to sync
syncPosition && positionChanged ? snapshot.position : default(Vector3?),
syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?),
syncScale && scaleChanged ? snapshot.scale : default(Vector3?)
);
}
if (cachedSnapshotComparison)
{
hasSentUnchangedPosition = true;
}
else
{
hasSentUnchangedPosition = false;
// Fixes https://github.com/MirrorNetworking/Mirror/issues/3572
// This also fixes https://github.com/MirrorNetworking/Mirror/issues/3573
// with the exception of Quaternion.Angle sensitivity has to be > 0.16.
// Unity issue, we are leaving it as is.
if (positionChanged) lastSnapshot.position = snapshot.position;
if (rotationChanged) lastSnapshot.rotation = snapshot.rotation;
if (positionChanged) lastSnapshot.scale = snapshot.scale;
}
}
}
} }
void UpdateServerInterpolation() void UpdateServerInterpolation()
@ -245,8 +198,6 @@ void UpdateClientBroadcast()
// receiver gets it from batch timestamp to save bandwidth. // receiver gets it from batch timestamp to save bandwidth.
TransformSnapshot snapshot = Construct(); TransformSnapshot snapshot = Construct();
if (changedDetection)
{
cachedChangedComparison = CompareChangedSnapshots(snapshot); cachedChangedComparison = CompareChangedSnapshots(snapshot);
if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; } if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; }
@ -265,48 +216,6 @@ void UpdateClientBroadcast()
UpdateLastSentSnapshot(cachedChangedComparison, snapshot); UpdateLastSentSnapshot(cachedChangedComparison, snapshot);
} }
} }
else
{
cachedSnapshotComparison = CompareSnapshots(snapshot);
if (cachedSnapshotComparison && hasSentUnchangedPosition && onlySyncOnChange) { return; }
if (compressRotation)
{
CmdClientToServerSyncCompressRotation(
// only sync what the user wants to sync
syncPosition && positionChanged ? snapshot.position : default(Vector3?),
syncRotation && rotationChanged ? Compression.CompressQuaternion(snapshot.rotation) : default(uint?),
syncScale && scaleChanged ? snapshot.scale : default(Vector3?)
);
}
else
{
CmdClientToServerSync(
// only sync what the user wants to sync
syncPosition && positionChanged ? snapshot.position : default(Vector3?),
syncRotation && rotationChanged ? snapshot.rotation : default(Quaternion?),
syncScale && scaleChanged ? snapshot.scale : default(Vector3?)
);
}
if (cachedSnapshotComparison)
{
hasSentUnchangedPosition = true;
}
else
{
hasSentUnchangedPosition = false;
// Fixes https://github.com/MirrorNetworking/Mirror/issues/3572
// This also fixes https://github.com/MirrorNetworking/Mirror/issues/3573
// with the exception of Quaternion.Angle sensitivity has to be > 0.16.
// Unity issue, we are leaving it as is.
if (positionChanged) lastSnapshot.position = snapshot.position;
if (rotationChanged) lastSnapshot.rotation = snapshot.rotation;
if (positionChanged) lastSnapshot.scale = snapshot.scale;
}
}
}
} }
void UpdateClientInterpolation() void UpdateClientInterpolation()
@ -364,119 +273,6 @@ protected virtual bool CompareSnapshots(TransformSnapshot currentSnapshot)
return (!positionChanged && !rotationChanged && !scaleChanged); return (!positionChanged && !rotationChanged && !scaleChanged);
} }
// cmd /////////////////////////////////////////////////////////////////
// only unreliable. see comment above of this file.
[Command(channel = Channels.Unreliable)]
void CmdClientToServerSync(Vector3? position, Quaternion? rotation, Vector3? scale)
{
OnClientToServerSync(position, rotation, scale);
//For client authority, immediately pass on the client snapshot to all other
//clients instead of waiting for server to send its snapshots.
if (syncDirection == SyncDirection.ClientToServer)
RpcServerToClientSync(position, rotation, scale);
}
// cmd /////////////////////////////////////////////////////////////////
// only unreliable. see comment above of this file.
[Command(channel = Channels.Unreliable)]
void CmdClientToServerSyncCompressRotation(Vector3? position, uint? rotation, Vector3? scale)
{
// A fix to not apply current interpolated GetRotation when receiving null/unchanged value, instead use last sent snapshot rotation.
Quaternion newRotation;
if (rotation.HasValue)
{
newRotation = Compression.DecompressQuaternion((uint)rotation);
}
else
{
newRotation = serverSnapshots.Count > 0 ? serverSnapshots.Values[serverSnapshots.Count - 1].rotation : GetRotation();
}
OnClientToServerSync(position, newRotation, scale);
//For client authority, immediately pass on the client snapshot to all other
//clients instead of waiting for server to send its snapshots.
if (syncDirection == SyncDirection.ClientToServer)
RpcServerToClientSyncCompressRotation(position, rotation, scale);
}
// local authority client sends sync message to server for broadcasting
protected virtual void OnClientToServerSync(Vector3? position, Quaternion? rotation, Vector3? scale)
{
// only apply if in client authority mode
if (syncDirection != SyncDirection.ClientToServer) return;
// protect against ever growing buffer size attacks
if (serverSnapshots.Count >= connectionToClient.snapshotBufferSizeLimit) return;
// only player owned objects (with a connection) can send to
// server. we can get the timestamp from the connection.
double timestamp = connectionToClient.remoteTimeStamp;
if (onlySyncOnChange)
{
double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkClient.sendInterval;
if (serverSnapshots.Count > 0 && serverSnapshots.Values[serverSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp)
ResetState();
}
AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale);
}
// rpc /////////////////////////////////////////////////////////////////
// only unreliable. see comment above of this file.
[ClientRpc(channel = Channels.Unreliable)]
void RpcServerToClientSync(Vector3? position, Quaternion? rotation, Vector3? scale) =>
OnServerToClientSync(position, rotation, scale);
// rpc /////////////////////////////////////////////////////////////////
// only unreliable. see comment above of this file.
[ClientRpc(channel = Channels.Unreliable)]
void RpcServerToClientSyncCompressRotation(Vector3? position, uint? rotation, Vector3? scale)
{
// A fix to not apply current interpolated GetRotation when receiving null/unchanged value, instead use last sent snapshot rotation.
Quaternion newRotation;
if (rotation.HasValue)
{
newRotation = Compression.DecompressQuaternion((uint)rotation);
}
else
{
newRotation = clientSnapshots.Count > 0 ? clientSnapshots.Values[clientSnapshots.Count - 1].rotation : GetRotation();
}
OnServerToClientSync(position, newRotation, scale);
}
// server broadcasts sync message to all clients
protected virtual void OnServerToClientSync(Vector3? position, Quaternion? rotation, Vector3? scale)
{
// in host mode, the server sends rpcs to all clients.
// the host client itself will receive them too.
// -> host server is always the source of truth
// -> we can ignore any rpc on the host client
// => otherwise host objects would have ever growing clientBuffers
// (rpc goes to clients. if isServer is true too then we are host)
if (isServer) return;
// don't apply for local player with authority
if (IsClientWithAuthority) return;
// on the client, we receive rpcs for all entities.
// not all of them have a connectionToServer.
// but all of them go through NetworkClient.connection.
// we can get the timestamp from there.
double timestamp = NetworkClient.connection.remoteTimeStamp;
if (onlySyncOnChange)
{
double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkServer.sendInterval;
if (clientSnapshots.Count > 0 && clientSnapshots.Values[clientSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp)
ResetState();
}
AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale);
}
protected virtual void UpdateLastSentSnapshot(Changed change, TransformSnapshot currentSnapshot) protected virtual void UpdateLastSentSnapshot(Changed change, TransformSnapshot currentSnapshot)
{ {
if (change == Changed.None || change == Changed.CompressRot) return; if (change == Changed.None || change == Changed.CompressRot) return;

View File

@ -12,10 +12,10 @@ public class NetworkTransformExposed : NetworkTransformUnreliable
public new TransformSnapshot Construct() => base.Construct(); public new TransformSnapshot Construct() => base.Construct();
public void Apply(TransformSnapshot interpolated) => public void Apply(TransformSnapshot interpolated) =>
base.Apply(interpolated, interpolated); base.Apply(interpolated, interpolated);
public new void OnClientToServerSync(Vector3? position, Quaternion? rotation, Vector3? scale) => public new void OnClientToServerSync(SyncData syncData) =>
base.OnClientToServerSync(position, rotation, scale); base.OnClientToServerSync(syncData);
public new void OnServerToClientSync(Vector3? position, Quaternion? rotation, Vector3? scale) => public new void OnServerToClientSync(SyncData syncData) =>
base.OnServerToClientSync(position, rotation, scale); base.OnServerToClientSync(syncData);
} }
public class NetworkTransform2kTests : MirrorTest public class NetworkTransform2kTests : MirrorTest
@ -199,7 +199,8 @@ public void OnClientToServerSync_WithoutClientAuthority()
{ {
// call OnClientToServerSync without authority // call OnClientToServerSync without authority
component.syncDirection = SyncDirection.ServerToClient; component.syncDirection = SyncDirection.ServerToClient;
component.OnClientToServerSync(Vector3.zero, Quaternion.identity, Vector3.zero); SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
component.OnClientToServerSync(syncData);
Assert.That(component.serverSnapshots.Count, Is.EqualTo(0)); Assert.That(component.serverSnapshots.Count, Is.EqualTo(0));
} }
@ -208,7 +209,8 @@ public void OnClientToServerSync_WithClientAuthority()
{ {
// call OnClientToServerSync with authority // call OnClientToServerSync with authority
component.syncDirection = SyncDirection.ClientToServer; component.syncDirection = SyncDirection.ClientToServer;
component.OnClientToServerSync(Vector3.zero, Quaternion.identity, Vector3.zero); SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
component.OnClientToServerSync(syncData);
Assert.That(component.serverSnapshots.Count, Is.EqualTo(1)); Assert.That(component.serverSnapshots.Count, Is.EqualTo(1));
} }
@ -219,13 +221,12 @@ public void OnClientToServerSync_WithClientAuthority_BufferSizeLimit()
// authority is required // authority is required
component.syncDirection = SyncDirection.ClientToServer; component.syncDirection = SyncDirection.ClientToServer;
SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
// add first should work // add first should work
component.OnClientToServerSync(Vector3.zero, Quaternion.identity, Vector3.zero); component.OnClientToServerSync(syncData);
Assert.That(component.serverSnapshots.Count, Is.EqualTo(1)); Assert.That(component.serverSnapshots.Count, Is.EqualTo(1));
// add second should be too much // add second should be too much
component.OnClientToServerSync(Vector3.zero, Quaternion.identity, Vector3.zero); component.OnClientToServerSync(syncData);
Assert.That(component.serverSnapshots.Count, Is.EqualTo(1)); Assert.That(component.serverSnapshots.Count, Is.EqualTo(1));
} }
@ -240,7 +241,8 @@ public void OnClientToServerSync_WithClientAuthority_Nullables_Uses_Last()
// call OnClientToServerSync with authority and nullable types // call OnClientToServerSync with authority and nullable types
// to make sure it uses the last valid position then. // to make sure it uses the last valid position then.
component.syncDirection = SyncDirection.ClientToServer; component.syncDirection = SyncDirection.ClientToServer;
component.OnClientToServerSync(new Vector3?(), new Quaternion?(), new Vector3?()); SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
component.OnClientToServerSync(syncData);
Assert.That(component.serverSnapshots.Count, Is.EqualTo(1)); Assert.That(component.serverSnapshots.Count, Is.EqualTo(1));
TransformSnapshot first = component.serverSnapshots.Values[0]; TransformSnapshot first = component.serverSnapshots.Values[0];
Assert.That(first.position, Is.EqualTo(Vector3.left)); Assert.That(first.position, Is.EqualTo(Vector3.left));
@ -257,9 +259,11 @@ public void OnServerToClientSync_WithoutClientAuthority()
component.netIdentity.isClient = true; component.netIdentity.isClient = true;
component.netIdentity.isLocalPlayer = true; component.netIdentity.isLocalPlayer = true;
SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
// call OnServerToClientSync without authority // call OnServerToClientSync without authority
component.syncDirection = SyncDirection.ServerToClient; component.syncDirection = SyncDirection.ServerToClient;
component.OnServerToClientSync(Vector3.zero, Quaternion.identity, Vector3.zero); component.OnServerToClientSync(syncData);
Assert.That(component.clientSnapshots.Count, Is.EqualTo(1)); Assert.That(component.clientSnapshots.Count, Is.EqualTo(1));
} }
@ -277,12 +281,14 @@ public void OnServerToClientSync_WithoutClientAuthority_bufferSizeLimit()
// client authority has to be disabled // client authority has to be disabled
component.syncDirection = SyncDirection.ServerToClient; component.syncDirection = SyncDirection.ServerToClient;
SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
// add first should work // add first should work
component.OnServerToClientSync(Vector3.zero, Quaternion.identity, Vector3.zero); component.OnServerToClientSync(syncData);
Assert.That(component.clientSnapshots.Count, Is.EqualTo(1)); Assert.That(component.clientSnapshots.Count, Is.EqualTo(1));
// add second should be too much // add second should be too much
component.OnServerToClientSync(Vector3.zero, Quaternion.identity, Vector3.zero); component.OnServerToClientSync(syncData);
Assert.That(component.clientSnapshots.Count, Is.EqualTo(1)); Assert.That(component.clientSnapshots.Count, Is.EqualTo(1));
} }
@ -297,7 +303,8 @@ public void OnServerToClientSync_WithClientAuthority()
// call OnServerToClientSync with authority // call OnServerToClientSync with authority
component.syncDirection = SyncDirection.ClientToServer; component.syncDirection = SyncDirection.ClientToServer;
component.OnServerToClientSync(Vector3.zero, Quaternion.identity, Vector3.zero); SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
component.OnServerToClientSync(syncData);
Assert.That(component.clientSnapshots.Count, Is.EqualTo(0)); Assert.That(component.clientSnapshots.Count, Is.EqualTo(0));
} }
@ -319,7 +326,8 @@ public void OnServerToClientSync_WithClientAuthority_Nullables_Uses_Last()
// call OnClientToServerSync with authority and nullable types // call OnClientToServerSync with authority and nullable types
// to make sure it uses the last valid position then. // to make sure it uses the last valid position then.
component.OnServerToClientSync(new Vector3?(), new Quaternion?(), new Vector3?()); SyncData syncData = new SyncData((Changed)255, Vector3.zero, Quaternion.identity, Vector3.zero);
component.OnServerToClientSync(syncData);
Assert.That(component.clientSnapshots.Count, Is.EqualTo(1)); Assert.That(component.clientSnapshots.Count, Is.EqualTo(1));
TransformSnapshot first = component.clientSnapshots.Values[0]; TransformSnapshot first = component.clientSnapshots.Values[0];
Assert.That(first.position, Is.EqualTo(Vector3.left)); Assert.That(first.position, Is.EqualTo(Vector3.left));