diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs
index d0606897ec..74f8abefb5 100644
--- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs
@@ -245,7 +245,7 @@ public ulong GetConfig(bool cache = true)
writer.WriteUInt32Packed(sortedEntry.Key);
}
}
-
+ writer.WriteBool(ConnectionApproval);
writer.WriteBool(EnableNetworkVariable);
writer.WriteBool(ForceSamePrefabs);
writer.WriteBool(EnableSceneManagement);
diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/InternalMessageHandler.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/InternalMessageHandler.cs
index 4ea516068c..d8318847a5 100644
--- a/com.unity.netcode.gameobjects/Runtime/Messaging/InternalMessageHandler.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Messaging/InternalMessageHandler.cs
@@ -31,7 +31,9 @@ public void HandleConnectionRequest(ulong clientId, Stream stream)
NetworkLog.LogWarning($"{nameof(NetworkConfig)} mismatch. The configuration between the server and client does not match");
}
- NetworkManager.DisconnectClient(clientId);
+ // Treat this similar to a client that is not approved (remove from pending and disconnect at transport layer)
+ NetworkManager.PendingClients.Remove(clientId);
+ NetworkManager.NetworkConfig.NetworkTransport.DisconnectRemoteClient(clientId);
return;
}
diff --git a/testproject/Assets/Scripts/ConnectionModeScript.cs b/testproject/Assets/Scripts/ConnectionModeScript.cs
index cb87892cec..3b225b53c7 100644
--- a/testproject/Assets/Scripts/ConnectionModeScript.cs
+++ b/testproject/Assets/Scripts/ConnectionModeScript.cs
@@ -95,4 +95,12 @@ public void OnStartClient()
m_ConnectionModeButtons.SetActive(false);
}
}
+
+ public void Reset()
+ {
+ if (NetworkManager.Singleton && !NetworkManager.Singleton.IsListening && m_ConnectionModeButtons)
+ {
+ m_ConnectionModeButtons.SetActive(true);
+ }
+ }
}
diff --git a/testproject/Assets/Tests/Manual/ConnectionApproval/ConnectionApprovalTest.unity b/testproject/Assets/Tests/Manual/ConnectionApproval/ConnectionApprovalTest.unity
index 6bcdf17aa8..591447cf8b 100644
--- a/testproject/Assets/Tests/Manual/ConnectionApproval/ConnectionApprovalTest.unity
+++ b/testproject/Assets/Tests/Manual/ConnectionApproval/ConnectionApprovalTest.unity
@@ -38,7 +38,7 @@ RenderSettings:
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
- m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1}
+ m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
@@ -143,7 +143,7 @@ PrefabInstance:
- target: {fileID: 2848221156307247792, guid: 3200770c16e3b2b4ebe7f604154faac7,
type: 3}
propertyPath: m_RootOrder
- value: 0
+ value: 1
objectReference: {fileID: 0}
- target: {fileID: 2848221156307247792, guid: 3200770c16e3b2b4ebe7f604154faac7,
type: 3}
@@ -300,7 +300,7 @@ RectTransform:
- {fileID: 1033031600}
- {fileID: 839387550}
m_Father: {fileID: 1907934187}
- m_RootOrder: 4
+ m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
@@ -420,6 +420,87 @@ MonoBehaviour:
m_ConnectionMessageToDisplay: {fileID: 1394268806}
m_SimulateFailure: {fileID: 344942972}
m_PlayerPrefabOverride: {fileID: 1493186929}
+ m_ClientDisconnectButton: {fileID: 1357994470}
+ m_ConnectionModeButtons: {fileID: 1931383346}
+--- !u!1 &609255385
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 609255386}
+ - component: {fileID: 609255388}
+ - component: {fileID: 609255387}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &609255386
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 609255385}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 1357994469}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &609255387
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 609255385}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 0.5058824, b: 0.003921569, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Disconnect
+--- !u!222 &609255388
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 609255385}
+ m_CullTransparentMesh: 1
--- !u!1001 &647084986
PrefabInstance:
m_ObjectHideFlags: 0
@@ -525,9 +606,6 @@ MonoBehaviour:
NetworkConfig:
ProtocolVersion: 0
NetworkTransport: {fileID: 697639107}
- RegisteredScenes:
- - ConnectionApprovalTest
- AllowRuntimeSceneChanges: 0
PlayerPrefab: {fileID: 4079352819444256614, guid: c16f03336b6104576a565ef79ad643c0,
type: 3}
NetworkPrefabs:
@@ -571,12 +649,7 @@ MonoBehaviour:
ConnectAddress: 127.0.0.1
ConnectPort: 7777
ServerListenPort: 7777
- ServerWebsocketListenPort: 8887
- SupportWebsocket: 0
Channels: []
- UseNetcodeRelay: 0
- NetcodeRelayAddress: 127.0.0.1
- NetcodeRelayPort: 8888
MessageSendMode: 0
--- !u!4 &697639108
Transform:
@@ -918,7 +991,7 @@ RectTransform:
m_LocalScale: {x: 0.7183, y: 0.7183, z: 0.7183}
m_Children: []
m_Father: {fileID: 1907934187}
- m_RootOrder: 1
+ m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 0}
m_AnchorMax: {x: 1, y: 0}
@@ -967,6 +1040,140 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1174150577}
m_CullTransparentMesh: 0
+--- !u!1 &1357994468
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1357994469}
+ - component: {fileID: 1357994472}
+ - component: {fileID: 1357994471}
+ - component: {fileID: 1357994470}
+ m_Layer: 5
+ m_Name: ClientDisconnect
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1357994469
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1357994468}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children:
+ - {fileID: 609255386}
+ m_Father: {fileID: 1907934187}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 0.5}
+ m_AnchorMax: {x: 0.5, y: 0.5}
+ m_AnchoredPosition: {x: 0, y: 260}
+ m_SizeDelta: {x: 160, y: 30}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1357994470
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1357994468}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 1357994471}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls:
+ - m_Target: {fileID: 606367640}
+ m_TargetAssemblyTypeName: TestProject.ManualTests.ConnectionApprovalComponent,
+ TestProject.ManualTests
+ m_MethodName: OnDisconnectClient
+ m_Mode: 1
+ m_Arguments:
+ m_ObjectArgument: {fileID: 0}
+ m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+ m_IntArgument: 0
+ m_FloatArgument: 0
+ m_StringArgument:
+ m_BoolArgument: 0
+ m_CallState: 2
+--- !u!114 &1357994471
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1357994468}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.2, g: 0.2, b: 0.2, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &1357994472
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1357994468}
+ m_CullTransparentMesh: 1
--- !u!1 &1394268804
GameObject:
m_ObjectHideFlags: 0
@@ -997,12 +1204,12 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 1907934187}
- m_RootOrder: 3
+ m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
- m_AnchoredPosition: {x: 0, y: 30}
- m_SizeDelta: {x: 200, y: 30}
+ m_AnchoredPosition: {x: 0, y: 109}
+ m_SizeDelta: {x: 400, y: 200}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1394268806
MonoBehaviour:
@@ -1026,12 +1233,12 @@ MonoBehaviour:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
- m_FontSize: 22
+ m_FontSize: 16
m_FontStyle: 1
- m_BestFit: 1
- m_MinSize: 2
+ m_BestFit: 0
+ m_MinSize: 0
m_MaxSize: 40
- m_Alignment: 4
+ m_Alignment: 7
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
@@ -1077,7 +1284,7 @@ RectTransform:
- {fileID: 1890361339}
- {fileID: 1760562150}
m_Father: {fileID: 1907934187}
- m_RootOrder: 5
+ m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
@@ -1152,7 +1359,7 @@ PrefabInstance:
- target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84,
type: 3}
propertyPath: m_RootOrder
- value: 2
+ value: 3
objectReference: {fileID: 0}
- target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84,
type: 3}
@@ -1754,6 +1961,7 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_Children:
+ - {fileID: 1357994469}
- {fileID: 274528836}
- {fileID: 1174150578}
- {fileID: 1569463775}
@@ -1768,3 +1976,15 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
+--- !u!114 &1931383346 stripped
+MonoBehaviour:
+ m_CorrespondingSourceObject: {fileID: 4850072633501053442, guid: d725b5588e1b956458798319e6541d84,
+ type: 3}
+ m_PrefabInstance: {fileID: 1569463774}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 50623966c8d88ab40982cc2b0e4c2d2e, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
diff --git a/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs b/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs
index 8fd734007a..7ba7fefc5e 100644
--- a/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs
+++ b/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs
@@ -1,4 +1,5 @@
using System.Collections;
+using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
@@ -6,6 +7,9 @@
namespace TestProject.ManualTests
{
+ ///
+ /// This component demonstrates how to use the Netcode for GameObjects connection approval feature
+ ///
public class ConnectionApprovalComponent : NetworkBehaviour
{
[SerializeField]
@@ -23,11 +27,22 @@ public class ConnectionApprovalComponent : NetworkBehaviour
[SerializeField]
private Toggle m_PlayerPrefabOverride;
+ [SerializeField]
+ private Button m_ClientDisconnectButton;
+ [SerializeField]
+ private ConnectionModeScript m_ConnectionModeButtons;
- private void Start()
+ private class MessageEntry
{
+ public string Message;
+ public float TimeOut;
+ }
+ private List m_Messages = new List();
+
+ private void Start()
+ {
if (m_PlayerPrefabOverride)
{
m_PlayerPrefabOverride.gameObject.SetActive(false);
@@ -43,6 +58,11 @@ private void Start()
m_ConnectionMessageToDisplay.gameObject.SetActive(false);
}
+ if (m_ClientDisconnectButton)
+ {
+ m_ClientDisconnectButton.gameObject.SetActive(false);
+ }
+
if (NetworkManager != null && NetworkManager.NetworkConfig.ConnectionApproval)
{
NetworkManager.ConnectionApprovalCallback += ConnectionApprovalCallback;
@@ -55,11 +75,50 @@ private void Start()
{
Debug.LogError($"You need to set the {nameof(m_ApprovalToken)} to a value first!");
}
+ }
+
+ NetworkManager.OnClientDisconnectCallback += NetworkManager_OnClientDisconnectCallback;
+ NetworkManager.OnClientConnectedCallback += NetworkManager_OnClientConnectedCallback;
+ }
- NetworkManager.OnClientDisconnectCallback += NetworkManager_OnClientDisconnectCallback;
+ ///
+ /// When a client connects we display a message and if we are not the server
+ /// we display a disconnect button for ease of testing.
+ ///
+ private void NetworkManager_OnClientConnectedCallback(ulong clientId)
+ {
+ if (m_ClientDisconnectButton)
+ {
+ m_ClientDisconnectButton.gameObject.SetActive(!IsServer);
+ }
+
+ AddNewMessage($"Client {clientId} was connected.");
+ }
+
+ ///
+ /// When a client is disconnected we display a message and if we
+ /// are not listening and not the server we reset the UI Connection
+ /// mode buttons
+ ///
+ private void NetworkManager_OnClientDisconnectCallback(ulong clientId)
+ {
+
+ AddNewMessage($"Client {clientId} was disconnected!");
+
+ if (!NetworkManager.IsListening && !NetworkManager.IsServer)
+ {
+ m_ConnectionModeButtons.Reset();
+ }
+
+ if (m_ClientDisconnectButton)
+ {
+ m_ClientDisconnectButton.gameObject.SetActive(false);
}
}
+ ///
+ /// Just display certain check boxes only when we are in a network session
+ ///
public override void OnNetworkSpawn()
{
if (m_SimulateFailure)
@@ -73,56 +132,108 @@ public override void OnNetworkSpawn()
}
}
- private void NetworkManager_OnClientDisconnectCallback(ulong obj)
+ ///
+ /// Used for the client when the disconnect button is pressed
+ ///
+ public void OnDisconnectClient()
{
- Debug.Log($"Client {obj} connected!");
+ if ( NetworkManager != null && NetworkManager.IsListening && !NetworkManager.IsServer)
+ {
+ NetworkManager.Shutdown();
+ m_ConnectionModeButtons.Reset();
+ if (m_ClientDisconnectButton)
+ {
+ m_ClientDisconnectButton.gameObject.SetActive(false);
+ }
+ }
}
- private void ConnectionApprovalCallback(byte[] arg1, ulong arg2, NetworkManager.ConnectionApprovedDelegate arg3)
+ ///
+ /// Invoked only on the server, this will handle the various connection approval combinations
+ ///
+ /// key or password to get approval
+ /// client identifier being approved
+ /// callback that should be invoked once it is determined if client is approved or not
+ private void ConnectionApprovalCallback(byte[] dataToken, ulong clientId, NetworkManager.ConnectionApprovedDelegate aprovalCallback)
{
- string approvalToken = Encoding.ASCII.GetString(arg1);
+ string approvalToken = Encoding.ASCII.GetString(dataToken);
var isTokenValid = approvalToken == m_ApprovalToken;
- if (m_SimulateFailure && m_SimulateFailure.isOn && IsServer && arg2 != NetworkManager.LocalClientId)
+ if (m_SimulateFailure && m_SimulateFailure.isOn && IsServer && clientId != NetworkManager.LocalClientId)
{
isTokenValid = false;
}
- if (isTokenValid)
+ if (m_GlobalObjectIdHashOverride != 0 && m_PlayerPrefabOverride && m_PlayerPrefabOverride.isOn)
{
- if (m_GlobalObjectIdHashOverride != 0 && m_PlayerPrefabOverride && m_PlayerPrefabOverride.isOn)
- {
- arg3.Invoke(true, m_GlobalObjectIdHashOverride, true, null, null);
- }
- else
- {
- arg3.Invoke(true, null, true, null, null);
- }
+ aprovalCallback.Invoke(true, m_GlobalObjectIdHashOverride, isTokenValid, null, null);
}
else
{
- NetworkManager.DisconnectClient(arg2);
- Debug.LogWarning($"User id {arg2} was disconnected due to failed connection approval!");
+ aprovalCallback.Invoke(true, null, isTokenValid, null, null);
}
- if (m_ConnectionMessageToDisplay && arg2 != NetworkManager.LocalClientId)
+
+ if (m_ConnectionMessageToDisplay)
{
if (isTokenValid)
{
- m_ConnectionMessageToDisplay.text = $"Client id {arg2} is authorized!";
+ AddNewMessage($"Client id {clientId} is authorized!");
}
else
{
- m_ConnectionMessageToDisplay.text = $"Client id {arg2} failed authorization!";
+ AddNewMessage($"Client id {clientId} failed authorization!");
}
m_ConnectionMessageToDisplay.gameObject.SetActive(true);
- StartCoroutine(WaitToHideConnectionText());
}
}
- private IEnumerator WaitToHideConnectionText()
+ ///
+ /// Adds a new message to be displayed and if our display coroutine is not running start it.
+ ///
+ /// message to add to the list of messages to be displayed
+ private void AddNewMessage(string msg)
{
- yield return new WaitForSeconds(5);
+ m_Messages.Add(new MessageEntry() { Message = msg, TimeOut = Time.realtimeSinceStartup + 8.0f });
+ if (!m_ConnectionMessageToDisplay.gameObject.activeInHierarchy)
+ {
+ StartCoroutine(DisplayMessatesUntilEmpty());
+ if (m_ConnectionMessageToDisplay)
+ {
+ m_ConnectionMessageToDisplay.gameObject.SetActive(true);
+ }
+ }
+ }
+
+ ///
+ /// Coroutine that displays messages until there are no more messages to be displayed.
+ ///
+ ///
+ private IEnumerator DisplayMessatesUntilEmpty()
+ {
+ var messagesToRemove = new List();
+ while (m_Messages.Count > 0)
+ {
+ m_ConnectionMessageToDisplay.text = string.Empty;
+ foreach (var message in m_Messages)
+ {
+ if (message.TimeOut > Time.realtimeSinceStartup)
+ {
+ m_ConnectionMessageToDisplay.text += message.Message + "\n";
+ }
+ else
+ {
+ messagesToRemove.Add(message);
+ }
+ }
+ yield return new WaitForSeconds(0.5f);
+ foreach (var message in messagesToRemove)
+ {
+ m_Messages.Remove(message);
+ }
+ messagesToRemove.Clear();
+ }
+
if (m_ConnectionMessageToDisplay)
{
m_ConnectionMessageToDisplay.gameObject.SetActive(false);
diff --git a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs
index f506dcb425..d96c970b6d 100644
--- a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs
+++ b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs
@@ -241,6 +241,50 @@ private void Server_OnClientConnectedCallback(ulong clientId)
m_ServerClientConnectedInvocations++;
}
+
+ private int m_ServerClientDisconnectedInvocations;
+
+ ///
+ /// Tests that clients are disconnected when their ConnectionApproval setting is mismatched with the host-server
+ /// and when scene management is enabled and disabled
+ ///
+ ///
+ [UnityTest]
+ public IEnumerator ConnectionApprovalMismatchTest([Values(true, false)] bool enableSceneManagement, [Values(true,false)] bool connectionApproval)
+ {
+ m_ServerClientDisconnectedInvocations = 0;
+
+ // Create Host and (numClients) clients
+ Assert.True(MultiInstanceHelpers.Create(3, out NetworkManager server, out NetworkManager[] clients));
+
+ server.NetworkConfig.EnableSceneManagement = enableSceneManagement;
+ server.OnClientDisconnectCallback += Server_OnClientDisconnectedCallback;
+ server.NetworkConfig.ConnectionApproval = connectionApproval;
+
+ foreach (var client in clients)
+ {
+ client.NetworkConfig.EnableSceneManagement = enableSceneManagement;
+ client.NetworkConfig.ConnectionApproval = !connectionApproval;
+ }
+
+ // Start the instances
+ if (!MultiInstanceHelpers.Start(true, server, clients))
+ {
+ Assert.Fail("Failed to start instances");
+ }
+
+ var nextFrameNumber = Time.frameCount + 5;
+ yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
+
+ Assert.True(m_ServerClientDisconnectedInvocations == 3);
+ }
+
+ private void Server_OnClientDisconnectedCallback(ulong clientId)
+ {
+ m_ServerClientDisconnectedInvocations++;
+ }
+
+
[TearDown]
public void TearDown()
{