Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ public void SetSingleton()
OnSingletonReady?.Invoke();
}

private void Awake()
protected virtual void Awake()
{
if (Log == null)
{
Expand All @@ -1088,7 +1088,7 @@ private void Awake()
OnInstantiated?.Invoke(this);
}

private void OnEnable()
protected virtual void OnEnable()
{
if (RunInBackground)
{
Expand Down Expand Up @@ -1337,6 +1337,11 @@ private bool CanStart(StartType type)
/// <returns>returns true if <see cref="NetworkManager"/> started in server mode successfully; otherwise false</returns>
public bool StartServer()
{
if (Log == null)
{
Log = new ContextualLogger(this, false);
Log.Warning(new Context(LogLevel.Normal, "No logger defined. Ensure base.Awake() and base.OnEnable is called in any derived NetworkManager classes."));
}
Log.CaptureFunctionCall();

if (!CanStart(StartType.Server))
Expand Down Expand Up @@ -1397,6 +1402,11 @@ public bool StartServer()
/// <returns>(<see cref="true"/>/<see cref="false"/>) returns true if <see cref="NetworkManager"/> started in client mode successfully.</returns>
public bool StartClient()
{
if (Log == null)
{
Log = new ContextualLogger(this, false);
Log.Warning(new Context(LogLevel.Normal, "No logger defined. Ensure base.Awake() and base.OnEnable is called in any derived NetworkManager classes."));
}
Log.CaptureFunctionCall();

if (!CanStart(StartType.Client))
Expand Down Expand Up @@ -1450,6 +1460,11 @@ public bool StartClient()
/// <returns>(<see cref="true"/>/<see cref="false"/>) returns true if <see cref="NetworkManager"/> started in host mode successfully.</returns>
public bool StartHost()
{
if (Log == null)
{
Log = new ContextualLogger(this, false);
Log.Warning(new Context(LogLevel.Normal, "No logger defined. Ensure base.Awake() and base.OnEnable is called in any derived NetworkManager classes."));
}
Log.CaptureFunctionCall();

if (!CanStart(StartType.Host))
Expand Down Expand Up @@ -1752,8 +1767,14 @@ private void OnApplicationQuit()
}

// Note that this gets also called manually by OnSceneUnloaded and OnApplicationQuit
private void OnDestroy()
protected virtual void OnDestroy()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2

A future OnDestroy override that disposes a native allocation can dispose it twice when a listening derived manager quits. OnApplicationQuit manually calls OnDestroy, which now dispatches to the override. Unity also invokes OnDestroy when destroying the active component. Previously, the manual call reached only NetworkManager's private implementation. Extract the manual shutdown work into a private method. Call that method from OnApplicationQuit and OnSceneUnloaded. Reserve virtual OnDestroy for Unity's destruction callback.

🤖 Helpful? 👍/👎

{
if (Log == null)
{
Log = new ContextualLogger(this, false);
Log.Warning(new Context(LogLevel.Normal, "No logger defined. Ensure base.Awake() and base.OnEnable is called in any derived NetworkManager classes."));
}

try
{
ShutdownInternal();
Expand Down
41 changes: 41 additions & 0 deletions testproject/Assets/Tests/Runtime/NetworkManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,45 @@ private void OnServerStopped(bool obj)
m_ServerNetworkManager.Shutdown();
}
}

internal class DerivedNetworkManagerTests
{
private class TestNetworkManager : NetworkManager
{
public void Awake() { }
public void OnEnable() { }
}

[UnityTest]
public IEnumerator ValidateDerivedNetworkManager()
{
var gameObject = new GameObject("TestNetworkManager");
var server = gameObject.AddComponent<TestNetworkManager>();
var mockTransport = server.gameObject.AddComponent<MockTransport>();
server.NetworkConfig ??= new NetworkConfig();
server.NetworkConfig.NetworkTransport = mockTransport;
var client = Object.Instantiate(server);

var isListening = server.StartServer();
Assert.That(isListening, Is.True, "Server failed to start!");

client.StartClient();

var timeoutHelper = new TimeoutHelper();
yield return NetcodeIntegrationTest.WaitForConditionOrTimeOut(() => client.IsListening, timeoutHelper);
Assert.That(timeoutHelper.TimedOut, Is.False, "Client timed out waiting to connect!");

Object.Destroy(client.gameObject);

server.Shutdown();
timeoutHelper = new TimeoutHelper();
yield return NetcodeIntegrationTest.WaitForConditionOrTimeOut(() => !server.IsListening, timeoutHelper);
Assert.That(timeoutHelper.TimedOut, Is.False, "Timed out waiting for server to shutdown!");

isListening = server.StartHost();
Assert.That(isListening, Is.True, "Host failed to start!");

Object.Destroy(gameObject);
}
}
}
Loading