com.unity.netcode.gameobjects@1.0.0-pre.10

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [1.0.0-pre.10] - 2022-06-21

### Added

- Added a new `OnTransportFailure` callback to `NetworkManager`. This callback is invoked when the manager's `NetworkTransport` encounters an unrecoverable error. Transport failures also cause the `NetworkManager` to shut down. Currently, this is only used by `UnityTransport` to signal a timeout of its connection to the Unity Relay servers. (#1994)
- Added `NetworkEvent.TransportFailure`, which can be used by implementations of `NetworkTransport` to signal to `NetworkManager` that an unrecoverable error was encountered. (#1994)
- Added test to ensure a warning occurs when nesting NetworkObjects in a NetworkPrefab (#1969)
- Added `NetworkManager.RemoveNetworkPrefab(...)` to remove a prefab from the prefabs list (#1950)

### Changed

- Updated `UnityTransport` dependency on `com.unity.transport` to 1.1.0. (#2025)
- (API Breaking) `ConnectionApprovalCallback` is no longer an `event` and will not allow more than 1 handler registered at a time. Also, `ConnectionApprovalCallback` is now a `Func<>` taking `ConnectionApprovalRequest` in and returning `ConnectionApprovalResponse` back out (#1972)

### Removed

### Fixed
- Fixed issue where dynamically spawned `NetworkObject`s could throw an exception if the scene of origin handle was zero (0) and the `NetworkObject` was already spawned. (#2017)
- Fixed issue where `NetworkObject.Observers` was not being cleared when despawned. (#2009)
- Fixed `NetworkAnimator` could not run in the server authoritative mode. (#2003)
- Fixed issue where late joining clients would get a soft synchronization error if any in-scene placed NetworkObjects were parented under another `NetworkObject`. (#1985)
- Fixed issue where `NetworkBehaviourReference` would throw a type cast exception if using `NetworkBehaviourReference.TryGet` and the component type was not found. (#1984)
- Fixed `NetworkSceneManager` was not sending scene event notifications for the currently active scene and any additively loaded scenes when loading a new scene in `LoadSceneMode.Single` mode. (#1975)
- Fixed issue where one or more clients disconnecting during a scene event would cause `LoadEventCompleted` or `UnloadEventCompleted` to wait until the `NetworkConfig.LoadSceneTimeOut` period before being triggered. (#1973)
- Fixed issues when multiple `ConnectionApprovalCallback`s were registered (#1972)
- Fixed a regression in serialization support: `FixedString`, `Vector2Int`, and `Vector3Int` types can now be used in NetworkVariables and RPCs again without requiring a `ForceNetworkSerializeByMemcpy<>` wrapper. (#1961)
- Fixed generic types that inherit from NetworkBehaviour causing crashes at compile time. (#1976)
- Fixed endless dialog boxes when adding a `NetworkBehaviour` to a `NetworkManager` or vice-versa. (#1947)
- Fixed `NetworkAnimator` issue where it was only synchronizing parameters if the layer or state changed or was transitioning between states. (#1946)
- Fixed `NetworkAnimator` issue where when it did detect a parameter had changed it would send all parameters as opposed to only the parameters that changed. (#1946)
- Fixed `NetworkAnimator` issue where it was not always disposing the `NativeArray` that is allocated when spawned. (#1946)
- Fixed `NetworkAnimator` issue where it was not taking the animation speed or state speed multiplier into consideration. (#1946)
- Fixed `NetworkAnimator` issue where it was not properly synchronizing late joining clients if they joined while `Animator` was transitioning between states. (#1946)
- Fixed `NetworkAnimator` issue where the server was not relaying changes to non-owner clients when a client was the owner. (#1946)
- Fixed issue where the `PacketLoss` metric for tools would return the packet loss over a connection lifetime instead of a single frame. (#2004)
This commit is contained in:
Unity Technologies
2022-06-21 00:00:00 +00:00
parent 5b1fc203ed
commit 0f7a30d285
62 changed files with 3763 additions and 1286 deletions

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
using System.Runtime.CompilerServices;
@@ -16,7 +17,12 @@ namespace Unity.Netcode.TestHelpers.Runtime
/// </summary>
public abstract class NetcodeIntegrationTest
{
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(4.0f);
/// <summary>
/// Used to determine if a NetcodeIntegrationTest is currently running to
/// determine how clients will load scenes
/// </summary>
internal static bool IsRunning { get; private set; }
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(8.0f);
protected static WaitForSeconds s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
/// <summary>
@@ -74,9 +80,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
}
}
protected int TotalClients => m_UseHost ? NumberOfClients + 1 : NumberOfClients;
protected int TotalClients => m_UseHost ? m_NumberOfClients + 1 : m_NumberOfClients;
protected const uint k_DefaultTickRate = 30;
private int m_NumberOfClients;
protected abstract int NumberOfClients { get; }
/// <summary>
@@ -119,7 +127,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
private NetworkManagerInstatiationMode m_NetworkManagerInstatiationMode;
private bool m_EnableVerboseDebug;
protected bool m_EnableVerboseDebug { get; set; }
/// <summary>
/// Used to display the various integration test
@@ -165,8 +173,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
[OneTimeSetUp]
public void OneTimeSetup()
{
Application.runInBackground = true;
m_NumberOfClients = NumberOfClients;
IsRunning = true;
m_EnableVerboseDebug = OnSetVerboseDebug();
IntegrationTestSceneHandler.VerboseDebugMode = m_EnableVerboseDebug;
VerboseDebug($"Entering {nameof(OneTimeSetup)}");
m_NetworkManagerInstatiationMode = OnSetIntegrationTestMode();
@@ -248,6 +259,61 @@ namespace Unity.Netcode.TestHelpers.Runtime
CreateServerAndClients(NumberOfClients);
}
protected virtual void OnNewClientCreated(NetworkManager networkManager)
{
}
protected virtual void OnNewClientStartedAndConnected(NetworkManager networkManager)
{
}
private void AddRemoveNetworkManager(NetworkManager networkManager, bool addNetworkManager)
{
var clientNetworkManagersList = new List<NetworkManager>(m_ClientNetworkManagers);
if (addNetworkManager)
{
clientNetworkManagersList.Add(networkManager);
}
else
{
clientNetworkManagersList.Remove(networkManager);
}
m_ClientNetworkManagers = clientNetworkManagersList.ToArray();
m_NumberOfClients = clientNetworkManagersList.Count;
}
protected IEnumerator CreateAndStartNewClient()
{
var networkManager = NetcodeIntegrationTestHelpers.CreateNewClient(m_ClientNetworkManagers.Length);
networkManager.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
// Notification that the new client (NetworkManager) has been created
// in the event any modifications need to be made before starting the client
OnNewClientCreated(networkManager);
NetcodeIntegrationTestHelpers.StartOneClient(networkManager);
AddRemoveNetworkManager(networkManager, true);
// Wait for the new client to connect
yield return WaitForClientsConnectedOrTimeOut();
if (s_GlobalTimeoutHelper.TimedOut)
{
AddRemoveNetworkManager(networkManager, false);
Object.Destroy(networkManager.gameObject);
}
AssertOnTimeout($"{nameof(CreateAndStartNewClient)} timed out waiting for the new client to be connected!");
ClientNetworkManagerPostStart(networkManager);
VerboseDebug($"[{networkManager.name}] Created and connected!");
}
protected IEnumerator StopOneClient(NetworkManager networkManager, bool destroy = false)
{
NetcodeIntegrationTestHelpers.StopOneClient(networkManager, destroy);
AddRemoveNetworkManager(networkManager, false);
yield return WaitForConditionOrTimeOut(() => !networkManager.IsConnectedClient);
}
/// <summary>
/// Creates the server and clients
/// </summary>
@@ -315,6 +381,54 @@ namespace Unity.Netcode.TestHelpers.Runtime
yield return null;
}
private void ClientNetworkManagerPostStart(NetworkManager networkManager)
{
networkManager.name = $"NetworkManager - Client - {networkManager.LocalClientId}";
Assert.NotNull(networkManager.LocalClient.PlayerObject, $"{nameof(StartServerAndClients)} detected that client {networkManager.LocalClientId} does not have an assigned player NetworkObject!");
// Get all player instances for the current client NetworkManager instance
var clientPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == networkManager.LocalClientId);
// Add this player instance to each client player entry
foreach (var playerNetworkObject in clientPlayerClones)
{
// When the server is not the host this needs to be done
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
{
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
}
if (!m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].ContainsKey(networkManager.LocalClientId))
{
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(networkManager.LocalClientId, playerNetworkObject);
}
}
}
protected void ClientNetworkManagerPostStartInit()
{
// Creates a dictionary for all player instances client and server relative
// This provides a simpler way to get a specific player instance relative to a client instance
foreach (var networkManager in m_ClientNetworkManagers)
{
ClientNetworkManagerPostStart(networkManager);
}
if (m_UseHost)
{
var clientSideServerPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == m_ServerNetworkManager.LocalClientId);
foreach (var playerNetworkObject in clientSideServerPlayerClones)
{
// When the server is not the host this needs to be done
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
{
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
}
if (!m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].ContainsKey(m_ServerNetworkManager.LocalClientId))
{
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(m_ServerNetworkManager.LocalClientId, playerNetworkObject);
}
}
}
}
/// <summary>
/// This starts the server and clients as long as <see cref="CanStartServerAndClients"/>
/// returns true.
@@ -340,8 +454,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
// Wait for all clients to connect
yield return WaitForClientsConnectedOrTimeOut();
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"{nameof(StartServerAndClients)} timed out waiting for all clients to be connected!");
AssertOnTimeout($"{nameof(StartServerAndClients)} timed out waiting for all clients to be connected!");
if (m_UseHost || m_ServerNetworkManager.IsHost)
{
@@ -357,25 +470,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
}
}
// Creates a dictionary for all player instances client and server relative
// This provides a simpler way to get a specific player instance relative to a client instance
foreach (var networkManager in m_ClientNetworkManagers)
{
Assert.NotNull(networkManager.LocalClient.PlayerObject, $"{nameof(StartServerAndClients)} detected that client {networkManager.LocalClientId} does not have an assigned player NetworkObject!");
// Get all player instances for the current client NetworkManager instance
var clientPlayerClones = Object.FindObjectsOfType<NetworkObject>().Where((c) => c.IsPlayerObject && c.OwnerClientId == networkManager.LocalClientId);
// Add this player instance to each client player entry
foreach (var playerNetworkObject in clientPlayerClones)
{
// When the server is not the host this needs to be done
if (!m_PlayerNetworkObjects.ContainsKey(playerNetworkObject.NetworkManager.LocalClientId))
{
m_PlayerNetworkObjects.Add(playerNetworkObject.NetworkManager.LocalClientId, new Dictionary<ulong, NetworkObject>());
}
m_PlayerNetworkObjects[playerNetworkObject.NetworkManager.LocalClientId].Add(networkManager.LocalClientId, playerNetworkObject);
}
}
ClientNetworkManagerPostStartInit();
// Notification that at this time the server and client(s) are instantiated,
// started, and connected on both sides.
@@ -409,11 +504,9 @@ namespace Unity.Netcode.TestHelpers.Runtime
/// </summary>
protected void DeRegisterSceneManagerHandler()
{
if (NetcodeIntegrationTestHelpers.ClientSceneHandler != null)
{
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsLoad -= ClientSceneHandler_CanClientsLoad;
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsUnload -= ClientSceneHandler_CanClientsUnload;
}
IntegrationTestSceneHandler.CanClientsLoad -= ClientSceneHandler_CanClientsLoad;
IntegrationTestSceneHandler.CanClientsUnload -= ClientSceneHandler_CanClientsUnload;
IntegrationTestSceneHandler.NetworkManagers.Clear();
}
/// <summary>
@@ -423,11 +516,9 @@ namespace Unity.Netcode.TestHelpers.Runtime
/// </summary>
protected void RegisterSceneManagerHandler()
{
if (NetcodeIntegrationTestHelpers.ClientSceneHandler != null)
{
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsLoad += ClientSceneHandler_CanClientsLoad;
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsUnload += ClientSceneHandler_CanClientsUnload;
}
IntegrationTestSceneHandler.CanClientsLoad += ClientSceneHandler_CanClientsLoad;
IntegrationTestSceneHandler.CanClientsUnload += ClientSceneHandler_CanClientsUnload;
NetcodeIntegrationTestHelpers.RegisterSceneManagerHandler(m_ServerNetworkManager, true);
}
private bool ClientSceneHandler_CanClientsUnload()
@@ -440,6 +531,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
return CanClientsLoad();
}
protected bool OnCanSceneCleanUpUnload(Scene scene)
{
return true;
}
/// <summary>
/// This shuts down all NetworkManager instances registered via the
/// <see cref="NetcodeIntegrationTestHelpers"/> class and cleans up
@@ -452,11 +548,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
// Shutdown and clean up both of our NetworkManager instances
try
{
if (NetcodeIntegrationTestHelpers.ClientSceneHandler != null)
{
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsLoad -= ClientSceneHandler_CanClientsLoad;
NetcodeIntegrationTestHelpers.ClientSceneHandler.CanClientsUnload -= ClientSceneHandler_CanClientsUnload;
}
DeRegisterSceneManagerHandler();
NetcodeIntegrationTestHelpers.Destroy();
@@ -476,6 +568,8 @@ namespace Unity.Netcode.TestHelpers.Runtime
// Cleanup any remaining NetworkObjects
DestroySceneNetworkObjects();
UnloadRemainingScenes();
// reset the m_ServerWaitForTick for the next test to initialize
s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
VerboseDebug($"Exiting {nameof(ShutdownAndCleanUp)}");
@@ -517,6 +611,7 @@ namespace Unity.Netcode.TestHelpers.Runtime
[OneTimeTearDown]
public void OneTimeTearDown()
{
IntegrationTestSceneHandler.VerboseDebugMode = false;
VerboseDebug($"Entering {nameof(OneTimeTearDown)}");
OnOneTimeTearDown();
@@ -528,7 +623,11 @@ namespace Unity.Netcode.TestHelpers.Runtime
// Disable NetcodeIntegrationTest auto-label feature
NetcodeIntegrationTestHelpers.RegisterNetcodeIntegrationTest(false);
UnloadRemainingScenes();
VerboseDebug($"Exiting {nameof(OneTimeTearDown)}");
IsRunning = false;
}
/// <summary>
@@ -783,5 +882,32 @@ namespace Unity.Netcode.TestHelpers.Runtime
{
m_UseHost = hostOrServer == HostOrServer.Host ? true : false;
}
/// <summary>
/// Just a helper function to avoid having to write the entire assert just to check if you
/// timed out.
/// </summary>
protected void AssertOnTimeout(string timeOutErrorMessage, TimeoutHelper assignedTimeoutHelper = null)
{
var timeoutHelper = assignedTimeoutHelper != null ? assignedTimeoutHelper : s_GlobalTimeoutHelper;
Assert.False(timeoutHelper.TimedOut, timeOutErrorMessage);
}
private void UnloadRemainingScenes()
{
// Unload any remaining scenes loaded but the test runner scene
// Note: Some tests only unload the server-side instance, and this
// just assures no currently loaded scenes will impact the next test
for (int i = 0; i < SceneManager.sceneCount; i++)
{
var scene = SceneManager.GetSceneAt(i);
if (!scene.IsValid() || !scene.isLoaded || scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName) || !OnCanSceneCleanUpUnload(scene))
{
continue;
}
VerboseDebug($"Unloading scene {scene.name}-{scene.handle}");
var asyncOperation = SceneManager.UnloadSceneAsync(scene);
}
}
}
}