diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md
index 9996ef2d61..73ed64a735 100644
--- a/com.unity.netcode.gameobjects/CHANGELOG.md
+++ b/com.unity.netcode.gameobjects/CHANGELOG.md
@@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Added
+- Added `NetworkManager.OnPreShutdown` which is called before the NetworkManager cleans up and shuts down. (#3366)
- Added interpolator types as an inspector view selection for position, rotation, and scale. (#3337)
- Added a new smooth dampening interpolator type that provides a nice balance between precision and smoothing results. (#3337)
- Added `NetworkTimeSystem.TickLatency` property that provides the average latency of a client. (#3337)
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
index d564f0f8f3..a35fcfec75 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
@@ -807,6 +807,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.
///
@@ -1481,6 +1487,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 8b1c993268..c2d482da67 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkManagerEventsTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkManagerEventsTests.cs
@@ -236,6 +236,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