diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md
index f4b0bfc60e..6cd479f449 100644
--- a/com.unity.netcode.gameobjects/CHANGELOG.md
+++ b/com.unity.netcode.gameobjects/CHANGELOG.md
@@ -77,6 +77,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Fixed
+- CMB service no longer waits for a timeout before disconnecting on an invalid ConnectionRequest. (#3812)
- Initialization errors with NetworkAnimator. (#3767)
- Multiple disconnect events from the same transport will no longer disconnect the host. (#3707)
- Fixed NetworkTransform state synchronization issue when `NetworkTransform.SwitchTransformSpaceWhenParented` is enabled and the associated NetworkObject is parented multiple times in a single frame or within a couple of frames. (#3664)
diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
index 29e4be6715..eea30f54b0 100644
--- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs
@@ -492,6 +492,8 @@ internal void HandleNetworkEvent(NetworkEvent networkEvent, ulong transportClien
///
private ulong m_LocalClientTransportId;
+ internal ulong LocalClientTransportId => m_LocalClientTransportId;
+
///
/// Handles a event.
///
@@ -595,8 +597,10 @@ internal void DisconnectEventHandler(ulong transportClientId)
// do not remove it just yet.
var (clientId, isConnectedClient) = TransportIdToClientId(transportClientId);
- // If the client is not registered and we are the server
- if (!isConnectedClient && NetworkManager.IsServer)
+ // If the client is not registered and we are the server or we are connecting to
+ // the live CMB service and the client had a transport Id assigned then exit early
+ /// handles disconnecting the client
+ if (!isConnectedClient && (NetworkManager.IsServer || (NetworkManager.CMBServiceConnection && m_LocalClientTransportId != 0)))
{
// Then exit early
return;
@@ -639,8 +643,18 @@ internal void DisconnectEventHandler(ulong transportClientId)
// Client's clean up their transport id separately from the server.
TransportIdCleanUp(transportClientId);
- // Notify local client of disconnection
- InvokeOnClientDisconnectCallback(clientId);
+ try
+ {
+ // Notify local client of disconnection
+ InvokeOnClientDisconnectCallback(clientId);
+ }
+ catch (Exception ex)
+ {
+ Debug.LogException(ex);
+ }
+
+ // Reset the transport ID
+ m_LocalClientTransportId = 0;
// As long as we are not in the middle of a shutdown
if (!NetworkManager.ShutdownInProgress)
diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DisconnectReasonMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DisconnectReasonMessage.cs
index 1a8bf88dcc..c640cf8aac 100644
--- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DisconnectReasonMessage.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DisconnectReasonMessage.cs
@@ -1,3 +1,6 @@
+using System.Collections;
+using UnityEngine;
+
namespace Unity.Netcode
{
internal struct DisconnectReasonMessage : INetworkMessage
@@ -37,10 +40,24 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
public void Handle(ref NetworkContext context)
{
+ var networkManager = (NetworkManager)context.SystemOwner;
// Always apply the server-side generated disconnect reason to the server specific disconnect reason.
// This is combined with the additional disconnect information when getting NetworkManager.DisconnectReason
// (NetworkConnectionManager.DisconnectReason).
- ((NetworkManager)context.SystemOwner).ConnectionManager.ServerDisconnectReason = Reason;
+ networkManager.ConnectionManager.ServerDisconnectReason = Reason;
+
+ if (networkManager.NetworkConfig.UseCMBService)
+ {
+ networkManager.StartCoroutine(HandleDisconnectAfterReason(networkManager));
+ }
+ }
+
+ private IEnumerator HandleDisconnectAfterReason(NetworkManager networkManager)
+ {
+ yield return new WaitForFixedUpdate();
+
+ var connectionManager = networkManager.ConnectionManager;
+ connectionManager.DisconnectEventHandler(connectionManager.LocalClientTransportId);
}
};
}
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs
index 4a436457c0..bb4b53f1f6 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/SessionVersionConnectionRequest.cs
@@ -9,52 +9,36 @@ internal class SessionVersionConnectionRequest : NetcodeIntegrationTest
{
protected override int NumberOfClients => 0;
- // TODO: [CmbServiceTests] Adapt to run with the service
- protected override bool UseCMBService()
- {
- return false;
- }
+ // Use a specific version for the CMB tests
+ // The CMB service has more detailed versioning logic. Not all lower versions are invalid to connect with the higher version.
+ // This version will not connect with the version lower.
+ private const int k_ValidCMBVersion = 5;
public SessionVersionConnectionRequest() : base(NetworkTopologyTypes.DistributedAuthority, HostOrServer.DAHost) { }
private bool m_UseValidSessionVersion;
private bool m_ClientWasDisconnected;
- private NetworkManager m_ClientNetworkManager;
+ private bool m_CanStartClients;
+
+ // Don't start automatically when using the CMB Service
+ // We want to customize the SessionVersion of the session owner before they connect
+ protected override bool CanStartServerAndClients() => !m_UseCmbService || m_CanStartClients;
///
/// Callback used to mock the scenario where a client has an invalid session version
///
- ///
- private SessionConfig GetInavlidSessionConfig()
+ private SessionConfig GetInvalidSessionConfig()
{
var authority = GetAuthorityNetworkManager();
return new SessionConfig(authority.SessionConfig.SessionVersion - 1);
}
- ///
- /// Overriding this method allows us to configure the newly instantiated client's
- /// NetworkManager prior to it being started.
- ///
- /// the newly instantiated NetworkManager
- protected override void OnNewClientCreated(NetworkManager networkManager)
- {
- m_ClientWasDisconnected = false;
- m_ClientNetworkManager = networkManager;
- m_ClientNetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback;
- if (!m_UseValidSessionVersion)
- {
- networkManager.OnGetSessionConfig = GetInavlidSessionConfig;
- }
- base.OnNewClientCreated(networkManager);
- }
-
///
/// Tracks if the client was disconnected or not
///
private void OnClientDisconnectCallback(ulong clientId)
{
m_ClientWasDisconnected = true;
- m_ClientNetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback;
}
///
@@ -69,51 +53,76 @@ protected override bool ShouldWaitForNewClientToConnect(NetworkManager networkMa
{
return m_UseValidSessionVersion;
}
-
- internal enum SessionVersionType
- {
- Valid,
- Invalid,
- }
-
///
/// Validates that when the client's session config version is valid a client will be
/// allowed to connect and when it is not valid the client will be disconnected.
///
- ///
- /// This is just a mock of the service logic to validate everything on the NGO side is
- /// working correctly.
- ///
- /// true = use valid session version | false = use invalid session version
[UnityTest]
- public IEnumerator ValidateSessionVersion([Values] SessionVersionType type)
+ public IEnumerator ValidateSessionVersion()
{
- // Test client being disconnected due to invalid session version
- m_UseValidSessionVersion = type == SessionVersionType.Valid;
- yield return CreateAndStartNewClient();
- yield return s_DefaultWaitForTick;
- if (!m_UseValidSessionVersion)
+ if (m_UseCmbService)
{
- yield return WaitForConditionOrTimeOut(() => m_ClientWasDisconnected);
- AssertOnTimeout("Client was not disconnected when it should have been!");
- Assert.True(m_ClientNetworkManager.DisconnectReason.Contains(ConnectionRequestMessage.InvalidSessionVersionMessage), "Client did not receive the correct invalid session version message!");
+ var authority = GetAuthorityNetworkManager();
+ authority.OnGetSessionConfig = () => new SessionConfig(k_ValidCMBVersion);
+ m_CanStartClients = true;
+ yield return StartServerAndClients();
}
- else
+
+ /*
+ * Test client being disconnected due to invalid session version
+ */
+ m_UseValidSessionVersion = false;
+
+ // Create and setup client to use invalid session config
+ var invalidClient = CreateNewClient();
+ invalidClient.OnClientDisconnectCallback += OnClientDisconnectCallback;
+ invalidClient.OnGetSessionConfig = GetInvalidSessionConfig;
+
+ // Start client and wait for disconnect callback
+ m_ClientWasDisconnected = false;
+ yield return StartClient(invalidClient);
+ Assert.True(invalidClient.IsListening);
+ yield return s_DefaultWaitForTick;
+
+ var timeoutHelper = new TimeoutHelper(30f);
+ yield return WaitForConditionOrTimeOut(() => !invalidClient.IsListening, timeoutHelper);
+ AssertOnTimeout("Client is still listening when it should have been disconnected!", timeoutHelper);
+
+ yield return WaitForConditionOrTimeOut(() => m_ClientWasDisconnected);
+ AssertOnTimeout("Client was not disconnected when it should have been!");
+
+ var expectedReason = m_UseCmbService ? "incompatible ngo c# package versions for feature" : ConnectionRequestMessage.InvalidSessionVersionMessage;
+ Assert.That(invalidClient.DisconnectReason, Does.Contain(expectedReason), $"Client did not receive the correct invalid session version message! Received: {invalidClient.DisconnectReason}");
+
+ // Clean up invalid client
+ invalidClient.OnClientDisconnectCallback -= OnClientDisconnectCallback;
+ yield return StopOneClient(invalidClient, true);
+
+ /*
+ * Test a later client with a valid version
+ * They should connect as normal
+ */
+ m_UseValidSessionVersion = true;
+
+ // Create and setup client to use invalid session config
+ var lateJoin = CreateNewClient();
+ lateJoin.OnClientDisconnectCallback += OnClientDisconnectCallback;
+ if (m_UseCmbService)
{
- Assert.False(m_ClientWasDisconnected, "Client was disconnected when it was expected to connect!");
- Assert.True(m_ClientNetworkManager.IsConnectedClient, "Client did not connect properly using the correct session version!");
+ lateJoin.OnGetSessionConfig = () => new SessionConfig(k_ValidCMBVersion);
}
- }
- ///
- /// Invoked at the end of each integration test pass.
- /// Primarily used to clean up for the next pass.
- ///
- protected override IEnumerator OnTearDown()
- {
- m_ClientNetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback;
- m_ClientNetworkManager = null;
- yield return base.OnTearDown();
+ // Start client and wait for disconnect callback
+ m_ClientWasDisconnected = false;
+ yield return StartClient(lateJoin);
+ yield return s_DefaultWaitForTick;
+
+ Assert.False(m_ClientWasDisconnected, "Client was disconnected when it was expected to connect!");
+ Assert.True(lateJoin.IsConnectedClient, "Client did not connect properly using the correct session version!");
+ Assert.That(GetAuthorityNetworkManager().ConnectedClientsIds, Has.Member(lateJoin.LocalClientId), "Newly joined client should be in connected list!");
+
+ // Clean up
+ lateJoin.OnClientDisconnectCallback -= OnClientDisconnectCallback;
}
}
}
diff --git a/testproject/.vsconfig b/testproject/.vsconfig
new file mode 100644
index 0000000000..f019fd0ad1
--- /dev/null
+++ b/testproject/.vsconfig
@@ -0,0 +1,6 @@
+{
+ "version": "1.0",
+ "components": [
+ "Microsoft.VisualStudio.Workload.ManagedGame"
+ ]
+}
diff --git a/testproject/Packages/packages-lock.json b/testproject/Packages/packages-lock.json
index a7e60d2362..675de94bf2 100644
--- a/testproject/Packages/packages-lock.json
+++ b/testproject/Packages/packages-lock.json
@@ -457,7 +457,8 @@
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.hierarchycore": "1.0.0"
+ "com.unity.modules.hierarchycore": "1.0.0",
+ "com.unity.modules.physics": "1.0.0"
}
},
"com.unity.modules.umbra": {
diff --git a/testproject/ProjectSettings/ProjectSettings.asset b/testproject/ProjectSettings/ProjectSettings.asset
index 5dafbe1407..3bb16ba357 100644
--- a/testproject/ProjectSettings/ProjectSettings.asset
+++ b/testproject/ProjectSettings/ProjectSettings.asset
@@ -70,6 +70,7 @@ PlayerSettings:
androidStartInFullscreen: 1
androidRenderOutsideSafeArea: 1
androidUseSwappy: 1
+ androidDisplayOptions: 1
androidBlitType: 0
androidResizeableActivity: 0
androidDefaultWindowWidth: 1920
@@ -86,6 +87,7 @@ PlayerSettings:
muteOtherAudioSources: 0
Prepare IOS For Recording: 0
Force IOS Speakers When Recording: 0
+ audioSpatialExperience: 0
deferSystemGesturesMode: 0
hideHomeButton: 0
submitAnalytics: 1
@@ -132,6 +134,7 @@ PlayerSettings:
switchNVNMaxPublicSamplerIDCount: 0
switchMaxWorkerMultiple: 8
switchNVNGraphicsFirmwareMemory: 32
+ switchGraphicsJobsSyncAfterKick: 1
vulkanNumSwapchainBuffers: 3
vulkanEnableSetSRGBWrite: 0
vulkanEnablePreTransform: 0
@@ -271,6 +274,9 @@ PlayerSettings:
AndroidBuildApkPerCpuArchitecture: 0
AndroidTVCompatibility: 0
AndroidIsGame: 1
+ androidAppCategory: 3
+ useAndroidAppCategory: 1
+ androidAppCategoryOther:
AndroidEnableTango: 0
androidEnableBanner: 1
androidUseLowAccuracyLocation: 0
@@ -442,6 +448,9 @@ PlayerSettings:
- m_BuildTarget: WebGLSupport
m_APIs: 0b000000
m_Automatic: 1
+ - m_BuildTarget: WindowsStandaloneSupport
+ m_APIs: 0200000012000000
+ m_Automatic: 0
m_BuildTargetVRSettings:
- m_BuildTarget: Standalone
m_Enabled: 0
@@ -723,12 +732,12 @@ PlayerSettings:
webGLMemoryLinearGrowthStep: 16
webGLMemoryGeometricGrowthStep: 0.2
webGLMemoryGeometricGrowthCap: 96
- webGLEnableWebGPU: 0
webGLPowerPreference: 2
webGLWebAssemblyTable: 0
webGLWebAssemblyBigInt: 0
webGLCloseOnQuit: 0
webWasm2023: 0
+ webEnableSubmoduleStrippingCompatibility: 0
scriptingDefineSymbols:
Standalone: UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
additionalCompilerArguments:
@@ -866,3 +875,5 @@ PlayerSettings:
insecureHttpOption: 0
androidVulkanDenyFilterList: []
androidVulkanAllowFilterList: []
+ androidVulkanDeviceFilterListAsset: {fileID: 0}
+ d3d12DeviceFilterListAsset: {fileID: 0}
diff --git a/testproject/ProjectSettings/ProjectVersion.txt b/testproject/ProjectSettings/ProjectVersion.txt
index 47df254537..c31f18a127 100644
--- a/testproject/ProjectSettings/ProjectVersion.txt
+++ b/testproject/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 6000.0.61f1
-m_EditorVersionWithRevision: 6000.0.61f1 (74a0adb02c31)
+m_EditorVersion: 6000.2.12f1
+m_EditorVersionWithRevision: 6000.2.12f1 (e89d5df0e333)