diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
index 429259c9cb..0aec58612f 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
@@ -477,6 +477,12 @@ public struct ConnectionApprovalRequest
///
public event Action OnClientStarted = null;
+ ///
+ /// Subscribe to this event to get notifications before a instance is being destroyed.
+ /// This is useful if you want to use the state of anything the NetworkManager cleans up during its shutdown.
+ ///
+ public event Action OnPreShutdown = null;
+
///
/// This callback is invoked once the local server is stopped.
///
@@ -1198,6 +1204,8 @@ internal void ShutdownInternal()
NetworkLog.LogInfo(nameof(ShutdownInternal));
}
+ OnPreShutdown?.Invoke();
+
this.UnregisterAllNetworkUpdates();
// Everything is shutdown in the order of their dependencies
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkManagerEventsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkManagerEventsTests.cs
index 34a406aed8..1b4d97df73 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkManagerEventsTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkManagerEventsTests.cs
@@ -237,6 +237,46 @@ public IEnumerator OnClientAndServerStartedCalledWhenHostStarts()
Assert.AreEqual(2, callbacksInvoked, "either OnServerStarted or OnClientStarted wasn't invoked");
}
+ [UnityTest]
+ public IEnumerator OnPreShutdownCalledWhenShuttingDown()
+ {
+ bool preShutdownInvoked = false;
+ bool shutdownInvoked = false;
+ var gameObject = new GameObject(nameof(OnPreShutdownCalledWhenShuttingDown));
+ m_ServerManager = gameObject.AddComponent();
+
+ // Set dummy transport that does nothing
+ var transport = gameObject.AddComponent();
+ m_ServerManager.NetworkConfig = new NetworkConfig() { NetworkTransport = transport };
+
+ Action onPreShutdown = () =>
+ {
+ preShutdownInvoked = true;
+ Assert.IsFalse(shutdownInvoked, "OnPreShutdown was invoked after OnServerStopped");
+ };
+
+ Action onServerStopped = (bool wasAlsoClient) =>
+ {
+ shutdownInvoked = true;
+ Assert.IsTrue(preShutdownInvoked, "OnPreShutdown wasn't invoked before OnServerStopped");
+ };
+
+ // Start server to cause initialization process
+ Assert.True(m_ServerManager.StartServer());
+ Assert.True(m_ServerManager.IsListening);
+
+ m_ServerManager.OnPreShutdown += onPreShutdown;
+ m_ServerManager.OnServerStopped += onServerStopped;
+ m_ServerManager.Shutdown();
+ Object.DestroyImmediate(gameObject);
+
+ yield return WaitUntilManagerShutsdown();
+
+ Assert.False(m_ServerManager.IsListening);
+ Assert.True(preShutdownInvoked, "OnPreShutdown wasn't invoked");
+ Assert.True(shutdownInvoked, "OnServerStopped wasn't invoked");
+ }
+
private IEnumerator WaitUntilManagerShutsdown()
{
/* Need two updates to actually shut down. First one to see the transport failing, which
diff --git a/pvpExceptions.json b/pvpExceptions.json
index f4eaca7c3f..0a338d445a 100644
--- a/pvpExceptions.json
+++ b/pvpExceptions.json
@@ -928,6 +928,7 @@
"Unity.Netcode.RuntimeTests.NetworkManagerEventsTests: IEnumerator OnServerStartedCalledWhenServerStarts(): undocumented",
"Unity.Netcode.RuntimeTests.NetworkManagerEventsTests: IEnumerator OnClientStartedCalledWhenClientStarts(): undocumented",
"Unity.Netcode.RuntimeTests.NetworkManagerEventsTests: IEnumerator OnClientAndServerStartedCalledWhenHostStarts(): undocumented",
+ "Unity.Netcode.RuntimeTests.NetworkManagerEventsTests: IEnumerator OnPreShutdownCalledWhenShuttingDown(): undocumented",
"Unity.Netcode.RuntimeTests.NetworkManagerEventsTests: IEnumerator Teardown(): undocumented",
"Unity.Netcode.RuntimeTests.NetworkManagerSceneManagerTests: undocumented",
"Unity.Netcode.RuntimeTests.NetworkManagerSceneManagerTests: void SceneManagerAssigned(): undocumented",