From 7f0ab63cf76f958a3db0b8e59695352dfda832e5 Mon Sep 17 00:00:00 2001 From: Jeffrey Rainy Date: Mon, 30 Aug 2021 11:41:23 -0400 Subject: [PATCH 1/5] feat: snapshot. MTT-1087 first part. separating the side effect (storing the sent info) from preparing the buffer to send --- .../Runtime/Core/SnapshotSystem.cs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs index b2a509f573..fc028d7cf7 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs @@ -243,15 +243,14 @@ internal void WriteEntry(NetworkWriter writer, in Entry entry) writer.WriteUInt16(entry.Length); } - internal void WriteSpawn(ClientData clientData, NetworkWriter writer, in SnapshotSpawnCommand spawn) + internal ClientData.SentSpawn WriteSpawn(in ClientData clientData, NetworkWriter writer, in SnapshotSpawnCommand spawn) { // remember which spawn we sent this connection with which sequence number // that way, upon ack, we can track what is being ack'ed - ClientData.SentSpawn s; - s.ObjectId = spawn.NetworkObjectId; - s.Tick = spawn.TickWritten; - s.SequenceNumber = clientData.SequenceNumber; - clientData.SentSpawns.Add(s); + ClientData.SentSpawn sentSpawn; + sentSpawn.ObjectId = spawn.NetworkObjectId; + sentSpawn.Tick = spawn.TickWritten; + sentSpawn.SequenceNumber = clientData.SequenceNumber; writer.WriteUInt64Packed(spawn.NetworkObjectId); writer.WriteUInt64Packed(spawn.GlobalObjectIdHash); @@ -265,20 +264,23 @@ internal void WriteSpawn(ClientData clientData, NetworkWriter writer, in Snapsho writer.WriteVector3(spawn.ObjectScale); writer.WriteInt32Packed(spawn.TickWritten); + + return sentSpawn; } - internal void WriteDespawn(ClientData clientData, NetworkWriter writer, in SnapshotDespawnCommand despawn) + internal ClientData.SentSpawn WriteDespawn(ClientData clientData, NetworkWriter writer, in SnapshotDespawnCommand despawn) { // remember which spawn we sent this connection with which sequence number // that way, upon ack, we can track what is being ack'ed - ClientData.SentSpawn s; - s.ObjectId = despawn.NetworkObjectId; - s.Tick = despawn.TickWritten; - s.SequenceNumber = clientData.SequenceNumber; - clientData.SentSpawns.Add(s); + ClientData.SentSpawn sentSpawn; + sentSpawn.ObjectId = despawn.NetworkObjectId; + sentSpawn.Tick = despawn.TickWritten; + sentSpawn.SequenceNumber = clientData.SequenceNumber; writer.WriteUInt64Packed(despawn.NetworkObjectId); writer.WriteInt32Packed(despawn.TickWritten); + + return sentSpawn; } /// /// Read a received Entry @@ -780,7 +782,8 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId) if (m_Snapshot.Spawns[index].TargetClientIds.Contains(clientId)) { - m_Snapshot.WriteSpawn(clientData, writer, in m_Snapshot.Spawns[index]); + var sentSpawn = m_Snapshot.WriteSpawn(clientData, writer, in m_Snapshot.Spawns[index]); + clientData.SentSpawns.Add(sentSpawn); spawnWritten++; } @@ -799,7 +802,8 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId) if (m_Snapshot.Despawns[index].TargetClientIds.Contains(clientId)) { - m_Snapshot.WriteDespawn(clientData, writer, in m_Snapshot.Despawns[index]); + var sentDespawn = m_Snapshot.WriteDespawn(clientData, writer, in m_Snapshot.Despawns[index]); + clientData.SentSpawns.Add(sentDespawn); despawnWritten++; } // limit spawn sizes, compare current pos to very first position we wrote to From 0ef806de35aef82b492ada4e6987d7ea9c06e71d Mon Sep 17 00:00:00 2001 From: Jeffrey Rainy Date: Mon, 30 Aug 2021 14:59:00 -0400 Subject: [PATCH 2/5] feat: snapshot. MTT-1087 second part. Writing SnapshotMessage that fit in the specified limit, instead of stopping once the limit is busted --- .../Runtime/Core/SnapshotSystem.cs | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs index fc028d7cf7..ab7e0c01b3 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs @@ -779,37 +779,58 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId) for (var j = 0; j < m_Snapshot.NumSpawns && !overSize; j++) { var index = clientData.NextSpawnIndex; + var savedPosition = writer.GetStream().Position; if (m_Snapshot.Spawns[index].TargetClientIds.Contains(clientId)) { var sentSpawn = m_Snapshot.WriteSpawn(clientData, writer, in m_Snapshot.Spawns[index]); - clientData.SentSpawns.Add(sentSpawn); - spawnWritten++; - } - // limit spawn sizes, compare current pos to very first position we wrote to - if (writer.GetStream().Position - positionSpawns > k_MaxSpawnUsage) - { - overSize = true; + // limit spawn sizes, compare current pos to very first position we wrote to + if (writer.GetStream().Position - positionSpawns > k_MaxSpawnUsage) + { + overSize = true; + // revert back the position to undo the write + writer.GetStream().Position = savedPosition; + } + else + { + clientData.SentSpawns.Add(sentSpawn); + spawnWritten++; + } } clientData.NextSpawnIndex = (clientData.NextSpawnIndex + 1) % m_Snapshot.NumSpawns; } + // even though we might have a spawn we could not fit, it's possible despawns will fit (they're smaller) + + // todo: this next line is commented for now because there's no check for a spawn command to have been + // ack'ed before sending a despawn for the same object. + // Uncommenting this line would allow some despawn to be sent while spawns are pending. + // As-is it is overly restrictive but allows us to go forward without the spawn/despawn dependency check + + // overSize = false; for (var j = 0; j < m_Snapshot.NumDespawns && !overSize; j++) { var index = clientData.NextDespawnIndex; + var savedPosition = writer.GetStream().Position; if (m_Snapshot.Despawns[index].TargetClientIds.Contains(clientId)) { var sentDespawn = m_Snapshot.WriteDespawn(clientData, writer, in m_Snapshot.Despawns[index]); - clientData.SentSpawns.Add(sentDespawn); - despawnWritten++; - } - // limit spawn sizes, compare current pos to very first position we wrote to - if (writer.GetStream().Position - positionSpawns > k_MaxSpawnUsage) - { - overSize = true; + + // limit spawn sizes, compare current pos to very first position we wrote to + if (writer.GetStream().Position - positionSpawns > k_MaxSpawnUsage) + { + overSize = true; + // revert back the position to undo the write + writer.GetStream().Position = savedPosition; + } + else + { + clientData.SentSpawns.Add(sentDespawn); + despawnWritten++; + } } clientData.NextDespawnIndex = (clientData.NextDespawnIndex + 1) % m_Snapshot.NumDespawns; } From c6584ab29b2ba11eb9b3d4dd2df36859b58892db Mon Sep 17 00:00:00 2001 From: Jeffrey Rainy Date: Mon, 30 Aug 2021 15:32:42 -0400 Subject: [PATCH 3/5] feat: snapshot. MTT-1087 part 3. Writing spawns after acks, because spawns are limited in message size --- com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs index ab7e0c01b3..7b163fc048 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs @@ -730,8 +730,8 @@ private void SendSnapshot(ulong clientId) writer.WriteUInt16(SentinelBefore); WriteBuffer(buffer); WriteIndex(buffer); - WriteSpawns(buffer, clientId); WriteAcks(buffer, clientId); + WriteSpawns(buffer, clientId); writer.WriteUInt16(SentinelAfter); m_ClientData[clientId].LastReceivedSequence = 0; @@ -1016,8 +1016,8 @@ internal void ReadSnapshot(ulong clientId, Stream snapshotStream) m_Snapshot.ReadBuffer(reader, snapshotStream); m_Snapshot.ReadIndex(reader); - m_Snapshot.ReadSpawns(reader); m_Snapshot.ReadAcks(clientId, m_ClientData[clientId], reader, GetConnectionRtt(clientId)); + m_Snapshot.ReadSpawns(reader); sentinel = reader.ReadUInt16(); if (sentinel != SentinelAfter) From 5b1046d001ae1816095a63ea37038a8d96b14d3e Mon Sep 17 00:00:00 2001 From: Jeffrey Rainy Date: Mon, 30 Aug 2021 16:20:26 -0400 Subject: [PATCH 4/5] feat: snapshot. MTT-1087 part 4. Using max spawn message size from NetworkConfig --- .../Runtime/Configuration/NetworkConfig.cs | 12 ++++++++++-- .../Runtime/Core/SnapshotSystem.cs | 8 +++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs index a123f16064..11efd5cf14 100644 --- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs @@ -166,10 +166,18 @@ public class NetworkConfig /// public bool EnableNetworkLogs = true; - // todo: transitional. For the next release, only Snapshot should remain - // The booleans allow iterative development and testing in the meantime + /// + /// Whether or not to enable Snapshot System for variable updates. Currently unsupported. + /// public bool UseSnapshotDelta { get; } = false; + /// + /// Whether or not to enable Snapshot System for spawn and despawn commands. Working but experimental. + /// public bool UseSnapshotSpawn { get; } = false; + /// + /// When Snapshot System spawn is enabled: max size of Snapshot Messages. Meant to fit MTU. + /// + public int SnapshotMaxSpawnUsage { get; } = 1200; public const int RttAverageSamples = 5; // number of RTT to keep an average of (plus one) public const int RttWindowSize = 64; // number of slots to use for RTT computations (max number of in-flight packets) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs index 7b163fc048..33ce62975a 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs @@ -607,8 +607,6 @@ internal class SnapshotSystem : INetworkUpdateSystem, IDisposable internal const ushort SentinelBefore = 0x4246; internal const ushort SentinelAfter = 0x89CE; - private const int k_MaxSpawnUsage = 1000; // max bytes to use for the spawn/despawn part - private NetworkManager m_NetworkManager = default; private Snapshot m_Snapshot = default; @@ -747,8 +745,8 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId) { var spawnWritten = 0; var despawnWritten = 0; + var overSize = false; - bool overSize = false; ClientData clientData = m_ClientData[clientId]; // this is needed because spawns being removed may have reduce the size below LRU position @@ -786,7 +784,7 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId) var sentSpawn = m_Snapshot.WriteSpawn(clientData, writer, in m_Snapshot.Spawns[index]); // limit spawn sizes, compare current pos to very first position we wrote to - if (writer.GetStream().Position - positionSpawns > k_MaxSpawnUsage) + if (writer.GetStream().Position - positionSpawns > m_NetworkManager.NetworkConfig.SnapshotMaxSpawnUsage) { overSize = true; // revert back the position to undo the write @@ -820,7 +818,7 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId) var sentDespawn = m_Snapshot.WriteDespawn(clientData, writer, in m_Snapshot.Despawns[index]); // limit spawn sizes, compare current pos to very first position we wrote to - if (writer.GetStream().Position - positionSpawns > k_MaxSpawnUsage) + if (writer.GetStream().Position - positionSpawns > m_NetworkManager.NetworkConfig.SnapshotMaxSpawnUsage) { overSize = true; // revert back the position to undo the write From 1a113202b6ec03c3dcd24c60533dabfeb5f4f1f9 Mon Sep 17 00:00:00 2001 From: Jeffrey Rainy Date: Mon, 30 Aug 2021 20:45:31 -0400 Subject: [PATCH 5/5] feat: snapshot. mtt-1087. Forgotten , for performance --- com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs index 33ce62975a..8b5133ea6f 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs @@ -268,7 +268,7 @@ internal ClientData.SentSpawn WriteSpawn(in ClientData clientData, NetworkWriter return sentSpawn; } - internal ClientData.SentSpawn WriteDespawn(ClientData clientData, NetworkWriter writer, in SnapshotDespawnCommand despawn) + internal ClientData.SentSpawn WriteDespawn(in ClientData clientData, NetworkWriter writer, in SnapshotDespawnCommand despawn) { // remember which spawn we sent this connection with which sequence number // that way, upon ack, we can track what is being ack'ed