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
1 change: 1 addition & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Fixed

- Fixed a NullReferenceException that would be thrown if a MonoBehaviour derived from NetworkManager defines it's own Awake or OnEnable. (#4244)
- Ensured a useful and human readable error is logged when a NetworkVariable is trying to serialize a private or protected type. (#4239)
- Issue where `NetworkAnimator` logged an error for a trigger-conditioned transition into an Exit node, and a client that joined during that transition, or during one into a sub-state machine, did not synchronize with it. Transitions that pass through Exit, Entry or sub-state machine nodes now resolve to the state they reach, and a late-joining client cross-fades from the matching originating state when several states transition into the same destination. (#4238)
- Ensured all callbacks are wrapped with exception handling to avoid silent errors. (#4161)
Expand Down
64 changes: 56 additions & 8 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,11 +1100,18 @@
OnSingletonReady?.Invoke();
}

private void Awake()
/// <summary>
/// Unity calls Awake when loading an instance of a script component.
/// </summary>
/// <remarks>
/// Override this method to implement custom initialization logic for a derived <see cref="NetworkManager"/>.
/// Ensure you call <c>base.Awake()</c> in your override to allow the base initialization to happen.
/// </remarks>
protected virtual void Awake()
{
if (Log == null)
{
Log = new ContextualLogger(this, false);
Log = new ContextualLogger(this);
}

NetworkConfig?.InitializePrefabs();
Expand All @@ -1124,7 +1131,14 @@
}
}

private void OnEnable()
/// <summary>
/// Called when a component of an active GameObject is first enabled.
/// </summary>
/// <remarks>
/// Override this method to implement custom initialization logic for a derived <see cref="NetworkManager"/>.
/// Ensure you call <c>base.OnEnable()</c> in your override to allow the base initialization to happen.
/// </remarks>
protected virtual void OnEnable()
{
if (RunInBackground)
{
Expand Down Expand Up @@ -1485,6 +1499,11 @@
/// <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);
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 @@ -1578,6 +1597,11 @@
/// <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);
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 @@ -1663,6 +1687,11 @@
/// <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);
Log.Warning(new Context(LogLevel.Normal, "No logger defined. Ensure base.Awake() and base.OnEnable is called in any derived NetworkManager classes."));
}

Check warning on line 1694 in com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs#L1691-L1694

Added lines #L1691 - L1694 were not covered by tests
Log.CaptureFunctionCall();

if (!CanStart(StartType.Host))
Expand Down Expand Up @@ -1848,7 +1877,7 @@
{
if (gameObject != null && scene == gameObject.scene)
{
OnDestroy();
DestroyInternal();

Check warning on line 1880 in com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs#L1880

Added line #L1880 was not covered by tests
}
}

Expand Down Expand Up @@ -1991,7 +2020,7 @@
}
}

// Ensures that the NetworkManager is cleaned up before OnDestroy is run on NetworkObjects and NetworkBehaviours when quitting the application.
// Ensures that the NetworkManager is cleaned up before DestroyInternal is run on NetworkObjects and NetworkBehaviours when quitting the application.
private void OnApplicationQuit()
{
// Abrupt shutdown (or immediate exit of play mode).
Expand All @@ -2005,7 +2034,7 @@
{
return;
}
OnDestroy();
DestroyInternal();
#if UNITY_EDITOR
if (Singleton != null)
{
Expand All @@ -2016,15 +2045,34 @@

private bool m_IsDestroyed = false;

/// <summary>
/// Called when a GameObject or component is about to be destroyed.
/// </summary>
/// <remarks>
/// Override this method to implement custom teardown logic for a derived <see cref="NetworkManager"/>.
/// Ensure you call <c>base.OnDestroy()</c> in your override to allow the base teardown to happen.
/// </remarks>
protected virtual void OnDestroy()
{
DestroyInternal();
}

// Internal destroy method that can't be overridden by derived classes.
// Note that this gets also called manually by OnSceneUnloaded and OnApplicationQuit
private void OnDestroy()
private void DestroyInternal()
{
if (m_IsDestroyed)
{
return;
}
m_IsDestroyed = true;

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

Check warning on line 2074 in com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs#L2071-L2074

Added lines #L2071 - L2074 were not covered by tests

try
{
ShutdownInternal();
Expand Down Expand Up @@ -2120,7 +2168,7 @@

if (Log == null)
{
Log = new ContextualLogger(this, false);
Log = new ContextualLogger(this);
}

// Do a validation pass on NetworkConfig properties
Expand Down
4 changes: 2 additions & 2 deletions com.unity.netcode.gameobjects/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "com.unity.netcode.gameobjects",
"displayName": "Netcode for GameObjects",
"description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.",
"version": "3.2.1",
"version": "3.3.0",
"unity": "6000.7",
"unityRelease": "0b8",
"dependencies": {
Expand All @@ -17,4 +17,4 @@
"path": "Samples~/Bootstrap"
}
]
}
}
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