11using System . Collections ;
2- using System . Collections . Generic ;
32using NUnit . Framework ;
43using Unity . Netcode . Components ;
54using Unity . Netcode . TestHelpers . Runtime ;
@@ -18,8 +17,8 @@ namespace Unity.Netcode.RuntimeTests
1817 /// can never be less than the tick latency. Deriving the render time from LocalTime eats into that margin by
1918 /// however far the two clocks are apart, and can push the target past ServerTime entirely.
2019 /// </remarks>
21- [ TestFixture ( HostOrServer . Host , NetworkTransform . InterpolationTypes . Lerp ) ]
22- [ TestFixture ( HostOrServer . Host , NetworkTransform . InterpolationTypes . SmoothDampening ) ]
20+ [ TestFixture ( NetworkTransform . InterpolationTypes . Lerp ) ]
21+ [ TestFixture ( NetworkTransform . InterpolationTypes . SmoothDampening ) ]
2322 internal class NetworkTransformInterpolationRenderTimeTests : IntegrationTestWithApproximation
2423 {
2524 protected override int NumberOfClients => 1 ;
@@ -47,19 +46,12 @@ internal class NetworkTransformInterpolationRenderTimeTests : IntegrationTestWit
4746 private NetworkManager m_AuthorityNetworkManager ;
4847 private NetworkTransform m_AuthorityInstance ;
4948 private Vector3 m_Direction ;
50- private int m_TickCount ;
5149
52- public NetworkTransformInterpolationRenderTimeTests ( HostOrServer hostOrServer , NetworkTransform . InterpolationTypes interpolationType ) : base ( hostOrServer )
50+ public NetworkTransformInterpolationRenderTimeTests ( NetworkTransform . InterpolationTypes interpolationType )
5351 {
5452 m_InterpolationType = interpolationType ;
5553 }
5654
57- // TODO: [CmbServiceTests] ServerTime's meaning under a CMB service session has not been verified.
58- protected override bool UseCMBService ( )
59- {
60- return false ;
61- }
62-
6355 protected override void OnServerAndClientsCreated ( )
6456 {
6557 m_TestPrefab = CreateNetworkObjectPrefab ( "RenderTimeTestObj" ) ;
@@ -86,139 +78,70 @@ private static double GetClockLeadInTicks(NetworkManager networkManager)
8678 /// </summary>
8779 private void OnNetworkTick ( )
8880 {
89- m_TickCount ++ ;
9081 m_AuthorityInstance . transform . position += m_Direction * k_DistancePerTick ;
9182 }
9283
93- private bool AllClientsSpawnedInstance ( )
94- {
95- foreach ( var networkManager in m_NetworkManagers )
96- {
97- if ( networkManager == m_AuthorityNetworkManager )
98- {
99- continue ;
100- }
101-
102- if ( ! networkManager . SpawnManager . SpawnedObjects . ContainsKey ( m_AuthorityInstance . NetworkObject . NetworkObjectId ) )
103- {
104- return false ;
105- }
106- }
107- return true ;
108- }
109-
110- private List < NetworkTransform > GetNonAuthorityInstances ( )
111- {
112- var instances = new List < NetworkTransform > ( ) ;
113- foreach ( var networkManager in m_NetworkManagers )
114- {
115- if ( networkManager == m_AuthorityNetworkManager )
116- {
117- continue ;
118- }
119-
120- var spawnedObject = networkManager . SpawnManager . SpawnedObjects [ m_AuthorityInstance . NetworkObject . NetworkObjectId ] ;
121- instances . Add ( spawnedObject . GetComponent < NetworkTransform > ( ) ) ;
122- }
123- return instances ;
124- }
125-
12684 [ UnityTest ]
12785 public IEnumerator RenderTimeTrailsTheServerClock ( )
12886 {
12987 m_AuthorityNetworkManager = GetAuthorityNetworkManager ( ) ;
13088 m_AuthorityInstance = SpawnObject ( m_TestPrefab , m_AuthorityNetworkManager ) . GetComponent < NetworkTransform > ( ) ;
13189
132- yield return WaitForConditionOrTimeOut ( AllClientsSpawnedInstance ) ;
90+ yield return WaitForSpawnedOnAllOrTimeOut ( m_AuthorityInstance . NetworkObject ) ;
13391 AssertOnTimeout ( $ "Not all clients spawned { m_AuthorityInstance . name } !") ;
13492
135- var nonAuthorityInstances = GetNonAuthorityInstances ( ) ;
136- Assert . IsNotEmpty ( nonAuthorityInstances , "There were no non-authority instances to measure!" ) ;
93+ var nonAuthority = GetNonAuthorityNetworkManager ( ) ;
94+ var nonAuthorityInstance = nonAuthority . SpawnManager . SpawnedObjects [ m_AuthorityInstance . NetworkObject . NetworkObjectId ] . GetComponent < NetworkTransform > ( ) ;
13795
13896 // Separate the two clocks by a known amount so that which one the render time is derived from is
13997 // actually distinguishable.
140- foreach ( var instance in nonAuthorityInstances )
141- {
142- var networkManager = instance . NetworkManager ;
143- networkManager . NetworkTimeSystem . LocalBufferSec = k_LocalBufferTicks * GetTickInterval ( networkManager ) ;
144- }
98+ nonAuthority . NetworkTimeSystem . LocalBufferSec = k_LocalBufferTicks * GetTickInterval ( nonAuthority ) ;
14599
146100 // Start continuous motion on the authority.
147101 m_Direction = GetRandomVector3 ( - 10 , 10 ) . normalized ;
148- m_TickCount = 0 ;
149102 m_AuthorityNetworkManager . NetworkTickSystem . Tick += OnNetworkTick ;
150103
151104 // The offset only moves when the client next receives a time sync, so wait for the separation to
152105 // actually take hold rather than assuming it has.
153- yield return WaitForConditionOrTimeOut ( ( ) =>
154- {
155- foreach ( var instance in nonAuthorityInstances )
156- {
157- if ( GetClockLeadInTicks ( instance . NetworkManager ) < k_RequiredLeadTicks )
158- {
159- return false ;
160- }
161- }
162- return true ;
163- } ) ;
164- AssertOnTimeout ( $ "The client clocks never separated by { k_RequiredLeadTicks } ticks, so this test " +
165- $ "cannot tell the two clocks apart and would pass regardless of which one is used.") ;
106+ yield return WaitForConditionOrTimeOut ( ( ) => GetClockLeadInTicks ( nonAuthority ) >= k_RequiredLeadTicks ) ;
107+ AssertOnTimeout ( $ "The nonAuthority clock never fell { k_RequiredLeadTicks } ticks behind, so this test " +
108+ "cannot tell the two clocks apart and would pass regardless of which one is used." ) ;
166109
167110 // Let the interpolator settle at the new separation before measuring.
168- var warmUpTarget = m_TickCount + k_WarmUpTicks ;
169- yield return WaitForConditionOrTimeOut ( ( ) => m_TickCount >= warmUpTarget ) ;
170- AssertOnTimeout ( "Timed out waiting for the authority to keep moving!" ) ;
111+ yield return WaitForTicks ( m_AuthorityNetworkManager , k_WarmUpTicks ) ;
171112
172113 // Sample how far behind ServerTime the state being interpolated towards was sent.
173- var totalTargetLagTicks = new Dictionary < NetworkTransform , double > ( ) ;
174- var totalBuffered = new Dictionary < NetworkTransform , int > ( ) ;
175- var samples = new Dictionary < NetworkTransform , int > ( ) ;
176- foreach ( var instance in nonAuthorityInstances )
177- {
178- totalTargetLagTicks . Add ( instance , 0.0d ) ;
179- totalBuffered . Add ( instance , 0 ) ;
180- samples . Add ( instance , 0 ) ;
181- }
182-
114+ var interpolator = nonAuthorityInstance . GetPositionInterpolator ( ) ;
115+ var totalTargetLagTicks = 0.0d ;
116+ var totalBuffered = 0 ;
117+ var samples = 0 ;
183118 for ( int frame = 0 ; frame < k_SampledFrames ; frame ++ )
184119 {
185- foreach ( var instance in nonAuthorityInstances )
120+ if ( interpolator . InterpolateState . Target . HasValue )
186121 {
187- var interpolator = instance . GetPositionInterpolator ( ) ;
188- if ( ! interpolator . InterpolateState . Target . HasValue )
189- {
190- continue ;
191- }
192-
193- var networkManager = instance . NetworkManager ;
194- var targetLag = networkManager . ServerTime . Time - interpolator . InterpolateState . Target . Value . TimeSent ;
195- totalTargetLagTicks [ instance ] += targetLag / GetTickInterval ( networkManager ) ;
196- totalBuffered [ instance ] += interpolator . m_BufferQueue . Count ;
197- samples [ instance ] ++ ;
122+ var targetLag = nonAuthority . ServerTime . Time - interpolator . InterpolateState . Target . Value . TimeSent ;
123+ totalTargetLagTicks += targetLag / GetTickInterval ( nonAuthority ) ;
124+ totalBuffered += interpolator . m_BufferQueue . Count ;
125+ samples ++ ;
198126 }
199127 yield return null ;
200128 }
201129
202130 m_AuthorityNetworkManager . NetworkTickSystem . Tick -= OnNetworkTick ;
203131
204- foreach ( var instance in nonAuthorityInstances )
205- {
206- Assert . Greater ( samples [ instance ] , 0 , $ "{ instance . name } never had a state to interpolate towards!") ;
207-
208- var networkManager = instance . NetworkManager ;
209- var meanTargetLagTicks = totalTargetLagTicks [ instance ] / samples [ instance ] ;
210- var meanBuffered = totalBuffered [ instance ] / ( float ) samples [ instance ] ;
211- var tickLatency = networkManager . NetworkTimeSystem . TickLatency ;
212-
213- // Anything less than the tick latency means the render time came from a clock that leads the one
214- // the states are stamped on.
215- Assert . GreaterOrEqual ( meanTargetLagTicks , tickLatency ,
216- $ "[{ m_InterpolationType } ] { instance . name } was interpolating towards a state sent " +
217- $ "{ meanTargetLagTicks : F3} ticks behind the server clock, but the render time is the server " +
218- $ "clock minus a tick latency of { tickLatency } , so it should never be less than that. " +
219- $ "(clock lead { GetClockLeadInTicks ( networkManager ) : F3} ticks, mean buffered { meanBuffered : F3} ). " +
220- $ "The render time is being derived from a clock that leads the one state updates are stamped on.") ;
221- }
132+ Assert . Greater ( samples , 0 , $ "{ nonAuthorityInstance . name } never had a state to interpolate towards!") ;
133+
134+ var meanTargetLagTicks = totalTargetLagTicks / samples ;
135+ var meanBuffered = totalBuffered / ( float ) samples ;
136+ var tickLatency = nonAuthority . NetworkTimeSystem . TickLatency ;
137+
138+ // Anything less than the tick latency means the render time came from a clock that leads the one
139+ // the states are stamped on.
140+ Assert . GreaterOrEqual ( meanTargetLagTicks , tickLatency ,
141+ $ "[{ m_InterpolationType } ] { nonAuthorityInstance . name } was interpolating towards a state sent " +
142+ $ "{ meanTargetLagTicks : F3} ticks behind the server clock, but the render time is the server " +
143+ $ "clock minus a tick latency of { tickLatency } , so it should never be less than that. " +
144+ $ "(clock lead { GetClockLeadInTicks ( nonAuthority ) : F3} ticks, mean buffered { meanBuffered : F3} )") ;
222145 }
223146 }
224147}
0 commit comments