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:
@@ -314,18 +314,18 @@ namespace Unity.Netcode
|
||||
/// <summary>
|
||||
/// Gets if we are executing as server
|
||||
/// </summary>
|
||||
protected bool IsServer { get; private set; }
|
||||
public bool IsServer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets if we are executing as client
|
||||
/// </summary>
|
||||
protected bool IsClient { get; private set; }
|
||||
public bool IsClient { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets if we are executing as Host, I.E Server and Client
|
||||
/// </summary>
|
||||
protected bool IsHost { get; private set; }
|
||||
public bool IsHost { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets Whether or not the object has a owner
|
||||
@@ -570,11 +570,11 @@ namespace Unity.Netcode
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<FieldInfo>();
|
||||
list.AddRange(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance));
|
||||
list.AddRange(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.AddRange(type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance));
|
||||
list.AddRange(type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
|
||||
}
|
||||
|
||||
if (type.BaseType != null && type.BaseType != typeof(NetworkBehaviour))
|
||||
|
||||
@@ -72,6 +72,23 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dirtyObj in m_DirtyNetworkObjects)
|
||||
{
|
||||
for (int k = 0; k < dirtyObj.ChildNetworkBehaviours.Count; k++)
|
||||
{
|
||||
var behaviour = dirtyObj.ChildNetworkBehaviours[k];
|
||||
for (int i = 0; i < behaviour.NetworkVariableFields.Count; i++)
|
||||
{
|
||||
if (behaviour.NetworkVariableFields[i].IsDirty() &&
|
||||
!behaviour.NetworkVariableIndexesToResetSet.Contains(i))
|
||||
{
|
||||
behaviour.NetworkVariableIndexesToResetSet.Add(i);
|
||||
behaviour.NetworkVariableIndexesToReset.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now, reset all the no-longer-dirty variables
|
||||
foreach (var dirtyobj in m_DirtyNetworkObjects)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,9 +265,8 @@ namespace Unity.Netcode
|
||||
throw new VisibilityChangeException("The object is already visible");
|
||||
}
|
||||
|
||||
NetworkManager.MarkObjectForShowingTo(this, clientId);
|
||||
Observers.Add(clientId);
|
||||
|
||||
NetworkManager.SpawnManager.SendSpawnCallForObject(clientId, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -351,26 +350,28 @@ namespace Unity.Netcode
|
||||
throw new NotServerException("Only server can change visibility");
|
||||
}
|
||||
|
||||
if (!Observers.Contains(clientId))
|
||||
{
|
||||
throw new VisibilityChangeException("The object is already hidden");
|
||||
}
|
||||
|
||||
if (clientId == NetworkManager.ServerClientId)
|
||||
{
|
||||
throw new VisibilityChangeException("Cannot hide an object from the server");
|
||||
}
|
||||
|
||||
Observers.Remove(clientId);
|
||||
|
||||
var message = new DestroyObjectMessage
|
||||
if (!NetworkManager.RemoveObjectFromShowingTo(this, clientId))
|
||||
{
|
||||
NetworkObjectId = NetworkObjectId,
|
||||
DestroyGameObject = !IsSceneObject.Value
|
||||
};
|
||||
// Send destroy call
|
||||
var size = NetworkManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientId);
|
||||
NetworkManager.NetworkMetrics.TrackObjectDestroySent(clientId, this, size);
|
||||
if (!Observers.Contains(clientId))
|
||||
{
|
||||
throw new VisibilityChangeException("The object is already hidden");
|
||||
}
|
||||
Observers.Remove(clientId);
|
||||
|
||||
var message = new DestroyObjectMessage
|
||||
{
|
||||
NetworkObjectId = NetworkObjectId,
|
||||
DestroyGameObject = !IsSceneObject.Value
|
||||
};
|
||||
// Send destroy call
|
||||
var size = NetworkManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, clientId);
|
||||
NetworkManager.NetworkMetrics.TrackObjectDestroySent(clientId, this, size);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1454,9 +1455,9 @@ namespace Unity.Netcode
|
||||
var globalObjectIdHash = NetworkManager.PrefabHandler.GetSourceGlobalObjectIdHash(GlobalObjectIdHash);
|
||||
return globalObjectIdHash == 0 ? GlobalObjectIdHash : globalObjectIdHash;
|
||||
}
|
||||
else if (NetworkManager.NetworkConfig.OverrideToNetworkPrefab.ContainsKey(GlobalObjectIdHash))
|
||||
if (NetworkManager.NetworkConfig.Prefabs.OverrideToNetworkPrefab.TryGetValue(GlobalObjectIdHash, out uint hash))
|
||||
{
|
||||
return NetworkManager.NetworkConfig.OverrideToNetworkPrefab[GlobalObjectIdHash];
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user