diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/ComponentController.cs b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/ComponentController.cs
index d3d6e678b9..710c7be745 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/ComponentController.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/ComponentController.cs
@@ -396,17 +396,21 @@ protected override void OnNetworkPostSpawn()
}
///
- ///
- /// If overriding this method, it is required that you invoke this base method.
- ///
+ // TODO: Not used anymore
public override void OnDestroy()
+ {
+ base.OnDestroy();
+ }
+
+
+ internal override void InternalOnDestroy()
{
if (m_CoroutineObject.IsRunning)
{
StopCoroutine(m_CoroutineObject.Coroutine);
m_CoroutineObject.IsRunning = false;
}
- base.OnDestroy();
+ base.InternalOnDestroy();
}
///
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs
index 3a41f7b3a9..e8653687b9 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs
@@ -75,7 +75,16 @@ public override bool Initialize(string defaultWorldName)
LastCreatedWorld = CreateLocalWorld("LocalWorld");
}
- OnInitialized?.Invoke();
+ // Always wrap events that can invoke user script in a try-catch to assure any
+ // proceeding script is still executed.
+ try
+ {
+ OnInitialized?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
return true;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs
index db3988b0fd..76bfc095cd 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs
@@ -54,7 +54,14 @@ protected override void OnUpdate()
foreach (var con in m_TempConnections)
{
- NetworkManager.OnNetCodeDisconnect?.Invoke(con);
+ try
+ {
+ NetworkManager.OnNetCodeDisconnect?.Invoke(con);
+ }
+ catch (System.Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
m_TempConnections.Clear();
@@ -83,7 +90,15 @@ protected override void OnUpdate()
// Set the connection in-game
commandBuffer.AddComponent(entry.Value.Entity);
commandBuffer.AddComponent(entry.Value.Entity, default(ConnectionState));
- NetworkManager.OnNetCodeConnect?.Invoke(entry.Value);
+
+ try
+ {
+ NetworkManager.OnNetCodeConnect?.Invoke(entry.Value);
+ }
+ catch (System.Exception ex)
+ {
+ Debug.LogException(ex);
+ }
m_TempConnections.Add(entry.Value);
}
}
@@ -104,8 +119,16 @@ protected override void OnUpdate()
foreach (var (networkId, entity) in SystemAPI.Query().WithEntityAccess())
{
commandBuffer.RemoveComponent(entity);
- NetworkManager.OnNetCodeDisconnect?.Invoke(new NetcodeConnection
- { World = World, Entity = entity, NetworkId = networkId.Value });
+
+ try
+ {
+ NetworkManager.OnNetCodeDisconnect?.Invoke(new NetcodeConnection
+ { World = World, Entity = entity, NetworkId = networkId.Value });
+ }
+ catch (System.Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
}
}
@@ -121,7 +144,15 @@ protected override void OnDestroy()
foreach (var (networkId, entity) in SystemAPI.Query().WithEntityAccess())
{
commandBuffer.RemoveComponent(entity);
- NetworkManager.OnNetCodeDisconnect?.Invoke(new NetcodeConnection { World = World, Entity = entity, NetworkId = networkId.Value });
+
+ try
+ {
+ NetworkManager.OnNetCodeDisconnect?.Invoke(new NetcodeConnection { World = World, Entity = entity, NetworkId = networkId.Value });
+ }
+ catch (System.Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
commandBuffer.Playback(EntityManager);
base.OnDestroy();
diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
index f614843cef..4c20edd258 100644
--- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
@@ -711,7 +711,15 @@ internal void TransportFailureEventHandler(bool duringStart = false)
var clientSeverOrHost = LocalClient.IsServer ? LocalClient.IsHost ? "Host" : "Server" : "Client";
var whenFailed = duringStart ? "start failure" : "failure";
NetworkLog.LogError($"{clientSeverOrHost} is shutting down due to network transport {whenFailed} of {NetworkManager.NetworkConfig.NetworkTransport.GetType().Name}!");
- OnTransportFailure?.Invoke();
+
+ try
+ {
+ OnTransportFailure?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
// If we had a transport failure when trying to start, reset the local client roles and directly invoke the internal shutdown.
if (duringStart)
@@ -854,12 +862,25 @@ internal void ApproveConnection(ref ConnectionRequestMessage connectionRequestMe
// Note: ToArray() also allocates. :(
var response = new NetworkManager.ConnectionApprovalResponse();
ClientsToApprove[context.SenderId] = response;
- ConnectionApprovalCallback?.Invoke(
- new NetworkManager.ConnectionApprovalRequest
- {
- Payload = connectionRequestMessage.ConnectionData,
- ClientNetworkId = context.SenderId
- }, response);
+ try
+ {
+ ConnectionApprovalCallback?.Invoke(
+ new NetworkManager.ConnectionApprovalRequest
+ {
+ Payload = connectionRequestMessage.ConnectionData,
+ ClientNetworkId = context.SenderId
+ }, response);
+ }
+ catch (Exception ex)
+ {
+ // A throwing approval handler would otherwise leave a Pending response stranded in
+ // ClientsToApprove, hanging the connecting client until it times out. Deny instead.
+ Debug.LogException(ex);
+ response.Approved = false;
+ response.Pending = false;
+ response.CreatePlayerObject = false;
+ response.Reason = "Connection approval handler threw an exception.";
+ }
}
///
@@ -1748,13 +1769,22 @@ internal void Shutdown()
{
//The Transport is set during initialization, thus it is possible for the Transport to be null
var transport = NetworkManager.NetworkConfig?.NetworkTransport;
- if (transport != null)
+ if (transport == null)
+ {
+ return;
+ }
+ // if the transport throws we need to ensure we finish the shutdown sequence.
+ try
{
transport.Shutdown();
- if (NetworkManager.LogLevel <= LogLevel.Developer)
- {
- NetworkLog.LogInfo($"{nameof(NetworkConnectionManager)}.{nameof(Shutdown)}() -> {nameof(IsListening)} && {nameof(NetworkManager.NetworkConfig.NetworkTransport)} != null -> {nameof(NetworkTransport)}.{nameof(NetworkTransport.Shutdown)}()");
- }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
+ if (NetworkManager.LogLevel <= LogLevel.Developer)
+ {
+ NetworkLog.LogInfo($"{nameof(NetworkConnectionManager)}.{nameof(Shutdown)}() -> {nameof(IsListening)} && {nameof(NetworkManager.NetworkConfig.NetworkTransport)} != null -> {nameof(NetworkTransport)}.{nameof(NetworkTransport.Shutdown)}()");
}
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs
index 5d1a04537b..8d79f0f6e4 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs
@@ -137,7 +137,14 @@ internal void __endSendServerRpc(ref FastBufferWriter bufferWriter, uint rpcMeth
MessageSize = 0
};
serverRpcMessage.ReadBuffer = tempBuffer;
- serverRpcMessage.Handle(ref context);
+ try
+ {
+ serverRpcMessage.Handle(ref context);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ }
rpcWriteSize = tempBuffer.Length;
}
else
@@ -267,7 +274,14 @@ internal void __endSendClientRpc(ref FastBufferWriter bufferWriter, uint rpcMeth
MessageSize = 0
};
clientRpcMessage.ReadBuffer = tempBuffer;
- clientRpcMessage.Handle(ref context);
+ try
+ {
+ clientRpcMessage.Handle(ref context);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ }
}
bufferWriter.Dispose();
@@ -640,8 +654,16 @@ protected internal virtual void OnIsDestroying()
///
internal void SetIsDestroying()
{
- // We intentionally invoke this before setting the IsDestroying flag.
- OnIsDestroying();
+ try
+ {
+ // We intentionally invoke this before setting the IsDestroying flag.
+ OnIsDestroying();
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ }
+ // Set outside of the try-catch: a throwing override must not leave this flag false.
IsDestroying = true;
}
@@ -931,7 +953,14 @@ internal void InternalOnGainedOwnership()
{
UpdateNetworkVariableOnOwnershipChanged();
}
- OnGainedOwnership();
+ try
+ {
+ OnGainedOwnership();
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ }
}
///
@@ -948,7 +977,14 @@ protected virtual void OnOwnershipChanged(ulong previous, ulong current)
internal void InternalOnOwnershipChanged(ulong previous, ulong current)
{
- OnOwnershipChanged(previous, current);
+ try
+ {
+ OnOwnershipChanged(previous, current);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ }
}
///
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
index 185d682f66..daa3292da9 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
@@ -252,7 +252,14 @@ internal void SetSessionOwner(ulong sessionOwner)
networkObject.InvokeSessionOwnerPromoted(isSessionOwner);
}
- OnSessionOwnerPromoted?.Invoke(sessionOwner);
+ try
+ {
+ OnSessionOwnerPromoted?.Invoke(sessionOwner);
+ }
+ catch (Exception ex)
+ {
+ Log.Exception(ex);
+ }
}
#if ENABLE_SESSIONOWNER_PROMOTION_NOTIFICATION
@@ -1103,7 +1110,14 @@ private void Awake()
EditorApplication.playModeStateChanged += ModeChanged;
#endif
// Notify we have instantiated a new instance of NetworkManager.
- OnInstantiated?.Invoke(this);
+ try
+ {
+ OnInstantiated?.Invoke(this);
+ }
+ catch (Exception ex)
+ {
+ Log.Exception(ex);
+ }
}
private void OnEnable()
@@ -1479,8 +1493,15 @@ internal bool InternalStartServer()
// Notify the server that everything should be synchronized/spawned at this time.
SpawnManager.NotifyNetworkObjectsSynchronized();
- OnServerStarted?.Invoke();
- OnStarted?.Invoke();
+ try
+ {
+ OnServerStarted?.Invoke();
+ OnStarted?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Log.Exception(ex);
+ }
ConnectionManager.LocalClient.IsApproved = true;
return true;
}
@@ -1555,8 +1576,15 @@ internal bool InternalStartClient()
}
else
{
- OnClientStarted?.Invoke();
- OnStarted?.Invoke();
+ try
+ {
+ OnClientStarted?.Invoke();
+ OnStarted?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Log.Exception(ex);
+ }
}
}
catch (Exception ex)
@@ -1677,9 +1705,16 @@ private void HostServerInitialize()
// Notify the host that everything should be synchronized/spawned at this time.
SpawnManager.NotifyNetworkObjectsSynchronized();
- OnServerStarted?.Invoke();
- OnClientStarted?.Invoke();
- OnStarted?.Invoke();
+ try
+ {
+ OnServerStarted?.Invoke();
+ OnClientStarted?.Invoke();
+ OnStarted?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Log.Exception(ex);
+ }
// This assures that any in-scene placed NetworkObject is spawned and
// any associated NetworkBehaviours' netcode related properties are
@@ -1874,21 +1909,28 @@ internal void ShutdownInternal()
NetworkTimeSystem?.Shutdown();
NetworkTickSystem = null;
- if (localClient.IsClient)
+
+ try
{
- // If we were a client, we want to know if we were a host
- // client or not. (why we pass in "IsServer")
- OnClientStopped?.Invoke(localClient.IsServer);
- }
+ if (localClient.IsClient)
+ {
+ // If we were a client, we want to know if we were a host
+ // client or not. (why we pass in "IsServer")
+ OnClientStopped?.Invoke(localClient.IsServer);
+ }
+ if (localClient.IsServer)
+ {
+ // If we were a server, we want to know if we were a host
+ // or not. (why we pass in "IsClient")
+ OnServerStopped?.Invoke(localClient.IsClient);
+ }
- if (localClient.IsServer)
+ OnStopped?.Invoke();
+ }
+ catch (Exception ex)
{
- // If we were a server, we want to know if we were a host
- // or not. (why we pass in "IsClient")
- OnServerStopped?.Invoke(localClient.IsClient);
+ Log.Exception(ex);
}
-
- OnStopped?.Invoke();
}
// Ensures that the NetworkManager is cleaned up before OnDestroy is run on NetworkObjects and NetworkBehaviours when quitting the application.
@@ -1914,9 +1956,17 @@ private void OnApplicationQuit()
#endif
}
+ private bool m_IsDestroyed = false;
+
// Note that this gets also called manually by OnSceneUnloaded and OnApplicationQuit
private void OnDestroy()
{
+ if (m_IsDestroyed)
+ {
+ return;
+ }
+ m_IsDestroyed = true;
+
try
{
ShutdownInternal();
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
index 0b39c84f6f..49a7088e56 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
@@ -523,7 +523,14 @@ public void DeferDespawn(int tickOffset, bool destroy = true)
// Notify all NetworkBehaviours that the authority is performing a deferred despawn.
// This is when user script would update NetworkVariable states that might be needed
// for the deferred despawn sequence on non-authoritative instances.
- behaviour.OnDeferringDespawn(DeferredDespawnTick);
+ try
+ {
+ behaviour.OnDeferringDespawn(DeferredDespawnTick);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
// DAHost handles sending updates to all clients
@@ -810,6 +817,19 @@ public enum OwnershipPermissionsFailureStatus
///
public OnOwnershipPermissionsFailureDelegateHandler OnOwnershipPermissionsFailure;
+
+ internal void InvokeOwnershipPermissionsFailure()
+ {
+ try
+ {
+ OnOwnershipPermissionsFailure?.Invoke(OwnershipPermissionsFailureStatus.SessionOwnerOnly);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
+ }
+
///
/// Returned by to signify w
/// : The request for ownership was sent (does not mean it will be granted, but the request was sent).
@@ -978,8 +998,16 @@ internal void OwnershipRequest(ulong clientRequestingOwnership)
// Finally, check to see if OnOwnershipRequested is registered and if user script is allowing
// this transfer of ownership
- if (OnOwnershipRequested != null && !OnOwnershipRequested.Invoke(clientRequestingOwnership))
+ try
{
+ if (OnOwnershipRequested != null && !OnOwnershipRequested.Invoke(clientRequestingOwnership))
+ {
+ response = OwnershipRequestResponseStatus.Denied;
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
response = OwnershipRequestResponseStatus.Denied;
}
@@ -1072,7 +1100,14 @@ public enum OwnershipRequestResponseStatus
///
internal void OwnershipRequestResponse(OwnershipRequestResponseStatus ownershipRequestResponse)
{
- OnOwnershipRequestResponse?.Invoke(ownershipRequestResponse);
+ try
+ {
+ OnOwnershipRequestResponse?.Invoke(ownershipRequestResponse);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
///
@@ -1434,6 +1469,27 @@ public void SetSceneObjectStatus(bool isSceneObject = false)
///
public VisibilityDelegate CheckObjectVisibility = null;
+ ///
+ /// Returns true if the object should be visible to the specified client, false otherwise
+ /// Defaults to the object being visible.
+ ///
+ internal bool InvokeCheckObjectVisibility(ulong clientId)
+ {
+ if (CheckObjectVisibility == null)
+ {
+ return true;
+ }
+ try
+ {
+ return CheckObjectVisibility(clientId);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ return true;
+ }
+ }
+
///
/// Delegate type for checking spawn options
///
@@ -1637,7 +1693,7 @@ public void NetworkShow(ulong clientId)
return;
}
- if (CheckObjectVisibility != null && !CheckObjectVisibility(clientId))
+ if (!InvokeCheckObjectVisibility(clientId))
{
if (NetworkManagerOwner.LogLevel <= LogLevel.Normal)
{
@@ -2295,8 +2351,8 @@ internal void SetupObservers()
// then add all connected clients as observers
foreach (var clientId in NetworkManagerOwner.ConnectedClientsIds)
{
- // If CheckObjectVisibility has a callback, then allow that method determine who the observers are.
- if (CheckObjectVisibility != null && !CheckObjectVisibility(clientId))
+ // If CheckObjectVisibility marks this object as not visible to the client, then skip adding it as an observer
+ if (!InvokeCheckObjectVisibility(clientId))
{
continue;
}
@@ -2386,7 +2442,14 @@ internal void InvokeBehaviourOnOwnershipChanged(ulong originalOwnerClientId, ulo
childBehaviour.UpdateNetworkProperties();
if (distributedAuthorityMode || isServer || isPreviousOwner)
{
- childBehaviour.OnLostOwnership();
+ try
+ {
+ childBehaviour.OnLostOwnership();
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
}
@@ -2457,7 +2520,14 @@ internal void InvokeBehaviourOnNetworkObjectParentChanged(NetworkObject parentNe
// Invoke internal notification
child.InternalOnNetworkObjectParentChanged(parentNetworkObject);
// Invoke public notification
- child.OnNetworkObjectParentChanged(parentNetworkObject);
+ try
+ {
+ child.OnNetworkObjectParentChanged(parentNetworkObject);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
}
@@ -3904,7 +3974,14 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
$"client scene mismatch detected! Client-side scene handle ({SceneOriginHandle}) for scene ({gameObject.scene.name})" +
$"has no associated server side (network) scene handle!");
}
- OnMigratedToNewScene?.Invoke();
+ try
+ {
+ OnMigratedToNewScene?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
// Only the authority side will notify clients of non-parented NetworkObject scene changes
if (m_HasAuthority && notify && !transform.parent)
diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs
index 62c3391b46..7adcf969db 100644
--- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionApprovedMessage.cs
@@ -157,7 +157,7 @@ public void Serialize(FastBufferWriter writer, int targetVersion)
// Serialize NetworkVariable data
foreach (var sobj in SpawnedObjectsList)
{
- if (sobj.SpawnWithObservers && (sobj.CheckObjectVisibility == null || sobj.CheckObjectVisibility(OwnerClientId)))
+ if (sobj.SpawnWithObservers && sobj.InvokeCheckObjectVisibility(OwnerClientId))
{
sobj.AddObserver(OwnerClientId);
// In distributed authority mode, we send the currently known observers of each NetworkObject to the client being synchronized.
diff --git a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/AnticipatedNetworkVariable.cs b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/AnticipatedNetworkVariable.cs
index 1cfab08e12..2ebb33553b 100644
--- a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/AnticipatedNetworkVariable.cs
+++ b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/AnticipatedNetworkVariable.cs
@@ -372,7 +372,14 @@ private void OnValueChangedInternal(T previousValue, T newValue)
m_SmoothDuration = 0;
m_CurrentSmoothTime = 0;
- OnAuthoritativeValueChanged?.Invoke(this, previousValue, newValue);
+ try
+ {
+ OnAuthoritativeValueChanged?.Invoke(this, previousValue, newValue);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
///
diff --git a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs
index 5bcd5cead3..a241e8463b 100644
--- a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs
+++ b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs
@@ -681,7 +681,15 @@ private void HandleAddListEvent(NetworkListEvent listEvent)
{
m_DirtyEvents.Add(listEvent);
MarkNetworkObjectDirty();
- OnListChanged?.Invoke(listEvent);
+
+ try
+ {
+ OnListChanged?.Invoke(listEvent);
+ }
+ catch (Exception ex)
+ {
+ UnityEngine.Debug.LogException(ex);
+ }
}
///
diff --git a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariable.cs b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariable.cs
index e8604a66aa..688efa454a 100644
--- a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariable.cs
+++ b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariable.cs
@@ -162,7 +162,14 @@ public virtual T Value
NetworkVariableSerialization.Duplicate(m_InternalValue, ref m_LastInternalValue);
SetDirty(true);
m_IsDisposed = false;
- OnValueChanged?.Invoke(previousValue, m_InternalValue);
+ try
+ {
+ OnValueChanged?.Invoke(previousValue, m_InternalValue);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
}
}
@@ -196,7 +203,14 @@ public bool CheckDirtyState(bool forceCheck = false)
if ((!isDirty || forceCheck) && !NetworkVariableSerialization.AreEqual(ref m_LastInternalValue, ref m_InternalValue))
{
SetDirty(true);
- OnValueChanged?.Invoke(m_LastInternalValue, m_InternalValue);
+ try
+ {
+ OnValueChanged?.Invoke(m_LastInternalValue, m_InternalValue);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
m_IsDisposed = false;
isDirty = true;
NetworkVariableSerialization.Duplicate(m_InternalValue, ref m_LastInternalValue);
@@ -345,7 +359,14 @@ public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
SetDirty(true);
}
- OnValueChanged?.Invoke(m_PreviousValue, m_InternalValue);
+ try
+ {
+ OnValueChanged?.Invoke(m_PreviousValue, m_InternalValue);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
///
diff --git a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs
index dd52c55782..ba44e8f0e4 100644
--- a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs
+++ b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs
@@ -125,7 +125,14 @@ public void Initialize(NetworkBehaviour networkBehaviour)
// When in distributed authority mode, there is no such thing as server write permissions
InternalWritePerm = m_NetworkManager.DistributedAuthorityMode ? NetworkVariableWritePermission.Owner : InternalWritePerm;
- OnInitialize();
+ try
+ {
+ OnInitialize();
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
// Some unit tests don't operate with a running NetworkManager.
// Only update the last time if there is a NetworkTimeSystem.
diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs
index f7ce87d521..972c3a8ccd 100644
--- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs
+++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs
@@ -215,13 +215,25 @@ public void UnloadUnassignedScenes(NetworkManager networkManager)
var scenHandleEntries = SceneNameToSceneHandles[sceneEntry.Key];
foreach (var sceneHandleEntry in scenHandleEntries)
{
- if (!sceneHandleEntry.Value.IsAssigned)
+ if (sceneHandleEntry.Value.IsAssigned)
+ {
+ continue;
+ }
+
+ try
{
- if (sceneManager.VerifySceneBeforeUnloading == null || sceneManager.VerifySceneBeforeUnloading.Invoke(sceneHandleEntry.Value.Scene))
+ // Don't unload the scene if the user-configured handler says to keep it loaded
+ if (sceneManager.VerifySceneBeforeUnloading != null && !sceneManager.VerifySceneBeforeUnloading.Invoke(sceneHandleEntry.Value.Scene))
{
- m_ScenesToUnload.Add(sceneHandleEntry.Value.Scene);
+ continue;
}
}
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
+
+ m_ScenesToUnload.Add(sceneHandleEntry.Value.Scene);
}
}
foreach (var sceneToUnload in m_ScenesToUnload)
@@ -379,18 +391,22 @@ public void SetClientSynchronizationMode(ref NetworkManager networkManager, Load
// If using scene verification
if (sceneManager.VerifySceneBeforeLoading != null)
{
- // Determine if we should take this scene into consideration
- if (!sceneManager.VerifySceneBeforeLoading.Invoke(scene.buildIndex, scene.name, LoadSceneMode.Additive))
+ try
{
- continue;
+ // Determine if we should take this scene into consideration
+ if (!sceneManager.VerifySceneBeforeLoading.Invoke(scene.buildIndex, scene.name, LoadSceneMode.Additive))
+ {
+ continue;
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
}
}
// If the scene is not already in the ScenesLoaded list, then add it
- if (!sceneManager.ScenesLoaded.ContainsKey(scene.handle))
- {
- sceneManager.ScenesLoaded.Add(scene.handle, scene);
- }
+ sceneManager.ScenesLoaded.TryAdd(scene.handle, scene);
}
}
// Set the client synchronization mode
diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs
index cafce0f7c1..f51d7151e0 100644
--- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs
@@ -598,11 +598,18 @@ internal bool HasSceneAuthority()
return (!NetworkManager.DistributedAuthorityMode && NetworkManager.IsServer) || (NetworkManager.DistributedAuthorityMode && NetworkManager.LocalClient.IsSessionOwner);
}
+ private bool m_IsDisposed;
+
///
/// Handle NetworkSceneManager clean up
///
public void Dispose()
{
+ if (m_IsDisposed)
+ {
+ return;
+ }
+ m_IsDisposed = true;
// Always assure we no longer listen to scene changes when disposed.
SceneManager.activeSceneChanged -= SceneManager_ActiveSceneChanged;
SceneUnloadEventHandler.Shutdown();
@@ -940,7 +947,16 @@ internal bool ValidateSceneBeforeLoading(int sceneIndex, string sceneName, LoadS
var validated = true;
if (VerifySceneBeforeLoading != null)
{
- validated = VerifySceneBeforeLoading.Invoke(sceneIndex, sceneName, loadSceneMode);
+ try
+ {
+ validated = VerifySceneBeforeLoading.Invoke(sceneIndex, sceneName, loadSceneMode);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ // Fallback to the no-handler default
+ validated = true;
+ }
}
if (!validated && !m_DisableValidationWarningMessages)
{
@@ -1646,16 +1662,23 @@ private void SceneUnloaded(Scene scene)
{
if (m_NetworkSceneManager != null && m_NetworkSceneManager.NetworkManager != null)
{
- m_NetworkSceneManager.OnSceneEvent?.Invoke(new SceneEvent()
+ try
+ {
+ m_NetworkSceneManager.OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ AsyncOperation = m_AsyncOperation,
+ SceneEventType = SceneEventType.UnloadComplete,
+ SceneName = m_Scene.name,
+ ScenePath = m_Scene.path,
+ LoadSceneMode = m_LoadSceneMode,
+ ClientId = m_ClientId
+ });
+ m_NetworkSceneManager.OnUnloadComplete?.Invoke(m_ClientId, m_Scene.name);
+ }
+ catch (Exception ex)
{
- AsyncOperation = m_AsyncOperation,
- SceneEventType = SceneEventType.UnloadComplete,
- SceneName = m_Scene.name,
- ScenePath = m_Scene.path,
- LoadSceneMode = m_LoadSceneMode,
- ClientId = m_ClientId
- });
- m_NetworkSceneManager.OnUnloadComplete?.Invoke(m_ClientId, m_Scene.name);
+ Debug.LogException(ex);
+ }
}
SceneManager.sceneUnloaded -= SceneUnloaded;
SceneUnloadComplete(this);
@@ -1671,17 +1694,25 @@ private SceneUnloadEventHandler(NetworkSceneManager networkSceneManager, Scene s
m_Scene = scene;
SceneManager.sceneUnloaded += SceneUnloaded;
// Send the initial unload event notification
- m_NetworkSceneManager.OnSceneEvent?.Invoke(new SceneEvent()
- {
- AsyncOperation = m_AsyncOperation,
- SceneEventType = SceneEventType.Unload,
- SceneName = m_Scene.name,
- ScenePath = m_Scene.path,
- LoadSceneMode = m_LoadSceneMode,
- ClientId = clientId
- });
+ try
+ {
+ m_NetworkSceneManager.OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ AsyncOperation = m_AsyncOperation,
+ SceneEventType = SceneEventType.Unload,
+ SceneName = m_Scene.name,
+ ScenePath = m_Scene.path,
+ LoadSceneMode = m_LoadSceneMode,
+ ClientId = clientId
+ });
- m_NetworkSceneManager.OnUnload?.Invoke(networkSceneManager.NetworkManager.LocalClientId, m_Scene.name, null);
+ m_NetworkSceneManager.OnUnload?.Invoke(networkSceneManager.NetworkManager.LocalClientId, m_Scene.name, null);
+
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
}
@@ -2092,13 +2123,20 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic
// Notify the local server that the client has been sent the synchronize event
if (!synchronizingService)
{
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
{
- SceneEventType = SceneEventType.Synchronize,
- ClientId = clientId
- });
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ SceneEventType = SceneEventType.Synchronize,
+ ClientId = clientId
+ });
+ OnSynchronize?.Invoke(clientId);
- OnSynchronize?.Invoke(clientId);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
EndSceneEvent(sceneEventData.SceneEventId);
@@ -2157,17 +2195,25 @@ private void OnClientBeginSync(uint sceneEventId)
sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, loadSceneMode, sceneEventProgress);
// Notify local client that a scene load has begun
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
{
- AsyncOperation = sceneLoad,
- SceneEventType = SceneEventType.Load,
- LoadSceneMode = loadSceneMode,
- SceneName = sceneName,
- ScenePath = ScenePathFromHash(sceneHash),
- ClientId = NetworkManager.LocalClientId,
- });
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ AsyncOperation = sceneLoad,
+ SceneEventType = SceneEventType.Load,
+ LoadSceneMode = loadSceneMode,
+ SceneName = sceneName,
+ ScenePath = ScenePathFromHash(sceneHash),
+ ClientId = NetworkManager.LocalClientId,
+ });
+
+ OnLoad?.Invoke(NetworkManager.LocalClientId, sceneName, loadSceneMode, sceneLoad);
- OnLoad?.Invoke(NetworkManager.LocalClientId, sceneName, loadSceneMode, sceneLoad);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
else
{
@@ -2323,13 +2369,21 @@ private void HandleClientSceneEvent(uint sceneEventId)
{
sceneEventData.IsStartingSynchronization = false;
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
{
- SceneEventType = SceneEventType.Synchronize,
- ClientId = NetworkManager.LocalClientId,
- });
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ SceneEventType = SceneEventType.Synchronize,
+ ClientId = NetworkManager.LocalClientId,
+ });
+
+ OnSynchronize?.Invoke(NetworkManager.LocalClientId);
- OnSynchronize?.Invoke(NetworkManager.LocalClientId);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
if (!sceneEventData.IsDoneWithSynchronization())
@@ -2406,13 +2460,21 @@ private void HandleClientSceneEvent(uint sceneEventId)
NetworkManager.ConnectionManager.InvokeOnClientConnectedCallback(NetworkManager.LocalClientId);
// Notify the client that they have finished synchronizing
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
{
- SceneEventType = sceneEventData.SceneEventType,
- ClientId = NetworkManager.LocalClientId, // Client sent this to the server
- });
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ SceneEventType = sceneEventData.SceneEventType,
+ ClientId = NetworkManager.LocalClientId, // Client sent this to the server
+ });
+
+ OnSynchronizeComplete?.Invoke(NetworkManager.LocalClientId);
- OnSynchronizeComplete?.Invoke(NetworkManager.LocalClientId);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
{
@@ -2434,11 +2496,18 @@ private void HandleClientSceneEvent(uint sceneEventId)
case SceneEventType.ReSynchronize:
{
// Notify the local client that they have been re-synchronized after being synchronized with an in progress game session
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
+ {
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ SceneEventType = sceneEventData.SceneEventType,
+ ClientId = NetworkManager.ServerClientId, // Server sent this to client
+ });
+ }
+ catch (Exception ex)
{
- SceneEventType = sceneEventData.SceneEventType,
- ClientId = NetworkManager.ServerClientId, // Server sent this to client
- });
+ Debug.LogException(ex);
+ }
EndSceneEvent(sceneEventId);
break;
@@ -2495,12 +2564,19 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
NetworkManager.ConnectedClients[clientId].IsConnected = true;
// Notify that a client has finished synchronizing
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
+ {
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ SceneEventType = sceneEventData.SceneEventType,
+ ClientId = clientId
+ });
+ OnSynchronizeComplete?.Invoke(clientId);
+ }
+ catch (Exception ex)
{
- SceneEventType = sceneEventData.SceneEventType,
- ClientId = clientId
- });
- OnSynchronizeComplete?.Invoke(clientId);
+ Debug.LogException(ex);
+ }
// For non-authority clients in a distributed authority session, we show hidden objects,
// we distribute NetworkObjects, and then we end the scene event.
@@ -2537,12 +2613,19 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
sceneEventData.SceneEventType = SceneEventType.ReSynchronize;
SendSceneEventData(sceneEventId, new ulong[] { clientId });
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
{
- SceneEventType = sceneEventData.SceneEventType,
- SceneName = string.Empty,
- ClientId = clientId
- });
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ SceneEventType = sceneEventData.SceneEventType,
+ SceneName = string.Empty,
+ ClientId = clientId
+ });
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
// DANGO-EXP TODO: Remove this once service distributes objects
NetworkManager.SpawnManager.DistributeNetworkObjects(clientId);
@@ -3349,39 +3432,46 @@ public List GetSceneMapping(MapTypes mapType)
private void InvokeSceneEvents(ulong clientId, SceneEventData eventData, AsyncOperation asyncOperation = null, Scene scene = default)
{
var sceneName = SceneNameFromHash(eventData.SceneHash);
- OnSceneEvent?.Invoke(new SceneEvent()
+ try
{
- AsyncOperation = asyncOperation,
- SceneEventType = eventData.SceneEventType,
- SceneName = sceneName,
- ScenePath = ScenePathFromHash(eventData.SceneHash),
- ClientId = clientId,
- LoadSceneMode = eventData.LoadSceneMode,
- ClientsThatCompleted = eventData.ClientsCompleted,
- ClientsThatTimedOut = eventData.ClientsTimedOut,
- Scene = scene,
- });
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ AsyncOperation = asyncOperation,
+ SceneEventType = eventData.SceneEventType,
+ SceneName = sceneName,
+ ScenePath = ScenePathFromHash(eventData.SceneHash),
+ ClientId = clientId,
+ LoadSceneMode = eventData.LoadSceneMode,
+ ClientsThatCompleted = eventData.ClientsCompleted,
+ ClientsThatTimedOut = eventData.ClientsTimedOut,
+ Scene = scene,
+ });
- switch (eventData.SceneEventType)
+ switch (eventData.SceneEventType)
+ {
+ case SceneEventType.Load:
+ OnLoad?.Invoke(clientId, sceneName, eventData.LoadSceneMode, asyncOperation);
+ break;
+ case SceneEventType.Unload:
+ OnUnload?.Invoke(clientId, sceneName, asyncOperation);
+ break;
+ case SceneEventType.LoadComplete:
+ OnLoadComplete?.Invoke(clientId, sceneName, eventData.LoadSceneMode);
+ break;
+ case SceneEventType.UnloadComplete:
+ OnUnloadComplete?.Invoke(clientId, sceneName);
+ break;
+ case SceneEventType.LoadEventCompleted:
+ OnLoadEventCompleted?.Invoke(SceneNameFromHash(eventData.SceneHash), eventData.LoadSceneMode, eventData.ClientsCompleted, eventData.ClientsTimedOut);
+ break;
+ case SceneEventType.UnloadEventCompleted:
+ OnUnloadEventCompleted?.Invoke(SceneNameFromHash(eventData.SceneHash), eventData.LoadSceneMode, eventData.ClientsCompleted, eventData.ClientsTimedOut);
+ break;
+ }
+ }
+ catch (Exception ex)
{
- case SceneEventType.Load:
- OnLoad?.Invoke(clientId, sceneName, eventData.LoadSceneMode, asyncOperation);
- break;
- case SceneEventType.Unload:
- OnUnload?.Invoke(clientId, sceneName, asyncOperation);
- break;
- case SceneEventType.LoadComplete:
- OnLoadComplete?.Invoke(clientId, sceneName, eventData.LoadSceneMode);
- break;
- case SceneEventType.UnloadComplete:
- OnUnloadComplete?.Invoke(clientId, sceneName);
- break;
- case SceneEventType.LoadEventCompleted:
- OnLoadEventCompleted?.Invoke(SceneNameFromHash(eventData.SceneHash), eventData.LoadSceneMode, eventData.ClientsCompleted, eventData.ClientsTimedOut);
- break;
- case SceneEventType.UnloadEventCompleted:
- OnUnloadEventCompleted?.Invoke(SceneNameFromHash(eventData.SceneHash), eventData.LoadSceneMode, eventData.ClientsCompleted, eventData.ClientsTimedOut);
- break;
+ Debug.LogException(ex);
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs
index daf8d153c0..9ca4ee19da 100644
--- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs
@@ -341,13 +341,27 @@ internal void HandleNetworkPrefabDestroy(NetworkObject networkObjectInstance)
{
if (m_PrefabAssetToPrefabHandler.TryGetValue(networkPrefabAssetHash, out var prefabInstanceHandler))
{
- prefabInstanceHandler.Destroy(networkObjectInstance);
+ try
+ {
+ prefabInstanceHandler.Destroy(networkObjectInstance);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
}
// Otherwise the NetworkObject is the source NetworkPrefab
else if (m_PrefabAssetToPrefabHandler.TryGetValue(networkObjectInstanceHash, out var prefabInstanceHandler))
{
- prefabInstanceHandler.Destroy(networkObjectInstance);
+ try
+ {
+ prefabInstanceHandler.Destroy(networkObjectInstance);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
index 28803104f4..e9f138cf84 100644
--- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
@@ -522,7 +522,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
{
NetworkLog.LogErrorServer($"[{networkObject.name}][Session Owner Only] You cannot change ownership of a {nameof(NetworkObject)} that has the {NetworkObject.OwnershipStatus.SessionOwner} flag set!");
}
- networkObject.OnOwnershipPermissionsFailure?.Invoke(NetworkObject.OwnershipPermissionsFailureStatus.SessionOwnerOnly);
+ networkObject.InvokeOwnershipPermissionsFailure();
return;
}
@@ -535,7 +535,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
{
NetworkLog.LogErrorServer($"[{networkObject.name}][Locked] You cannot change ownership while a {nameof(NetworkObject)} is locked!");
}
- networkObject.OnOwnershipPermissionsFailure?.Invoke(NetworkObject.OwnershipPermissionsFailureStatus.Locked);
+ networkObject.InvokeOwnershipPermissionsFailure();
return;
}
if (networkObject.IsRequestInProgress)
@@ -544,7 +544,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
{
NetworkLog.LogErrorServer($"[{networkObject.name}][Request Pending] You cannot change ownership while a {nameof(NetworkObject)} has a pending ownership request!");
}
- networkObject.OnOwnershipPermissionsFailure?.Invoke(NetworkObject.OwnershipPermissionsFailureStatus.RequestInProgress);
+ networkObject.InvokeOwnershipPermissionsFailure();
return;
}
if (networkObject.IsOwnershipRequestRequired)
@@ -553,7 +553,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
{
NetworkLog.LogErrorServer($"[{networkObject.name}][Request Required] You cannot change ownership directly if a {nameof(NetworkObject)} has the {NetworkObject.OwnershipStatus.RequestRequired} flag set!");
}
- networkObject.OnOwnershipPermissionsFailure?.Invoke(NetworkObject.OwnershipPermissionsFailureStatus.RequestRequired);
+ networkObject.InvokeOwnershipPermissionsFailure();
return;
}
if (!networkObject.IsOwnershipTransferable)
@@ -562,7 +562,7 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId, bool
{
NetworkLog.LogErrorServer($"[{networkObject.name}][Not transferrable] You cannot change ownership of a {nameof(NetworkObject)} that does not have the {NetworkObject.OwnershipStatus.Transferable} flag set!");
}
- networkObject.OnOwnershipPermissionsFailure?.Invoke(NetworkObject.OwnershipPermissionsFailureStatus.NotTransferrable);
+ networkObject.InvokeOwnershipPermissionsFailure();
return;
}
}
@@ -1915,7 +1915,7 @@ internal void UpdateObservedNetworkObjects(ulong clientId)
else
{
// CheckObject visibility overrides SpawnWithObservers under this condition
- if (sobj.CheckObjectVisibility(clientId))
+ if (sobj.InvokeCheckObjectVisibility(clientId))
{
sobj.AddObserver(clientId);
}
@@ -2312,8 +2312,19 @@ internal void DeferredDespawnUpdate(NetworkTime serverTime)
// Double check to make sure user did not remove the callback
if (networkObject.OnDeferredDespawnComplete != null)
{
+ var despawnThisTick = false;
+ try
+ {
+ despawnThisTick = networkObject.OnDeferredDespawnComplete.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ // If the user callback throws, despawn immediately to avoid throwing every tick.
+ despawnThisTick = true;
+ }
// If the user callback returns true, then we despawn it this tick
- if (networkObject.OnDeferredDespawnComplete.Invoke())
+ if (despawnThisTick)
{
deferredObjectEntry.TickToDespawn = currentTick;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Timing/AnticipationSystem.cs b/com.unity.netcode.gameobjects/Runtime/Timing/AnticipationSystem.cs
index 0e86fd24fc..33bbaa3f12 100644
--- a/com.unity.netcode.gameobjects/Runtime/Timing/AnticipationSystem.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Timing/AnticipationSystem.cs
@@ -69,13 +69,28 @@ public void ProcessReanticipation()
{
foreach (var behaviour in item.OwnerObject.ChildNetworkBehaviours.Values)
{
- behaviour.OnReanticipate(lastRoundTripTime);
+ try
+ {
+ behaviour.OnReanticipate(lastRoundTripTime);
+ }
+ catch (System.Exception ex)
+ {
+ UnityEngine.Debug.LogException(ex);
+ }
}
item.ResetAnticipation();
}
ObjectsToReanticipate.Clear();
- OnReanticipate?.Invoke(lastRoundTripTime);
+
+ try
+ {
+ OnReanticipate?.Invoke(lastRoundTripTime);
+ }
+ catch (System.Exception ex)
+ {
+ UnityEngine.Debug.LogException(ex);
+ }
}
public void Update()
diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs
index 13bf8784b3..1b9a484bdc 100644
--- a/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Transports/NetworkTransport.cs
@@ -50,7 +50,14 @@ public abstract class NetworkTransport : MonoBehaviour
/// The time the event was received, as reported by Time.realtimeSinceStartup.
protected void InvokeOnTransportEvent(NetworkEvent eventType, ulong clientId, ArraySegment payload, float receiveTime)
{
- OnTransportEvent?.Invoke(eventType, clientId, payload, receiveTime);
+ try
+ {
+ OnTransportEvent?.Invoke(eventType, clientId, payload, receiveTime);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
}
///