com.unity.netcode.gameobjects@1.3.1

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.3.1] - 2023-03-27

### Added

- Added detection and graceful handling of corrupt packets for additional safety. (#2419)

### Changed

- The UTP component UI has been updated to be more user-friendly for new users by adding a simple toggle to switch between local-only (127.0.0.1) and remote (0.0.0.0) binding modes, using the toggle "Allow Remote Connections" (#2408)
- Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.3. (#2450)
- `NetworkShow()` of `NetworkObject`s are delayed until the end of the frame to ensure consistency of delta-driven variables like `NetworkList`.
- Dirty `NetworkObject` are reset at end-of-frame and not at serialization time.
- `NetworkHide()` of an object that was just `NetworkShow()`n produces a warning, as remote clients will _not_ get a spawn/despawn pair.
- Renamed the NetworkTransform.SetState parameter `shouldGhostsInterpolate` to `teleportDisabled` for better clarity of what that parameter does. (#2228)
- Network prefabs are now stored in a ScriptableObject that can be shared between NetworkManagers, and have been exposed for public access. By default, a Default Prefabs List is created that contains all NetworkObject prefabs in the project, and new NetworkManagers will default to using that unless that option is turned off in the Netcode for GameObjects settings. Existing NetworkManagers will maintain their existing lists, which can be migrated to the new format via a button in their inspector. (#2322)

### Fixed

- Fixed issue where changes to a layer's weight would not synchronize unless a state transition was occurring.(#2399)
- Fixed issue where `NetworkManager.LocalClientId` was returning the `NetworkTransport.ServerClientId` as opposed to the `NetworkManager.m_LocalClientId`. (#2398)
- Fixed issue where a dynamically spawned `NetworkObject` parented under an in-scene placed `NetworkObject` would have its `InScenePlaced` value changed to `true`. This would result in a soft synchronization error for late joining clients. (#2396)
- Fixed a UTP test that was failing when you install Unity Transport package 2.0.0 or newer. (#2347)
- Fixed issue where `NetcodeSettingsProvider` would throw an exception in Unity 2020.3.x versions. (#2345)
- Fixed server side issue where, depending upon component ordering, some NetworkBehaviour components might not have their OnNetworkDespawn method invoked if the client side disconnected. (#2323)
- Fixed a case where data corruption could occur when using UnityTransport when reaching a certain level of send throughput. (#2332)
- Fixed an issue in `UnityTransport` where an exception would be thrown if starting a Relay host/server on WebGL. This exception should only be thrown if using direct connections (where WebGL can't act as a host/server). (#2321)
- Fixed `NetworkAnimator` issue where it was not checking for `AnimatorStateTtansition.destinationStateMachine` and any possible sub-states defined within it. (#2309)
- Fixed `NetworkAnimator` issue where the host client was receiving the ClientRpc animation updates when the host was the owner.(#2309)
- Fixed `NetworkAnimator` issue with using pooled objects and when specific properties are cleaned during despawn and destroy.(#2309)
- Fixed issue where `NetworkAnimator` was checking for animation changes when the associated `NetworkObject` was not spawned.(#2309)
- Corrected an issue with the documentation for BufferSerializer (#2401)
This commit is contained in:
Unity Technologies
2023-03-27 00:00:00 +00:00
parent fe02ca682e
commit 8060718e04
69 changed files with 3128 additions and 888 deletions

View File

@@ -67,6 +67,9 @@ namespace Unity.Netcode
internal Dictionary<ulong, ConnectionApprovalResponse> ClientsToApprove = new Dictionary<ulong, ConnectionApprovalResponse>();
// Stores the objects that need to be shown at end-of-frame
internal Dictionary<ulong, List<NetworkObject>> ObjectsToShowToClient = new Dictionary<ulong, List<NetworkObject>>();
/// <summary>
/// The <see cref="NetworkPrefabHandler"/> instance created after starting the <see cref="NetworkManager"/>
/// </summary>
@@ -140,15 +143,55 @@ namespace Unity.Netcode
public bool OnVerifyCanReceive(ulong senderId, Type messageType, FastBufferReader messageContent, ref NetworkContext context)
{
if (m_NetworkManager.PendingClients.TryGetValue(senderId, out PendingClient client) &&
(client.ConnectionState == PendingClient.State.PendingApproval || (client.ConnectionState == PendingClient.State.PendingConnection && messageType != typeof(ConnectionRequestMessage))))
if (m_NetworkManager.IsServer)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
if (messageType == typeof(ConnectionApprovedMessage))
{
NetworkLog.LogWarning($"Message received from {nameof(senderId)}={senderId} before it has been accepted");
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionApprovedMessage)} was received from a client on the server side. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {MessagingSystem.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
if (m_NetworkManager.PendingClients.TryGetValue(senderId, out PendingClient client) &&
(client.ConnectionState == PendingClient.State.PendingApproval || (client.ConnectionState == PendingClient.State.PendingConnection && messageType != typeof(ConnectionRequestMessage))))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogWarning($"Message received from {nameof(senderId)}={senderId} before it has been accepted");
}
return false;
}
return false;
if (m_NetworkManager.ConnectedClients.TryGetValue(senderId, out NetworkClient connectedClient) && messageType == typeof(ConnectionRequestMessage))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionRequestMessage)} was received from a client when the connection has already been established. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {MessagingSystem.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
}
else
{
if (messageType == typeof(ConnectionRequestMessage))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionRequestMessage)} was received from the server on the client side. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {MessagingSystem.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
if (m_NetworkManager.IsConnectedClient && messageType == typeof(ConnectionApprovedMessage))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"A {nameof(ConnectionApprovedMessage)} was received from the server when the connection has already been established. This should not happen. Please report this to the Netcode for GameObjects team at https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues and include the following data: Message Size: {messageContent.Length}. Message Content: {MessagingSystem.ByteArrayToString(messageContent.ToArray(), 0, messageContent.Length)}");
}
return false;
}
}
return !m_NetworkManager.m_StopProcessingMessages;
@@ -195,14 +238,14 @@ namespace Unity.Netcode
{
if (gameObject.TryGetComponent<NetworkObject>(out var networkObject))
{
if (NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(networkObject.GlobalObjectIdHash))
if (NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.ContainsKey(networkObject.GlobalObjectIdHash))
{
switch (NetworkConfig.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].Override)
switch (NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].Override)
{
case NetworkPrefabOverride.Hash:
case NetworkPrefabOverride.Prefab:
{
return NetworkConfig.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].OverridingTargetPrefab;
return NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].OverridingTargetPrefab;
}
}
}
@@ -280,7 +323,7 @@ namespace Unity.Netcode
/// </summary>
public ulong LocalClientId
{
get => IsServer ? NetworkConfig.NetworkTransport.ServerClientId : m_LocalClientId;
get => m_LocalClientId;
internal set => m_LocalClientId = value;
}
@@ -508,6 +551,19 @@ namespace Unity.Netcode
internal static event Action OnSingletonReady;
#if UNITY_EDITOR
internal delegate void ResetNetworkManagerDelegate(NetworkManager manager);
internal static ResetNetworkManagerDelegate OnNetworkManagerReset;
#endif
private void Reset()
{
#if UNITY_EDITOR
OnNetworkManagerReset?.Invoke(this);
#endif
}
#if UNITY_EDITOR
internal void OnValidate()
{
@@ -533,72 +589,38 @@ namespace Unity.Netcode
}
// During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it
NetworkConfig.NetworkPrefabOverrideLinks.Clear();
NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.Clear();
var prefabs = NetworkConfig.Prefabs.Prefabs;
// Check network prefabs and assign to dictionary for quick look up
for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++)
for (int i = 0; i < prefabs.Count; i++)
{
var networkPrefab = NetworkConfig.NetworkPrefabs[i];
var networkPrefab = prefabs[i];
var networkPrefabGo = networkPrefab?.Prefab;
if (networkPrefabGo != null)
if (networkPrefabGo == null)
{
if (!networkPrefabGo.TryGetComponent<NetworkObject>(out var networkObject))
continue;
}
var networkObject = networkPrefabGo.GetComponent<NetworkObject>();
if (networkObject == null)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"Cannot register {PrefabDebugHelper(networkPrefab)}, it does not have a {nameof(NetworkObject)} component at its root");
}
continue;
}
{
var childNetworkObjects = new List<NetworkObject>();
networkPrefabGo.GetComponentsInChildren(true, childNetworkObjects);
if (childNetworkObjects.Count > 1) // total count = 1 root NetworkObject + n child NetworkObjects
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogError($"Cannot register {PrefabDebugHelper(networkPrefab)}, it does not have a {nameof(NetworkObject)} component at its root");
}
}
else
{
{
var childNetworkObjects = new List<NetworkObject>();
networkPrefabGo.GetComponentsInChildren(true, childNetworkObjects);
if (childNetworkObjects.Count > 1) // total count = 1 root NetworkObject + n child NetworkObjects
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogWarning($"{PrefabDebugHelper(networkPrefab)} has child {nameof(NetworkObject)}(s) but they will not be spawned across the network (unsupported {nameof(NetworkPrefab)} setup)");
}
}
}
// Default to the standard NetworkPrefab.Prefab's NetworkObject first
var globalObjectIdHash = networkObject.GlobalObjectIdHash;
// Now check to see if it has an override
switch (networkPrefab.Override)
{
case NetworkPrefabOverride.Prefab:
{
if (NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride == null &&
NetworkConfig.NetworkPrefabs[i].Prefab != null)
{
if (networkPrefab.SourcePrefabToOverride == null)
{
networkPrefab.SourcePrefabToOverride = networkPrefabGo;
}
globalObjectIdHash = networkPrefab.SourcePrefabToOverride.GetComponent<NetworkObject>().GlobalObjectIdHash;
}
break;
}
case NetworkPrefabOverride.Hash:
globalObjectIdHash = networkPrefab.SourceHashToOverride;
break;
}
// Add to the NetworkPrefabOverrideLinks or handle a new (blank) entries
if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(globalObjectIdHash))
{
NetworkConfig.NetworkPrefabOverrideLinks.Add(globalObjectIdHash, networkPrefab);
}
else
{
// Duplicate entries can happen when adding a new entry into a list of existing entries
// Either this is user error or a new entry, either case we replace it with a new, blank, NetworkPrefab under this condition
NetworkConfig.NetworkPrefabs[i] = new NetworkPrefab();
NetworkLog.LogWarning($"{PrefabDebugHelper(networkPrefab)} has child {nameof(NetworkObject)}(s) but they will not be spawned across the network (unsupported {nameof(NetworkPrefab)} setup)");
}
}
}
@@ -640,22 +662,9 @@ namespace Unity.Netcode
}
var networkPrefab = new NetworkPrefab { Prefab = prefab };
NetworkConfig.NetworkPrefabs.Add(networkPrefab);
if (IsListening)
bool added = NetworkConfig.Prefabs.Add(networkPrefab);
if (IsListening && added)
{
var sourcePrefabGlobalObjectIdHash = (uint)0;
var targetPrefabGlobalObjectIdHash = (uint)0;
if (!ShouldAddPrefab(networkPrefab, out sourcePrefabGlobalObjectIdHash, out targetPrefabGlobalObjectIdHash))
{
NetworkConfig.NetworkPrefabs.Remove(networkPrefab);
return;
}
if (!AddPrefabRegistration(networkPrefab, sourcePrefabGlobalObjectIdHash, targetPrefabGlobalObjectIdHash))
{
NetworkConfig.NetworkPrefabs.Remove(networkPrefab);
return;
}
DeferredMessageManager.ProcessTriggers(IDeferredMessageManager.TriggerType.OnAddPrefab, networkObject.GlobalObjectIdHash);
}
}
@@ -678,221 +687,14 @@ namespace Unity.Netcode
}
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;
}
}
NetworkConfig.Prefabs.Remove(prefab);
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;
targetPrefabGlobalObjectIdHash = 0;
var networkObject = (NetworkObject)null;
if (networkPrefab == null || (networkPrefab.Prefab == null && networkPrefab.Override == NetworkPrefabOverride.None))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
{
NetworkLog.LogWarning(
$"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {index})");
}
return false;
}
else if (networkPrefab.Override == NetworkPrefabOverride.None)
{
if (!networkPrefab.Prefab.TryGetComponent(out networkObject))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
{
NetworkLog.LogWarning($"{PrefabDebugHelper(networkPrefab)} is missing " +
$"a {nameof(NetworkObject)} component (entry will be ignored).");
}
return false;
}
// Otherwise get the GlobalObjectIdHash value
sourcePrefabGlobalObjectIdHash = networkObject.GlobalObjectIdHash;
}
else // Validate Overrides
{
// Validate source prefab override values first
switch (networkPrefab.Override)
{
case NetworkPrefabOverride.Hash:
{
if (networkPrefab.SourceHashToOverride == 0)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
{
NetworkLog.LogWarning($"{nameof(NetworkPrefab)} {nameof(NetworkPrefab.SourceHashToOverride)} is zero " +
"(entry will be ignored).");
}
return false;
}
sourcePrefabGlobalObjectIdHash = networkPrefab.SourceHashToOverride;
break;
}
case NetworkPrefabOverride.Prefab:
{
if (networkPrefab.SourcePrefabToOverride == null)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
{
NetworkLog.LogWarning($"{nameof(NetworkPrefab)} {nameof(NetworkPrefab.SourcePrefabToOverride)} is null (entry will be ignored).");
}
Debug.LogWarning($"{nameof(NetworkPrefab)} override entry {networkPrefab.SourceHashToOverride} will be removed and ignored.");
return false;
}
else
{
if (!networkPrefab.SourcePrefabToOverride.TryGetComponent(out networkObject))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
{
NetworkLog.LogWarning($"{nameof(NetworkPrefab)} ({networkPrefab.SourcePrefabToOverride.name}) " +
$"is missing a {nameof(NetworkObject)} component (entry will be ignored).");
}
Debug.LogWarning($"{nameof(NetworkPrefab)} override entry (\"{networkPrefab.SourcePrefabToOverride.name}\") will be removed and ignored.");
return false;
}
sourcePrefabGlobalObjectIdHash = networkObject.GlobalObjectIdHash;
}
break;
}
}
// Validate target prefab override values next
if (networkPrefab.OverridingTargetPrefab == null)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
{
NetworkLog.LogWarning($"{nameof(NetworkPrefab)} {nameof(NetworkPrefab.OverridingTargetPrefab)} is null!");
}
switch (networkPrefab.Override)
{
case NetworkPrefabOverride.Hash:
{
Debug.LogWarning($"{nameof(NetworkPrefab)} override entry {networkPrefab.SourceHashToOverride} will be removed and ignored.");
break;
}
case NetworkPrefabOverride.Prefab:
{
Debug.LogWarning($"{nameof(NetworkPrefab)} override entry ({networkPrefab.SourcePrefabToOverride.name}) will be removed and ignored.");
break;
}
}
return false;
}
else
{
targetPrefabGlobalObjectIdHash = networkPrefab.OverridingTargetPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash;
}
}
return true;
}
internal bool AddPrefabRegistration(NetworkPrefab networkPrefab, uint sourcePrefabGlobalObjectIdHash, uint targetPrefabGlobalObjectIdHash)
{
// Assign the appropriate GlobalObjectIdHash to the appropriate NetworkPrefab
if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(sourcePrefabGlobalObjectIdHash))
{
if (networkPrefab.Override == NetworkPrefabOverride.None)
{
NetworkConfig.NetworkPrefabOverrideLinks.Add(sourcePrefabGlobalObjectIdHash, networkPrefab);
}
else
{
if (!NetworkConfig.OverrideToNetworkPrefab.ContainsKey(targetPrefabGlobalObjectIdHash))
{
switch (networkPrefab.Override)
{
case NetworkPrefabOverride.Prefab:
{
NetworkConfig.NetworkPrefabOverrideLinks.Add(sourcePrefabGlobalObjectIdHash, networkPrefab);
NetworkConfig.OverrideToNetworkPrefab.Add(targetPrefabGlobalObjectIdHash, sourcePrefabGlobalObjectIdHash);
}
break;
case NetworkPrefabOverride.Hash:
{
NetworkConfig.NetworkPrefabOverrideLinks.Add(sourcePrefabGlobalObjectIdHash, networkPrefab);
NetworkConfig.OverrideToNetworkPrefab.Add(targetPrefabGlobalObjectIdHash, sourcePrefabGlobalObjectIdHash);
}
break;
}
}
else
{
var networkObject = networkPrefab.Prefab.GetComponent<NetworkObject>();
// This can happen if a user tries to make several GlobalObjectIdHash values point to the same target
Debug.LogError($"{nameof(NetworkPrefab)} (\"{networkObject.name}\") has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} target entry value of: {targetPrefabGlobalObjectIdHash}! Removing entry from list!");
return false;
}
}
}
else
{
var networkObject = networkPrefab.Prefab.GetComponent<NetworkObject>();
// This should never happen, but in the case it somehow does log an error and remove the duplicate entry
Debug.LogError($"{nameof(NetworkPrefab)} ({networkObject.name}) has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} source entry value of: {sourcePrefabGlobalObjectIdHash}! Removing entry from list!");
return false;
}
return true;
}
private void InitializePrefabs(int startIdx = 0)
{
// This is used to remove entries not needed or invalid
var removeEmptyPrefabs = new List<int>();
// Build the NetworkPrefabOverrideLinks dictionary
for (int i = startIdx; i < NetworkConfig.NetworkPrefabs.Count; i++)
{
var sourcePrefabGlobalObjectIdHash = (uint)0;
var targetPrefabGlobalObjectIdHash = (uint)0;
if (!ShouldAddPrefab(NetworkConfig.NetworkPrefabs[i], out sourcePrefabGlobalObjectIdHash, out targetPrefabGlobalObjectIdHash, i))
{
removeEmptyPrefabs.Add(i);
continue;
}
if (!AddPrefabRegistration(NetworkConfig.NetworkPrefabs[i], sourcePrefabGlobalObjectIdHash, targetPrefabGlobalObjectIdHash))
{
removeEmptyPrefabs.Add(i);
continue;
}
}
// Clear out anything that is invalid or not used (for invalid entries we already logged warnings to the user earlier)
// Iterate backwards so indices don't shift as we remove
for (int i = removeEmptyPrefabs.Count - 1; i >= 0; i--)
{
NetworkConfig.NetworkPrefabs.RemoveAt(removeEmptyPrefabs[i]);
}
removeEmptyPrefabs.Clear();
}
private void Initialize(bool server)
internal void Initialize(bool server)
{
// Don't allow the user to start a network session if the NetworkManager is
// still parented under another GameObject
@@ -982,11 +784,7 @@ namespace Unity.Netcode
this.RegisterNetworkUpdate(NetworkUpdateStage.PreUpdate);
// Always clear our prefab override links before building
NetworkConfig.NetworkPrefabOverrideLinks.Clear();
NetworkConfig.OverrideToNetworkPrefab.Clear();
InitializePrefabs();
NetworkConfig.InitializePrefabs();
// If we have a player prefab, then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning.
if (NetworkConfig.PlayerPrefab != null)
@@ -994,15 +792,11 @@ namespace Unity.Netcode
if (NetworkConfig.PlayerPrefab.TryGetComponent<NetworkObject>(out var playerPrefabNetworkObject))
{
//In the event there is no NetworkPrefab entry (i.e. no override for default player prefab)
if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(playerPrefabNetworkObject
if (!NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.ContainsKey(playerPrefabNetworkObject
.GlobalObjectIdHash))
{
//Then add a new entry for the player prefab
var playerNetworkPrefab = new NetworkPrefab();
playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab;
NetworkConfig.NetworkPrefabs.Insert(0, playerNetworkPrefab);
NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash,
playerNetworkPrefab);
AddNetworkPrefab(NetworkConfig.PlayerPrefab);
}
}
else
@@ -1048,6 +842,7 @@ namespace Unity.Netcode
IsServer = true;
IsClient = false;
IsListening = true;
LocalClientId = ServerClientId;
try
{
@@ -1282,6 +1077,8 @@ namespace Unity.Netcode
private void Awake()
{
NetworkConfig?.InitializePrefabs();
UnityEngine.SceneManagement.SceneManager.sceneUnloaded += OnSceneUnloaded;
}
@@ -1663,6 +1460,17 @@ namespace Unity.Netcode
// Do NetworkVariable updates
BehaviourUpdater.NetworkBehaviourUpdate(this);
// Handle NetworkObjects to show
foreach (var client in ObjectsToShowToClient)
{
ulong clientId = client.Key;
foreach (var networkObject in client.Value)
{
SpawnManager.SendSpawnCallForObject(clientId, networkObject);
}
}
ObjectsToShowToClient.Clear();
int timeSyncFrequencyTicks = (int)(k_TimeSyncFrequency * NetworkConfig.TickRate);
if (IsServer && NetworkTickSystem.ServerTime.Tick % timeSyncFrequencyTicks == 0)
{
@@ -2082,7 +1890,12 @@ namespace Unity.Netcode
}
else
{
Destroy(playerObject.gameObject);
// Call despawn to assure NetworkBehaviour.OnNetworkDespawn is invoked
// on the server-side (when the client side disconnected).
// This prevents the issue (when just destroying the GameObject) where
// any NetworkBehaviour component(s) destroyed before the NetworkObject
// would not have OnNetworkDespawn invoked.
SpawnManager.DespawnObject(playerObject, true);
}
}
else
@@ -2334,5 +2147,37 @@ namespace Unity.Netcode
NetworkMetrics.TrackObjectSpawnSent(clientPair.Key, ConnectedClients[clientId].PlayerObject, size);
}
}
internal void MarkObjectForShowingTo(NetworkObject networkObject, ulong clientId)
{
if (!ObjectsToShowToClient.ContainsKey(clientId))
{
ObjectsToShowToClient.Add(clientId, new List<NetworkObject>());
}
ObjectsToShowToClient[clientId].Add(networkObject);
}
// returns whether any matching objects would have become visible and were returned to hidden state
internal bool RemoveObjectFromShowingTo(NetworkObject networkObject, ulong clientId)
{
var ret = false;
if (!ObjectsToShowToClient.ContainsKey(clientId))
{
return false;
}
// probably overkill, but deals with multiple entries
while (ObjectsToShowToClient[clientId].Contains(networkObject))
{
Debug.LogWarning(
"Object was shown and hidden from the same client in the same Network frame. As a result, the client will _not_ receive a NetworkSpawn");
ObjectsToShowToClient[clientId].Remove(networkObject);
ret = true;
}
networkObject.Observers.Remove(clientId);
return ret;
}
}
}