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",