|
8 | 8 | // using Unity.Netcode.Samples;
|
9 | 9 | using UnityEngine;
|
10 | 10 | using UnityEngine.TestTools;
|
| 11 | +using Object = UnityEngine.Object; |
11 | 12 |
|
12 | 13 | namespace Unity.Netcode.RuntimeTests
|
13 | 14 | {
|
@@ -188,14 +189,171 @@ public IEnumerator TestCantChangeTransformFromOtherSideAuthority([Values] bool t
|
188 | 189 | * ownership change
|
189 | 190 | * test teleport with interpolation
|
190 | 191 | * test teleport without interpolation
|
191 |
| - * test dynamic spawning |
| 192 | + * test dynamic spawning -- done with NetworkTransformRespawnTests |
192 | 193 | */
|
193 | 194 |
|
194 | 195 | [UnityTearDown]
|
195 | 196 | public override IEnumerator Teardown()
|
196 | 197 | {
|
197 | 198 | yield return base.Teardown();
|
198 |
| - UnityEngine.Object.DestroyImmediate(m_PlayerPrefab); |
| 199 | + Object.DestroyImmediate(m_PlayerPrefab); |
| 200 | + } |
| 201 | + } |
| 202 | + |
| 203 | + /// <summary> |
| 204 | + /// This test simulates a pooled NetworkObject being re-used over time with a NetworkTransform |
| 205 | + /// This test validates that pooled NetworkObjects' NetworkTransforms are completely reset in |
| 206 | + /// order to properly start interpolating from the new spawn position and not the previous position |
| 207 | + /// when the registered Network Prefab was despawned. This specifically tests the client side. |
| 208 | + /// </summary> |
| 209 | + public class NetworkTransformRespawnTests : BaseMultiInstanceTest, INetworkPrefabInstanceHandler |
| 210 | + { |
| 211 | + /// <summary> |
| 212 | + /// Our test object mover NetworkBehaviour |
| 213 | + /// </summary> |
| 214 | + public class DynamicObjectMover : NetworkBehaviour |
| 215 | + { |
| 216 | + public Vector3 SpawnedPosition; |
| 217 | + private Rigidbody m_Rigidbody; |
| 218 | + private Vector3 m_MoveTowardsPosition = new Vector3(20, 0, 20); |
| 219 | + |
| 220 | + private void OnEnable() |
| 221 | + { |
| 222 | + SpawnedPosition = transform.position; |
| 223 | + } |
| 224 | + |
| 225 | + private void Update() |
| 226 | + { |
| 227 | + if (!IsSpawned || !IsServer) |
| 228 | + { |
| 229 | + return; |
| 230 | + } |
| 231 | + |
| 232 | + if (m_Rigidbody == null) |
| 233 | + { |
| 234 | + m_Rigidbody = GetComponent<Rigidbody>(); |
| 235 | + } |
| 236 | + if (m_Rigidbody != null) |
| 237 | + { |
| 238 | + m_Rigidbody.MovePosition(transform.position + (m_MoveTowardsPosition * Time.fixedDeltaTime)); |
| 239 | + } |
| 240 | + } |
| 241 | + } |
| 242 | + |
| 243 | + protected override int NbClients => 1; |
| 244 | + private GameObject m_ObjectToSpawn; |
| 245 | + private GameObject m_ClientSideObject; |
| 246 | + private NetworkObject m_DefaultNetworkObject; |
| 247 | + private Vector3 m_LastClientSidePosition; |
| 248 | + private bool m_ClientSideSpawned; |
| 249 | + |
| 250 | + public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation) |
| 251 | + { |
| 252 | + m_ClientSideSpawned = true; |
| 253 | + m_ClientSideObject.SetActive(true); |
| 254 | + return m_ClientSideObject.GetComponent<NetworkObject>(); |
| 255 | + } |
| 256 | + |
| 257 | + public void Destroy(NetworkObject networkObject) |
| 258 | + { |
| 259 | + m_ClientSideSpawned = false; |
| 260 | + networkObject.gameObject.SetActive(false); |
| 261 | + m_LastClientSidePosition = networkObject.transform.position; |
| 262 | + } |
| 263 | + |
| 264 | + public override IEnumerator Setup() |
| 265 | + { |
| 266 | + m_BypassStartAndWaitForClients = true; |
| 267 | + yield return StartSomeClientsAndServerWithPlayers(true, NbClients); |
| 268 | + |
| 269 | + m_ObjectToSpawn = new GameObject("NetworkTransformDynamicObject"); |
| 270 | + m_DefaultNetworkObject = m_ObjectToSpawn.AddComponent<NetworkObject>(); |
| 271 | + m_ObjectToSpawn.AddComponent<NetworkTransform>(); |
| 272 | + var rigidBody = m_ObjectToSpawn.AddComponent<Rigidbody>(); |
| 273 | + rigidBody.useGravity = false; |
| 274 | + m_ObjectToSpawn.AddComponent<NetworkRigidbody>(); |
| 275 | + m_ObjectToSpawn.AddComponent<DynamicObjectMover>(); |
| 276 | + MultiInstanceHelpers.MakeNetworkObjectTestPrefab(m_DefaultNetworkObject); |
| 277 | + |
| 278 | + var networkPrefab = new NetworkPrefab(); |
| 279 | + networkPrefab.Prefab = m_ObjectToSpawn; |
| 280 | + m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(networkPrefab); |
| 281 | + m_ServerNetworkManager.NetworkConfig.EnableSceneManagement = false; |
| 282 | + |
| 283 | + foreach (var client in m_ClientNetworkManagers) |
| 284 | + { |
| 285 | + client.NetworkConfig.NetworkPrefabs.Add(networkPrefab); |
| 286 | + client.NetworkConfig.EnableSceneManagement = false; |
| 287 | + // Add a client side prefab handler for this NetworkObject |
| 288 | + client.PrefabHandler.AddHandler(m_ObjectToSpawn, this); |
| 289 | + } |
| 290 | + m_DefaultNetworkObject.NetworkManagerOwner = m_ServerNetworkManager; |
| 291 | + m_ClientSideObject = Object.Instantiate(m_ObjectToSpawn); |
| 292 | + m_ClientSideObject.SetActive(false); |
| 293 | + } |
| 294 | + |
| 295 | + [UnityTest] |
| 296 | + public IEnumerator RespawnedPositionTest() |
| 297 | + { |
| 298 | + if (!MultiInstanceHelpers.Start(true, m_ServerNetworkManager, m_ClientNetworkManagers)) |
| 299 | + { |
| 300 | + Debug.LogError("Failed to start instances"); |
| 301 | + Assert.Fail("Failed to start instances"); |
| 302 | + } |
| 303 | + |
| 304 | + // Wait for connection on client side |
| 305 | + yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(m_ClientNetworkManagers)); |
| 306 | + |
| 307 | + // Wait for connection on server side |
| 308 | + yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnectedToServer(m_ServerNetworkManager, NbClients + 1)); |
| 309 | + |
| 310 | + Assert.True(m_ObjectToSpawn != null); |
| 311 | + Assert.True(m_DefaultNetworkObject != null); |
| 312 | + m_DefaultNetworkObject.Spawn(); |
| 313 | + yield return new WaitUntil(() => m_ClientSideSpawned); |
| 314 | + |
| 315 | + // Let the object move a bit |
| 316 | + yield return new WaitForSeconds(0.5f); |
| 317 | + |
| 318 | + // Make sure it moved on the client side |
| 319 | + Assert.IsTrue(m_ClientSideObject.transform.position != Vector3.zero); |
| 320 | + |
| 321 | + m_ServerNetworkManager.SpawnManager.DespawnObject(m_DefaultNetworkObject); |
| 322 | + yield return new WaitUntil(() => !m_ClientSideSpawned); |
| 323 | + |
| 324 | + // Re-spawn the same NetworkObject |
| 325 | + m_DefaultNetworkObject.Spawn(); |
| 326 | + yield return new WaitUntil(() => m_ClientSideSpawned); |
| 327 | + |
| 328 | + // !!! This is the primary element for this particular test !!! |
| 329 | + // If NetworkTransform.OnNetworkDespawn did not have m_LocalAuthoritativeNetworkState.Reset(); |
| 330 | + // then this will always fail. To verify this will fail you can comment out that line of code |
| 331 | + // in NetworkTransform.OnNetworkDespawn and run this test again. |
| 332 | + Assert.IsTrue(m_ClientSideObject.transform.position == Vector3.zero); |
| 333 | + |
| 334 | + // Next we make sure the last spawn instance position was anything but zero |
| 335 | + // (i.e. it moved prior to despawning and respawning the object) |
| 336 | + Assert.IsTrue(m_LastClientSidePosition != Vector3.zero); |
| 337 | + |
| 338 | + // Done |
| 339 | + m_DefaultNetworkObject.Despawn(); |
| 340 | + } |
| 341 | + |
| 342 | + public override IEnumerator Teardown() |
| 343 | + { |
| 344 | + if (m_ClientSideObject != null) |
| 345 | + { |
| 346 | + Object.Destroy(m_ClientSideObject); |
| 347 | + m_ClientSideObject = null; |
| 348 | + } |
| 349 | + |
| 350 | + if (m_ObjectToSpawn != null) |
| 351 | + { |
| 352 | + Object.Destroy(m_ObjectToSpawn); |
| 353 | + m_ObjectToSpawn = null; |
| 354 | + } |
| 355 | + |
| 356 | + return base.Teardown(); |
199 | 357 | }
|
200 | 358 | }
|
201 | 359 | }
|
0 commit comments