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:
@@ -60,6 +60,8 @@ namespace Unity.Netcode
|
||||
|
||||
private NetworkPrefabHandler m_PrefabHandler;
|
||||
|
||||
internal Dictionary<ulong, ConnectionApprovalResponse> ClientsToApprove = new Dictionary<ulong, ConnectionApprovalResponse>();
|
||||
|
||||
public NetworkPrefabHandler PrefabHandler
|
||||
{
|
||||
get
|
||||
@@ -206,12 +208,14 @@ namespace Unity.Netcode
|
||||
/// <summary>
|
||||
/// Gets or sets if the application should be set to run in background
|
||||
/// </summary>
|
||||
[HideInInspector] public bool RunInBackground = true;
|
||||
[HideInInspector]
|
||||
public bool RunInBackground = true;
|
||||
|
||||
/// <summary>
|
||||
/// The log level to use
|
||||
/// </summary>
|
||||
[HideInInspector] public LogLevel LogLevel = LogLevel.Normal;
|
||||
[HideInInspector]
|
||||
public LogLevel LogLevel = LogLevel.Normal;
|
||||
|
||||
/// <summary>
|
||||
/// The singleton instance of the NetworkManager
|
||||
@@ -358,26 +362,71 @@ namespace Unity.Netcode
|
||||
public event Action OnServerStarted = null;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type called when connection has been approved. This only has to be set on the server.
|
||||
/// The callback to invoke if the <see cref="NetworkTransport"/> fails.
|
||||
/// </summary>
|
||||
/// <param name="createPlayerObject">If true, a player object will be created. Otherwise the client will have no object.</param>
|
||||
/// <param name="playerPrefabHash">The prefabHash to use for the client. If createPlayerObject is false, this is ignored. If playerPrefabHash is null, the default player prefab is used.</param>
|
||||
/// <param name="approved">Whether or not the client was approved</param>
|
||||
/// <param name="position">The position to spawn the client at. If null, the prefab position is used.</param>
|
||||
/// <param name="rotation">The rotation to spawn the client with. If null, the prefab position is used.</param>
|
||||
public delegate void ConnectionApprovedDelegate(bool createPlayerObject, uint? playerPrefabHash, bool approved, Vector3? position, Quaternion? rotation);
|
||||
/// <remarks>
|
||||
/// A failure of the transport is always followed by the <see cref="NetworkManager"/> shutting down. Recovering
|
||||
/// from a transport failure would normally entail reconfiguring the transport (e.g. re-authenticating, or
|
||||
/// recreating a new service allocation depending on the transport) and restarting the client/server/host.
|
||||
/// </remarks>
|
||||
public event Action OnTransportFailure = null;
|
||||
|
||||
/// <summary>
|
||||
/// The callback to invoke during connection approval
|
||||
/// Connection Approval Response
|
||||
/// </summary>
|
||||
public event Action<byte[], ulong, ConnectionApprovedDelegate> ConnectionApprovalCallback = null;
|
||||
/// <param name="Approved">Whether or not the client was approved</param>
|
||||
/// <param name="CreatePlayerObject">If true, a player object will be created. Otherwise the client will have no object.</param>
|
||||
/// <param name="PlayerPrefabHash">The prefabHash to use for the client. If createPlayerObject is false, this is ignored. If playerPrefabHash is null, the default player prefab is used.</param>
|
||||
/// <param name="Position">The position to spawn the client at. If null, the prefab position is used.</param>
|
||||
/// <param name="Rotation">The rotation to spawn the client with. If null, the prefab position is used.</param>
|
||||
/// <param name="Pending">If the Approval decision cannot be made immediately, the client code can set Pending to true, keep a reference to the ConnectionApprovalResponse object and write to it later. Client code must exercise care to setting all the members to the value it wants before marking Pending to false, to indicate completion. If the field is set as Pending = true, we'll monitor the object until it gets set to not pending anymore and use the parameters then.</param>
|
||||
public class ConnectionApprovalResponse
|
||||
{
|
||||
public bool Approved;
|
||||
public bool CreatePlayerObject;
|
||||
public uint? PlayerPrefabHash;
|
||||
public Vector3? Position;
|
||||
public Quaternion? Rotation;
|
||||
public bool Pending;
|
||||
}
|
||||
|
||||
internal void InvokeConnectionApproval(byte[] payload, ulong clientId, ConnectionApprovedDelegate action) => ConnectionApprovalCallback?.Invoke(payload, clientId, action);
|
||||
/// <summary>
|
||||
/// Connection Approval Request
|
||||
/// </summary>
|
||||
/// <param name="Payload">The connection data payload</param>
|
||||
/// <param name="ClientNetworkId">The Network Id of the client we are about to handle</param>
|
||||
public struct ConnectionApprovalRequest
|
||||
{
|
||||
public byte[] Payload;
|
||||
public ulong ClientNetworkId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The callback to invoke during connection approval. Allows client code to decide whether or not to allow incoming client connection
|
||||
/// </summary>
|
||||
public Action<ConnectionApprovalRequest, ConnectionApprovalResponse> ConnectionApprovalCallback
|
||||
{
|
||||
get => m_ConnectionApprovalCallback;
|
||||
set
|
||||
{
|
||||
if (value != null && value.GetInvocationList().Length > 1)
|
||||
{
|
||||
throw new InvalidOperationException($"Only one {nameof(ConnectionApprovalCallback)} can be registered at a time.");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ConnectionApprovalCallback = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Action<ConnectionApprovalRequest, ConnectionApprovalResponse> m_ConnectionApprovalCallback;
|
||||
|
||||
/// <summary>
|
||||
/// The current NetworkConfig
|
||||
/// </summary>
|
||||
[HideInInspector] public NetworkConfig NetworkConfig;
|
||||
[HideInInspector]
|
||||
public NetworkConfig NetworkConfig;
|
||||
|
||||
/// <summary>
|
||||
/// The current host name we are connected to, used to validate certificate
|
||||
@@ -389,7 +438,7 @@ namespace Unity.Netcode
|
||||
internal static event Action OnSingletonReady;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
internal void OnValidate()
|
||||
{
|
||||
if (NetworkConfig == null)
|
||||
{
|
||||
@@ -541,6 +590,47 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a prefab from the prefab list.
|
||||
/// As with AddNetworkPrefab, this is specific to the client it's called on -
|
||||
/// calling it on the server does not automatically remove anything on any of the
|
||||
/// client processes.
|
||||
///
|
||||
/// Like AddNetworkPrefab, when NetworkConfig.ForceSamePrefabs is enabled,
|
||||
/// this cannot be called after connecting.
|
||||
/// </summary>
|
||||
/// <param name="prefab"></param>
|
||||
public void RemoveNetworkPrefab(GameObject prefab)
|
||||
{
|
||||
if (IsListening && NetworkConfig.ForceSamePrefabs)
|
||||
{
|
||||
throw new Exception($"Prefabs cannot be removed after starting {nameof(NetworkManager)} when {nameof(NetworkConfig.ForceSamePrefabs)} is enabled.");
|
||||
}
|
||||
|
||||
var globalObjectIdHash = prefab.GetComponent<NetworkObject>().GlobalObjectIdHash;
|
||||
for (var i = 0; i < NetworkConfig.NetworkPrefabs.Count; ++i)
|
||||
{
|
||||
if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent<NetworkObject>().GlobalObjectIdHash == globalObjectIdHash)
|
||||
{
|
||||
NetworkConfig.NetworkPrefabs.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (PrefabHandler.ContainsHandler(globalObjectIdHash))
|
||||
{
|
||||
PrefabHandler.RemoveHandler(globalObjectIdHash);
|
||||
}
|
||||
if (NetworkConfig.NetworkPrefabOverrideLinks.TryGetValue(globalObjectIdHash, out var targetPrefab))
|
||||
{
|
||||
NetworkConfig.NetworkPrefabOverrideLinks.Remove(globalObjectIdHash);
|
||||
var targetHash = targetPrefab.Prefab.GetComponent<NetworkObject>().GlobalObjectIdHash;
|
||||
if (NetworkConfig.OverrideToNetworkPrefab.ContainsKey(targetHash))
|
||||
{
|
||||
NetworkConfig.OverrideToNetworkPrefab.Remove(targetHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldAddPrefab(NetworkPrefab networkPrefab, out uint sourcePrefabGlobalObjectIdHash, out uint targetPrefabGlobalObjectIdHash, int index = -1)
|
||||
{
|
||||
sourcePrefabGlobalObjectIdHash = 0;
|
||||
@@ -865,6 +955,7 @@ namespace Unity.Netcode
|
||||
m_ConnectedClientIds.Clear();
|
||||
LocalClient = null;
|
||||
NetworkObject.OrphanChildren.Clear();
|
||||
ClientsToApprove.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -899,6 +990,7 @@ namespace Unity.Netcode
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Server is shutting down due to network transport start failure of {NetworkConfig.NetworkTransport.GetType().Name}!");
|
||||
OnTransportFailure?.Invoke();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
@@ -926,6 +1018,7 @@ namespace Unity.Netcode
|
||||
if (!NetworkConfig.NetworkTransport.StartClient())
|
||||
{
|
||||
Debug.LogError($"Client is shutting down due to network transport start failure of {NetworkConfig.NetworkTransport.GetType().Name}!");
|
||||
OnTransportFailure?.Invoke();
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
@@ -958,6 +1051,7 @@ namespace Unity.Netcode
|
||||
if (!NetworkConfig.NetworkTransport.StartServer())
|
||||
{
|
||||
Debug.LogError($"Server is shutting down due to network transport start failure of {NetworkConfig.NetworkTransport.GetType().Name}!");
|
||||
OnTransportFailure?.Invoke();
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
@@ -970,27 +1064,29 @@ namespace Unity.Netcode
|
||||
IsClient = true;
|
||||
IsListening = true;
|
||||
|
||||
if (NetworkConfig.ConnectionApproval)
|
||||
if (NetworkConfig.ConnectionApproval && ConnectionApprovalCallback != null)
|
||||
{
|
||||
InvokeConnectionApproval(NetworkConfig.ConnectionData, ServerClientId,
|
||||
(createPlayerObject, playerPrefabHash, approved, position, rotation) =>
|
||||
var response = new ConnectionApprovalResponse();
|
||||
ConnectionApprovalCallback(new ConnectionApprovalRequest { Payload = NetworkConfig.ConnectionData, ClientNetworkId = ServerClientId }, response);
|
||||
if (!response.Approved)
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
// You cannot decline the local server. Force approved to true
|
||||
if (!approved)
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
|
||||
{
|
||||
NetworkLog.LogWarning(
|
||||
"You cannot decline the host connection. The connection was automatically approved.");
|
||||
}
|
||||
}
|
||||
NetworkLog.LogWarning("You cannot decline the host connection. The connection was automatically approved.");
|
||||
}
|
||||
}
|
||||
|
||||
HandleApproval(ServerClientId, createPlayerObject, playerPrefabHash, true, position, rotation);
|
||||
});
|
||||
response.Approved = true;
|
||||
HandleConnectionApproval(ServerClientId, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleApproval(ServerClientId, NetworkConfig.PlayerPrefab != null, null, true, null, null);
|
||||
var response = new ConnectionApprovalResponse
|
||||
{
|
||||
Approved = true,
|
||||
CreatePlayerObject = NetworkConfig.PlayerPrefab != null
|
||||
};
|
||||
HandleConnectionApproval(ServerClientId, response);
|
||||
}
|
||||
|
||||
SpawnManager.ServerSpawnSceneObjectsOnStartSweep();
|
||||
@@ -1076,7 +1172,6 @@ namespace Unity.Netcode
|
||||
private void Awake()
|
||||
{
|
||||
UnityEngine.SceneManagement.SceneManager.sceneUnloaded += OnSceneUnloaded;
|
||||
NetworkVariableHelper.InitializeAllBaseDelegates();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1327,6 +1422,43 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessPendingApprovals()
|
||||
{
|
||||
List<ulong> senders = null;
|
||||
|
||||
foreach (var responsePair in ClientsToApprove)
|
||||
{
|
||||
var response = responsePair.Value;
|
||||
var senderId = responsePair.Key;
|
||||
|
||||
if (!response.Pending)
|
||||
{
|
||||
try
|
||||
{
|
||||
HandleConnectionApproval(senderId, response);
|
||||
|
||||
if (senders == null)
|
||||
{
|
||||
senders = new List<ulong>();
|
||||
}
|
||||
senders.Add(senderId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (senders != null)
|
||||
{
|
||||
foreach (var sender in senders)
|
||||
{
|
||||
ClientsToApprove.Remove(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkEarlyUpdate()
|
||||
{
|
||||
if (!IsListening)
|
||||
@@ -1334,6 +1466,8 @@ namespace Unity.Netcode
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessPendingApprovals();
|
||||
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
s_TransportPoll.Begin();
|
||||
#endif
|
||||
@@ -1554,6 +1688,12 @@ namespace Unity.Netcode
|
||||
s_TransportDisconnect.End();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case NetworkEvent.TransportFailure:
|
||||
Debug.LogError($"Shutting down due to network transport failure of {NetworkConfig.NetworkTransport.GetType().Name}!");
|
||||
OnTransportFailure?.Invoke();
|
||||
Shutdown(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1818,15 +1958,11 @@ namespace Unity.Netcode
|
||||
/// <summary>
|
||||
/// Server Side: Handles the approval of a client
|
||||
/// </summary>
|
||||
/// <param name="ownerClientId">client being approved</param>
|
||||
/// <param name="createPlayerObject">whether we want to create a player or not</param>
|
||||
/// <param name="playerPrefabHash">the GlobalObjectIdHash value for the Network Prefab to create as the player</param>
|
||||
/// <param name="approved">Is the player approved or not?</param>
|
||||
/// <param name="position">Used when createPlayerObject is true, position of the player when spawned </param>
|
||||
/// <param name="rotation">Used when createPlayerObject is true, rotation of the player when spawned</param>
|
||||
internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? playerPrefabHash, bool approved, Vector3? position, Quaternion? rotation)
|
||||
/// <param name="ownerClientId">The Network Id of the client being approved</param>
|
||||
/// <param name="response">The response to allow the player in or not, with its parameters</param>
|
||||
internal void HandleConnectionApproval(ulong ownerClientId, ConnectionApprovalResponse response)
|
||||
{
|
||||
if (approved)
|
||||
if (response.Approved)
|
||||
{
|
||||
// Inform new client it got approved
|
||||
PendingClients.Remove(ownerClientId);
|
||||
@@ -1836,10 +1972,23 @@ namespace Unity.Netcode
|
||||
m_ConnectedClientsList.Add(client);
|
||||
m_ConnectedClientIds.Add(client.ClientId);
|
||||
|
||||
if (createPlayerObject)
|
||||
if (response.CreatePlayerObject)
|
||||
{
|
||||
var networkObject = SpawnManager.CreateLocalNetworkObject(false, playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash, ownerClientId, null, position, rotation);
|
||||
SpawnManager.SpawnNetworkObjectLocally(networkObject, SpawnManager.GetNetworkObjectId(), false, true, ownerClientId, false);
|
||||
var networkObject = SpawnManager.CreateLocalNetworkObject(
|
||||
isSceneObject: false,
|
||||
response.PlayerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash,
|
||||
ownerClientId,
|
||||
parentNetworkId: null,
|
||||
networkSceneHandle: null,
|
||||
response.Position,
|
||||
response.Rotation);
|
||||
SpawnManager.SpawnNetworkObjectLocally(
|
||||
networkObject,
|
||||
SpawnManager.GetNetworkObjectId(),
|
||||
sceneObject: false,
|
||||
playerObject: true,
|
||||
ownerClientId,
|
||||
destroyWithScene: false);
|
||||
|
||||
ConnectedClients[ownerClientId].PlayerObject = networkObject;
|
||||
}
|
||||
@@ -1879,13 +2028,13 @@ namespace Unity.Netcode
|
||||
InvokeOnClientConnectedCallback(ownerClientId);
|
||||
}
|
||||
|
||||
if (!createPlayerObject || (playerPrefabHash == null && NetworkConfig.PlayerPrefab == null))
|
||||
if (!response.CreatePlayerObject || (response.PlayerPrefabHash == null && NetworkConfig.PlayerPrefab == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Separating this into a contained function call for potential further future separation of when this notification is sent.
|
||||
ApprovedPlayerSpawn(ownerClientId, playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash);
|
||||
ApprovedPlayerSpawn(ownerClientId, response.PlayerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user