@@ -35,6 +35,7 @@ internal struct SnapshotDespawnCommand
35
35
// snapshot internal
36
36
internal int TickWritten ;
37
37
internal List < ulong > TargetClientIds ;
38
+ internal int TimesWritten ;
38
39
}
39
40
40
41
internal struct SnapshotSpawnCommand
@@ -57,6 +58,7 @@ internal struct SnapshotSpawnCommand
57
58
// snapshot internal
58
59
internal int TickWritten ;
59
60
internal List < ulong > TargetClientIds ;
61
+ internal int TimesWritten ;
60
62
}
61
63
62
64
// A table of NetworkVariables that constitutes a Snapshot.
@@ -191,6 +193,11 @@ internal void AddSpawn(SnapshotSpawnCommand command)
191
193
command . TargetClientIds = GetClientList ( ) ;
192
194
}
193
195
196
+ // todo: store, for each client, the spawn not ack'ed yet,
197
+ // to prevent sending despawns to them.
198
+ // for clientData in client list
199
+ // clientData.SpawnSet.Add(command.NetworkObjectId);
200
+
194
201
// todo:
195
202
// this 'if' might be temporary, but is needed to help in debugging
196
203
// or maybe it stays
@@ -302,7 +309,7 @@ internal Entry ReadEntry(NetworkReader reader)
302
309
303
310
internal SnapshotSpawnCommand ReadSpawn ( NetworkReader reader )
304
311
{
305
- SnapshotSpawnCommand command ;
312
+ var command = new SnapshotSpawnCommand ( ) ;
306
313
307
314
command . NetworkObjectId = reader . ReadUInt64Packed ( ) ;
308
315
command . GlobalObjectIdHash = ( uint ) reader . ReadUInt64Packed ( ) ;
@@ -315,18 +322,16 @@ internal SnapshotSpawnCommand ReadSpawn(NetworkReader reader)
315
322
command . ObjectScale = reader . ReadVector3 ( ) ;
316
323
317
324
command . TickWritten = reader . ReadInt32Packed ( ) ;
318
- command . TargetClientIds = default ;
319
325
320
326
return command ;
321
327
}
322
328
323
329
internal SnapshotDespawnCommand ReadDespawn ( NetworkReader reader )
324
330
{
325
- SnapshotDespawnCommand command ;
331
+ var command = new SnapshotDespawnCommand ( ) ;
326
332
327
333
command . NetworkObjectId = reader . ReadUInt64Packed ( ) ;
328
334
command . TickWritten = reader . ReadInt32Packed ( ) ;
329
- command . TargetClientIds = default ;
330
335
331
336
return command ;
332
337
}
@@ -499,8 +504,11 @@ internal void ReadAcks(ulong clientId, ClientData clientData, NetworkReader read
499
504
internal void ProcessSingleAck ( ushort ackSequence , ulong clientId , ClientData clientData , ConnectionRtt connection )
500
505
{
501
506
// look through the spawns sent
502
- foreach ( var sent in clientData . SentSpawns )
507
+ for ( int index = 0 ; index < clientData . SentSpawns . Count ; /*no increment*/ )
503
508
{
509
+ // needless copy, but I didn't find a way around
510
+ ClientData . SentSpawn sent = clientData . SentSpawns [ index ] ;
511
+
504
512
// for those with the sequence number being ack'ed
505
513
if ( sent . SequenceNumber == ackSequence )
506
514
{
@@ -548,6 +556,16 @@ internal void ProcessSingleAck(ushort ackSequence, ulong clientId, ClientData cl
548
556
}
549
557
}
550
558
}
559
+
560
+ // remove current `sent`, by moving last over,
561
+ // as it was acknowledged.
562
+ // skip incrementing index
563
+ clientData . SentSpawns [ index ] = clientData . SentSpawns [ clientData . SentSpawns . Count - 1 ] ;
564
+ clientData . SentSpawns . RemoveAt ( clientData . SentSpawns . Count - 1 ) ;
565
+ }
566
+ else
567
+ {
568
+ index ++ ;
551
569
}
552
570
}
553
571
@@ -741,6 +759,38 @@ private void SendSnapshot(ulong clientId)
741
759
}
742
760
}
743
761
762
+ // Checks if a given SpawnCommand should be written to a Snapshot Message
763
+ // Performs exponential back off. To write a spawn a second time
764
+ // two ticks must have gone by. To write it a third time, four ticks, etc...
765
+ // This prioritize commands that have been re-sent less than others
766
+ private bool ShouldWriteSpawn ( in SnapshotSpawnCommand spawnCommand )
767
+ {
768
+ if ( m_CurrentTick < spawnCommand . TickWritten )
769
+ {
770
+ return false ;
771
+ }
772
+
773
+ // 63 as we can't shift more than that.
774
+ var diff = Math . Min ( 63 , m_CurrentTick - spawnCommand . TickWritten ) ;
775
+
776
+ // -1 to make the first resend immediate
777
+ return ( 1 << diff ) > ( spawnCommand . TimesWritten - 1 ) ;
778
+ }
779
+
780
+ private bool ShouldWriteDespawn ( in SnapshotDespawnCommand despawnCommand )
781
+ {
782
+ if ( m_CurrentTick < despawnCommand . TickWritten )
783
+ {
784
+ return false ;
785
+ }
786
+
787
+ // 63 as we can't shift more than that.
788
+ var diff = Math . Min ( 63 , m_CurrentTick - despawnCommand . TickWritten ) ;
789
+
790
+ // -1 to make the first resend immediate
791
+ return ( 1 << diff ) > ( despawnCommand . TimesWritten - 1 ) ;
792
+ }
793
+
744
794
private void WriteSpawns ( NetworkBuffer buffer , ulong clientId )
745
795
{
746
796
var spawnWritten = 0 ;
@@ -779,7 +829,8 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId)
779
829
var index = clientData . NextSpawnIndex ;
780
830
var savedPosition = writer . GetStream ( ) . Position ;
781
831
782
- if ( m_Snapshot . Spawns [ index ] . TargetClientIds . Contains ( clientId ) )
832
+ // todo: re-enable ShouldWriteSpawn, once we have a mechanism to not let despawn pass in front of spawns
833
+ if ( m_Snapshot . Spawns [ index ] . TargetClientIds . Contains ( clientId ) /*&& ShouldWriteSpawn(m_Snapshot.Spawns[index])*/ )
783
834
{
784
835
var sentSpawn = m_Snapshot . WriteSpawn ( clientData , writer , in m_Snapshot . Spawns [ index ] ) ;
785
836
@@ -792,6 +843,7 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId)
792
843
}
793
844
else
794
845
{
846
+ m_Snapshot . Spawns [ index ] . TimesWritten ++ ;
795
847
clientData . SentSpawns . Add ( sentSpawn ) ;
796
848
spawnWritten ++ ;
797
849
}
@@ -805,15 +857,15 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId)
805
857
// ack'ed before sending a despawn for the same object.
806
858
// Uncommenting this line would allow some despawn to be sent while spawns are pending.
807
859
// As-is it is overly restrictive but allows us to go forward without the spawn/despawn dependency check
808
-
809
860
// overSize = false;
810
861
811
862
for ( var j = 0 ; j < m_Snapshot . NumDespawns && ! overSize ; j ++ )
812
863
{
813
864
var index = clientData . NextDespawnIndex ;
814
865
var savedPosition = writer . GetStream ( ) . Position ;
815
866
816
- if ( m_Snapshot . Despawns [ index ] . TargetClientIds . Contains ( clientId ) )
867
+ // todo: re-enable ShouldWriteSpawn, once we have a mechanism to not let despawn pass in front of spawns
868
+ if ( m_Snapshot . Despawns [ index ] . TargetClientIds . Contains ( clientId ) /*&& ShouldWriteDespawn(m_Snapshot.Despawns[index])*/ )
817
869
{
818
870
var sentDespawn = m_Snapshot . WriteDespawn ( clientData , writer , in m_Snapshot . Despawns [ index ] ) ;
819
871
@@ -826,6 +878,7 @@ private void WriteSpawns(NetworkBuffer buffer, ulong clientId)
826
878
}
827
879
else
828
880
{
881
+ m_Snapshot . Despawns [ index ] . TimesWritten ++ ;
829
882
clientData . SentSpawns . Add ( sentDespawn ) ;
830
883
despawnWritten ++ ;
831
884
}
@@ -955,16 +1008,14 @@ internal void ReadSnapshot(ulong clientId, Stream snapshotStream)
955
1008
clientId = m_NetworkManager . ServerClientId ;
956
1009
}
957
1010
958
- int snapshotTick = default ;
959
-
960
1011
using var reader = PooledNetworkReader . Get ( snapshotStream ) ;
961
1012
// make sure we have a ClientData entry for each client
962
1013
if ( ! m_ClientData . ContainsKey ( clientId ) )
963
1014
{
964
1015
m_ClientData . Add ( clientId , new ClientData ( ) ) ;
965
1016
}
966
1017
967
- snapshotTick = reader . ReadInt32Packed ( ) ;
1018
+ var snapshotTick = reader . ReadInt32Packed ( ) ;
968
1019
var sequence = reader . ReadUInt16 ( ) ;
969
1020
970
1021
if ( sequence >= m_ClientData [ clientId ] . LastReceivedSequence )
0 commit comments