com.unity.netcode.gameobjects@1.8.0
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.8.0] - 2023-12-12 ### Added - Added a new RPC attribute, which is simply `Rpc`. (#2762) - This is a generic attribute that can perform the functions of both Server and Client RPCs, as well as enabling client-to-client RPCs. Includes several default targets: `Server`, `NotServer`, `Owner`, `NotOwner`, `Me`, `NotMe`, `ClientsAndHost`, and `Everyone`. Runtime overrides are available for any of these targets, as well as for sending to a specific ID or groups of IDs. - This attribute also includes the ability to defer RPCs that are sent to the local process to the start of the next frame instead of executing them immediately, treating them as if they had gone across the network. The default behavior is to execute immediately. - This attribute effectively replaces `ServerRpc` and `ClientRpc`. `ServerRpc` and `ClientRpc` remain in their existing forms for backward compatibility, but `Rpc` will be the recommended and most supported option. - Added `NetworkManager.OnConnectionEvent` as a unified connection event callback to notify clients and servers of all client connections and disconnections within the session (#2762) - Added `NetworkManager.ServerIsHost` and `NetworkBehaviour.ServerIsHost` to allow a client to tell if it is connected to a host or to a dedicated server (#2762) - Added `SceneEventProgress.SceneManagementNotEnabled` return status to be returned when a `NetworkSceneManager` method is invoked and scene management is not enabled. (#2735) - Added `SceneEventProgress.ServerOnlyAction` return status to be returned when a `NetworkSceneManager` method is invoked by a client. (#2735) - Added `NetworkObject.InstantiateAndSpawn` and `NetworkSpawnManager.InstantiateAndSpawn` methods to simplify prefab spawning by assuring that the prefab is valid and applies any override prior to instantiating the `GameObject` and spawning the `NetworkObject` instance. (#2710) ### Fixed - Fixed issue where a client disconnected by a server-host would not receive a local notification. (#2789) - Fixed issue where a server-host could shutdown during a relay connection but periodically the transport disconnect message sent to any connected clients could be dropped. (#2789) - Fixed issue where a host could disconnect its local client but remain running as a server. (#2789) - Fixed issue where `OnClientDisconnectedCallback` was not being invoked under certain conditions. (#2789) - Fixed issue where `OnClientDisconnectedCallback` was always returning 0 as the client identifier. (#2789) - Fixed issue where if a host or server shutdown while a client owned NetworkObjects (other than the player) it would throw an exception. (#2789) - Fixed issue where setting values on a `NetworkVariable` or `NetworkList` within `OnNetworkDespawn` during a shutdown sequence would throw an exception. (#2789) - Fixed issue where a teleport state could potentially be overridden by a previous unreliable delta state. (#2777) - Fixed issue where `NetworkTransform` was using the `NetworkManager.ServerTime.Tick` as opposed to `NetworkManager.NetworkTickSystem.ServerTime.Tick` during the authoritative side's tick update where it performed a delta state check. (#2777) - Fixed issue where a parented in-scene placed NetworkObject would be destroyed upon a client or server exiting a network session but not unloading the original scene in which the NetworkObject was placed. (#2737) - Fixed issue where during client synchronization and scene loading, when client synchronization or the scene loading mode are set to `LoadSceneMode.Single`, a `CreateObjectMessage` could be received, processed, and the resultant spawned `NetworkObject` could be instantiated in the client's currently active scene that could, towards the end of the client synchronization or loading process, be unloaded and cause the newly created `NetworkObject` to be destroyed (and throw and exception). (#2735) - Fixed issue where a `NetworkTransform` instance with interpolation enabled would result in wide visual motion gaps (stuttering) under above normal latency conditions and a 1-5% or higher packet are drop rate. (#2713) - Fixed issue where you could not have multiple source network prefab overrides targeting the same network prefab as their override. (#2710) ### Changed - Changed the server or host shutdown so it will now perform a "soft shutdown" when `NetworkManager.Shutdown` is invoked. This will send a disconnect notification to all connected clients and the server-host will wait for all connected clients to disconnect or timeout after a 5 second period before completing the shutdown process. (#2789) - Changed `OnClientDisconnectedCallback` will now return the assigned client identifier on the local client side if the client was approved and assigned one prior to being disconnected. (#2789) - Changed `NetworkTransform.SetState` (and related methods) now are cumulative during a fractional tick period and sent on the next pending tick. (#2777) - `NetworkManager.ConnectedClientsIds` is now accessible on the client side and will contain the list of all clients in the session, including the host client if the server is operating in host mode (#2762) - Changed `NetworkSceneManager` to return a `SceneEventProgress` status and not throw exceptions for methods invoked when scene management is disabled and when a client attempts to access a `NetworkSceneManager` method by a client. (#2735) - Changed `NetworkTransform` authoritative instance tick registration so a single `NetworkTransform` specific tick event update will update all authoritative instances to improve perofmance. (#2713) - Changed `NetworkPrefabs.OverrideToNetworkPrefab` dictionary is no longer used/populated due to it ending up being related to a regression bug and not allowing more than one override to be assigned to a network prefab asset. (#2710) - Changed in-scene placed `NetworkObject`s now store their source network prefab asset's `GlobalObjectIdHash` internally that is used, when scene management is disabled, by clients to spawn the correct prefab even if the `NetworkPrefab` entry has an override. This does not impact dynamically spawning the same prefab which will yield the override on both host and client. (#2710) - Changed in-scene placed `NetworkObject`s no longer require a `NetworkPrefab` entry with `GlobalObjectIdHash` override in order for clients to properly synchronize. (#2710) - Changed in-scene placed `NetworkObject`s now set their `IsSceneObject` value when generating their `GlobalObjectIdHash` value. (#2710) - Changed the default `NetworkConfig.SpawnTimeout` value from 1.0s to 10.0s. (#2710)
This commit is contained in:
@@ -10,6 +10,38 @@ using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
|
||||
public enum ConnectionEvent
|
||||
{
|
||||
ClientConnected,
|
||||
PeerConnected,
|
||||
ClientDisconnected,
|
||||
PeerDisconnected
|
||||
}
|
||||
|
||||
public struct ConnectionEventData
|
||||
{
|
||||
public ConnectionEvent EventType;
|
||||
|
||||
/// <summary>
|
||||
/// The client ID for the client that just connected
|
||||
/// For the <see cref="ConnectionEvent.ClientConnected"/> and <see cref="ConnectionEvent.ClientDisconnected"/>
|
||||
/// events on the client side, this will be LocalClientId.
|
||||
/// On the server side, this will be the ID of the client that just connected.
|
||||
///
|
||||
/// For the <see cref="ConnectionEvent.PeerConnected"/> and <see cref="ConnectionEvent.PeerDisconnected"/>
|
||||
/// events on the client side, this will be the client ID assigned by the server to the remote peer.
|
||||
/// </summary>
|
||||
public ulong ClientId;
|
||||
|
||||
/// <summary>
|
||||
/// This is only populated in <see cref="ConnectionEvent.ClientConnected"/> on the client side, and
|
||||
/// contains the list of other peers who were present before you connected. In all other situations,
|
||||
/// this array will be uninitialized.
|
||||
/// </summary>
|
||||
public NativeArray<ulong> PeerClientIds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The NGO connection manager handles:
|
||||
/// - Client Connections
|
||||
@@ -42,7 +74,105 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
public event Action<ulong> OnClientDisconnectCallback = null;
|
||||
|
||||
internal void InvokeOnClientConnectedCallback(ulong clientId) => OnClientConnectedCallback?.Invoke(clientId);
|
||||
/// <summary>
|
||||
/// The callback to invoke once a peer connects. This callback is only ran on the server and on the local client that connects.
|
||||
/// </summary>
|
||||
public event Action<NetworkManager, ConnectionEventData> OnConnectionEvent = null;
|
||||
|
||||
|
||||
internal void InvokeOnClientConnectedCallback(ulong clientId)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnClientConnectedCallback?.Invoke(clientId);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
|
||||
if (!NetworkManager.IsServer)
|
||||
{
|
||||
var peerClientIds = new NativeArray<ulong>(Math.Max(NetworkManager.ConnectedClientsIds.Count - 1, 0), Allocator.Temp);
|
||||
// `using var peerClientIds` or `using(peerClientIds)` renders it immutable...
|
||||
using var sentinel = peerClientIds;
|
||||
|
||||
var idx = 0;
|
||||
foreach (var peerId in NetworkManager.ConnectedClientsIds)
|
||||
{
|
||||
if (peerId == NetworkManager.LocalClientId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
peerClientIds[idx] = peerId;
|
||||
++idx;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = NetworkManager.LocalClientId, EventType = ConnectionEvent.ClientConnected, PeerClientIds = peerClientIds });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = clientId, EventType = ConnectionEvent.ClientConnected });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void InvokeOnClientDisconnectCallback(ulong clientId)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnClientDisconnectCallback?.Invoke(clientId);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
try
|
||||
{
|
||||
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = clientId, EventType = ConnectionEvent.ClientDisconnected });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
internal void InvokeOnPeerConnectedCallback(ulong clientId)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = clientId, EventType = ConnectionEvent.PeerConnected });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
internal void InvokeOnPeerDisconnectedCallback(ulong clientId)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnConnectionEvent?.Invoke(NetworkManager, new ConnectionEventData { ClientId = clientId, EventType = ConnectionEvent.PeerDisconnected });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The callback to invoke if the <see cref="NetworkTransport"/> fails.
|
||||
@@ -217,7 +347,7 @@ namespace Unity.Netcode
|
||||
// When this happens, the client will not have an entry within the m_TransportIdToClientIdMap or m_ClientIdToTransportIdMap lookup tables so we exit early and just return 0 to be used for the disconnect event.
|
||||
if (!LocalClient.IsServer && !TransportIdToClientIdMap.ContainsKey(transportId))
|
||||
{
|
||||
return 0;
|
||||
return NetworkManager.LocalClientId;
|
||||
}
|
||||
|
||||
var clientId = TransportIdToClientId(transportId);
|
||||
@@ -346,31 +476,38 @@ namespace Unity.Netcode
|
||||
s_TransportDisconnect.Begin();
|
||||
#endif
|
||||
var clientId = TransportIdCleanUp(transportClientId);
|
||||
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
|
||||
{
|
||||
NetworkLog.LogInfo($"Disconnect Event From {clientId}");
|
||||
}
|
||||
|
||||
// If we are a client and we have gotten the ServerClientId back, then use our assigned local id as the client that was
|
||||
// disconnected (either the user disconnected or the server disconnected, but the client that disconnected is the LocalClientId)
|
||||
if (!NetworkManager.IsServer && clientId == NetworkManager.ServerClientId)
|
||||
{
|
||||
clientId = NetworkManager.LocalClientId;
|
||||
}
|
||||
|
||||
// Process the incoming message queue so that we get everything from the server disconnecting us or, if we are the server, so we got everything from that client.
|
||||
MessageManager.ProcessIncomingMessageQueue();
|
||||
|
||||
try
|
||||
InvokeOnClientDisconnectCallback(clientId);
|
||||
|
||||
if (LocalClient.IsHost)
|
||||
{
|
||||
OnClientDisconnectCallback?.Invoke(clientId);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
InvokeOnPeerDisconnectedCallback(clientId);
|
||||
}
|
||||
|
||||
if (LocalClient.IsServer)
|
||||
{
|
||||
OnClientDisconnectFromServer(clientId);
|
||||
}
|
||||
else
|
||||
else // As long as we are not in the middle of a shutdown
|
||||
if (!NetworkManager.ShutdownInProgress)
|
||||
{
|
||||
// We must pass true here and not process any sends messages as we are no longer connected and thus there is no one to send any messages to and this will cause an exception within UnityTransport as the client ID is no longer valid.
|
||||
// We must pass true here and not process any sends messages as we are no longer connected.
|
||||
// Otherwise, attempting to process messages here can cause an exception within UnityTransport
|
||||
// as the client ID is no longer valid.
|
||||
NetworkManager.Shutdown(true);
|
||||
}
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
@@ -623,8 +760,17 @@ namespace Unity.Netcode
|
||||
var message = new ConnectionApprovedMessage
|
||||
{
|
||||
OwnerClientId = ownerClientId,
|
||||
NetworkTick = NetworkManager.LocalTime.Tick
|
||||
NetworkTick = NetworkManager.LocalTime.Tick,
|
||||
ConnectedClientIds = new NativeArray<ulong>(ConnectedClientIds.Count, Allocator.Temp)
|
||||
};
|
||||
|
||||
var i = 0;
|
||||
foreach (var clientId in ConnectedClientIds)
|
||||
{
|
||||
message.ConnectedClientIds[i] = clientId;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (!NetworkManager.NetworkConfig.EnableSceneManagement)
|
||||
{
|
||||
// Update the observed spawned NetworkObjects for the newly connected player when scene management is disabled
|
||||
@@ -651,12 +797,17 @@ namespace Unity.Netcode
|
||||
|
||||
SendMessage(ref message, NetworkDelivery.ReliableFragmentedSequenced, ownerClientId);
|
||||
message.MessageVersions.Dispose();
|
||||
message.ConnectedClientIds.Dispose();
|
||||
|
||||
// If scene management is disabled, then we are done and notify the local host-server the client is connected
|
||||
if (!NetworkManager.NetworkConfig.EnableSceneManagement)
|
||||
{
|
||||
NetworkManager.ConnectedClients[ownerClientId].IsConnected = true;
|
||||
InvokeOnClientConnectedCallback(ownerClientId);
|
||||
if (LocalClient.IsHost)
|
||||
{
|
||||
InvokeOnPeerConnectedCallback(ownerClientId);
|
||||
}
|
||||
}
|
||||
else // Otherwise, let NetworkSceneManager handle the initial scene and NetworkObject synchronization
|
||||
{
|
||||
@@ -740,6 +891,8 @@ namespace Unity.Netcode
|
||||
|
||||
ConnectedClients.Add(clientId, networkClient);
|
||||
ConnectedClientsList.Add(networkClient);
|
||||
var message = new ClientConnectedMessage { ClientId = clientId };
|
||||
NetworkManager.MessageManager.SendMessage(ref message, NetworkDelivery.ReliableFragmentedSequenced, ConnectedClientIds);
|
||||
ConnectedClientIds.Add(clientId);
|
||||
return networkClient;
|
||||
}
|
||||
@@ -757,6 +910,7 @@ namespace Unity.Netcode
|
||||
|
||||
// If we are shutting down and this is the server or host disconnecting, then ignore
|
||||
// clean up as everything that needs to be destroyed will be during shutdown.
|
||||
|
||||
if (NetworkManager.ShutdownInProgress && clientId == NetworkManager.ServerClientId)
|
||||
{
|
||||
return;
|
||||
@@ -780,7 +934,7 @@ namespace Unity.Netcode
|
||||
NetworkManager.SpawnManager.DespawnObject(playerObject, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (!NetworkManager.ShutdownInProgress)
|
||||
{
|
||||
playerObject.RemoveOwnership();
|
||||
}
|
||||
@@ -799,7 +953,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle changing ownership and prefab handlers
|
||||
// Handle changing ownership and prefab handlers
|
||||
for (int i = clientOwnedObjects.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var ownedObject = clientOwnedObjects[i];
|
||||
@@ -816,7 +970,7 @@ namespace Unity.Netcode
|
||||
Object.Destroy(ownedObject.gameObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (!NetworkManager.ShutdownInProgress)
|
||||
{
|
||||
ownedObject.RemoveOwnership();
|
||||
}
|
||||
@@ -837,6 +991,8 @@ namespace Unity.Netcode
|
||||
}
|
||||
|
||||
ConnectedClientIds.Remove(clientId);
|
||||
var message = new ClientDisconnectedMessage { ClientId = clientId };
|
||||
MessageManager?.SendMessage(ref message, NetworkDelivery.ReliableFragmentedSequenced, ConnectedClientIds);
|
||||
}
|
||||
|
||||
// If the client ID transport map exists
|
||||
@@ -845,13 +1001,11 @@ namespace Unity.Netcode
|
||||
var transportId = ClientIdToTransportId(clientId);
|
||||
NetworkManager.NetworkConfig.NetworkTransport.DisconnectRemoteClient(transportId);
|
||||
|
||||
try
|
||||
InvokeOnClientDisconnectCallback(clientId);
|
||||
|
||||
if (LocalClient.IsHost)
|
||||
{
|
||||
OnClientDisconnectCallback?.Invoke(clientId);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
InvokeOnPeerDisconnectedCallback(clientId);
|
||||
}
|
||||
|
||||
// Clean up the transport to client (and vice versa) mappings
|
||||
@@ -889,6 +1043,12 @@ namespace Unity.Netcode
|
||||
throw new NotServerException($"Only server can disconnect remote clients. Please use `{nameof(Shutdown)}()` instead.");
|
||||
}
|
||||
|
||||
if (clientId == NetworkManager.ServerClientId)
|
||||
{
|
||||
Debug.LogWarning($"Disconnecting the local server-host client is not allowed. Use NetworkManager.Shutdown instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(reason))
|
||||
{
|
||||
var disconnectReason = new DisconnectReasonMessage
|
||||
@@ -933,13 +1093,8 @@ namespace Unity.Netcode
|
||||
/// </summary>
|
||||
internal void Shutdown()
|
||||
{
|
||||
LocalClient.IsApproved = false;
|
||||
LocalClient.IsConnected = false;
|
||||
if (LocalClient.IsServer)
|
||||
{
|
||||
// make sure all messages are flushed before transport disconnect clients
|
||||
MessageManager?.ProcessSendQueues();
|
||||
|
||||
// Build a list of all client ids to be disconnected
|
||||
var disconnectedIds = new HashSet<ulong>();
|
||||
|
||||
@@ -975,9 +1130,15 @@ namespace Unity.Netcode
|
||||
{
|
||||
DisconnectRemoteClient(clientId);
|
||||
}
|
||||
|
||||
// make sure all messages are flushed before transport disconnects clients
|
||||
MessageManager?.ProcessSendQueues();
|
||||
}
|
||||
else if (NetworkManager != null && NetworkManager.IsListening && LocalClient.IsClient)
|
||||
{
|
||||
// make sure all messages are flushed before disconnecting
|
||||
MessageManager?.ProcessSendQueues();
|
||||
|
||||
// Client only, send disconnect and if transport throws and exception, log the exception and continue the shutdown sequence (or forever be shutting down)
|
||||
try
|
||||
{
|
||||
@@ -989,6 +1150,12 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
LocalClient.IsApproved = false;
|
||||
LocalClient.IsConnected = false;
|
||||
ConnectedClients.Clear();
|
||||
ConnectedClientIds.Clear();
|
||||
ConnectedClientsList.Clear();
|
||||
|
||||
if (NetworkManager != null && NetworkManager.NetworkConfig?.NetworkTransport != null)
|
||||
{
|
||||
NetworkManager.NetworkConfig.NetworkTransport.OnTransportEvent -= HandleNetworkEvent;
|
||||
|
||||
Reference in New Issue
Block a user