From 4d25e83fd6c1163e840231ffa36eb915986f8269 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 2 Sep 2021 19:32:20 -0500 Subject: [PATCH 1/5] refactor fix This is just an update on the connection approval manual test to verify that users receive the appropriate messages when a client is approved or not approved. Server will know if the client is approved or not based on how it processed the NetworkConfig.ConnectionData sent to it and clients will just be notified they were disconnected. --- .../Assets/Scripts/ConnectionModeScript.cs | 8 + .../ConnectionApprovalTest.unity | 262 ++++++++++++++++-- .../Scripts/ConnectionApprovalComponent.cs | 122 ++++++-- 3 files changed, 350 insertions(+), 42 deletions(-) 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..0d80cda4e4 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; @@ -23,11 +24,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 +55,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; @@ -57,6 +74,33 @@ private void Start() } NetworkManager.OnClientDisconnectCallback += NetworkManager_OnClientDisconnectCallback; + NetworkManager.OnClientConnectedCallback += NetworkManager_OnClientConnectedCallback; + } + } + + private void NetworkManager_OnClientConnectedCallback(ulong obj) + { + if (m_ClientDisconnectButton) + { + m_ClientDisconnectButton.gameObject.SetActive(!IsServer); + } + + AddNewMessage($"Client {obj} was connected."); + } + + private void NetworkManager_OnClientDisconnectCallback(ulong obj) + { + + AddNewMessage($"Client {obj} was disconnected!"); + + if (!NetworkManager.IsListening && !NetworkManager.IsServer) + { + m_ConnectionModeButtons.Reset(); + } + + if (m_ClientDisconnectButton) + { + m_ClientDisconnectButton.gameObject.SetActive(false); } } @@ -73,46 +117,47 @@ public override void OnNetworkSpawn() } } - private void NetworkManager_OnClientDisconnectCallback(ulong obj) + 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) + 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); @@ -120,9 +165,44 @@ private void ConnectionApprovalCallback(byte[] arg1, ulong arg2, NetworkManager. } } + private void AddNewMessage(string msg) + { + m_Messages.Add(new MessageEntry() { Message = msg, TimeOut = Time.realtimeSinceStartup + 8.0f }); + if (!m_ConnectionMessageToDisplay.gameObject.activeInHierarchy) + { + StartCoroutine(WaitToHideConnectionText()); + if (m_ConnectionMessageToDisplay) + { + m_ConnectionMessageToDisplay.gameObject.SetActive(true); + } + } + } + private IEnumerator WaitToHideConnectionText() { - yield return new WaitForSeconds(5); + 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); From 1a26f626cb8610a7e920d7440f8a0c2750833ad1 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 2 Sep 2021 19:39:53 -0500 Subject: [PATCH 2/5] refactor and style added some additional comments as well as refactored a little bit of code and renamed some methods and parameters for clarity --- .../Scripts/ConnectionApprovalComponent.cs | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs b/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs index 0d80cda4e4..55260041a2 100644 --- a/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs +++ b/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs @@ -7,6 +7,9 @@ namespace TestProject.ManualTests { + /// + /// This component demonstrates how to use the Netcode for GameObjects connection approval feature + /// public class ConnectionApprovalComponent : NetworkBehaviour { [SerializeField] @@ -78,20 +81,29 @@ private void Start() } } - private void NetworkManager_OnClientConnectedCallback(ulong obj) + /// + /// 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 {obj} was connected."); + AddNewMessage($"Client {clientId} was connected."); } - private void NetworkManager_OnClientDisconnectCallback(ulong obj) + /// + /// 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 {obj} was disconnected!"); + AddNewMessage($"Client {clientId} was disconnected!"); if (!NetworkManager.IsListening && !NetworkManager.IsServer) { @@ -104,6 +116,9 @@ private void NetworkManager_OnClientDisconnectCallback(ulong obj) } } + /// + /// Just display certain check boxes only when we are in a network session + /// public override void OnNetworkSpawn() { if (m_SimulateFailure) @@ -117,6 +132,9 @@ public override void OnNetworkSpawn() } } + /// + /// Used for the client when the disconnect button is pressed + /// public void OnDisconnectClient() { if ( NetworkManager != null && NetworkManager.IsListening && !NetworkManager.IsServer) @@ -130,6 +148,12 @@ public void OnDisconnectClient() } } + /// + /// 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(dataToken); @@ -161,16 +185,19 @@ private void ConnectionApprovalCallback(byte[] dataToken, ulong clientId, Networ } m_ConnectionMessageToDisplay.gameObject.SetActive(true); - StartCoroutine(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) { m_Messages.Add(new MessageEntry() { Message = msg, TimeOut = Time.realtimeSinceStartup + 8.0f }); if (!m_ConnectionMessageToDisplay.gameObject.activeInHierarchy) { - StartCoroutine(WaitToHideConnectionText()); + StartCoroutine(DisplayMessatesUntilEmpty()); if (m_ConnectionMessageToDisplay) { m_ConnectionMessageToDisplay.gameObject.SetActive(true); @@ -178,7 +205,11 @@ private void AddNewMessage(string msg) } } - private IEnumerator WaitToHideConnectionText() + /// + /// 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) From 7059075e032ead4dcca598be53cc36bc528f5a9d Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 2 Sep 2021 20:02:57 -0500 Subject: [PATCH 3/5] fix When a client or server have mismatched connection approval NetworkManager settings this fix will make sure to disconnect the client as well as it will properly detect the mismatched NetworkConfigs and log a message to the console on the server/host so users know why the client was disconnected. Made an adjustment to the connection approval component so this scenario can be tested. --- .../Runtime/Configuration/NetworkConfig.cs | 2 +- .../Runtime/Messaging/InternalMessageHandler.cs | 4 +++- .../Tests/Manual/Scripts/ConnectionApprovalComponent.cs | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) 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 52cb61f30a..16cbc52ff0 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/Tests/Manual/Scripts/ConnectionApprovalComponent.cs b/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs index 55260041a2..7ba7fefc5e 100644 --- a/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs +++ b/testproject/Assets/Tests/Manual/Scripts/ConnectionApprovalComponent.cs @@ -75,10 +75,10 @@ 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; + NetworkManager.OnClientConnectedCallback += NetworkManager_OnClientConnectedCallback; } /// From bcf7cd0ff13ee35d376f3f5bd6c7fe79019bf4d0 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 2 Sep 2021 20:39:40 -0500 Subject: [PATCH 4/5] test Adding a unit test which verifies clients are disconnected when there is a connection approval setting mismatch between client and server when scene management is enabled and disabled. --- .../Runtime/MultiClientConnectionApproval.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs index f506dcb425..57c336b56c 100644 --- a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs +++ b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs @@ -241,6 +241,53 @@ private void Server_OnClientConnectedCallback(ulong clientId) m_ServerClientConnectedInvocations++; } + + private int m_ServerClientDisconnectedInvocations; + + private int m_ClientDisconnectedInvocation; + + /// + /// 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; + m_ClientDisconnectedInvocation = 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() { From 0cf34a9ff38d86c32a5d928c27e49ac6bcb0e3f3 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 2 Sep 2021 20:43:01 -0500 Subject: [PATCH 5/5] refactor Removing unused property. --- .../Assets/Tests/Runtime/MultiClientConnectionApproval.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs index 57c336b56c..d96c970b6d 100644 --- a/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs +++ b/testproject/Assets/Tests/Runtime/MultiClientConnectionApproval.cs @@ -244,8 +244,6 @@ private void Server_OnClientConnectedCallback(ulong clientId) private int m_ServerClientDisconnectedInvocations; - private int m_ClientDisconnectedInvocation; - /// /// Tests that clients are disconnected when their ConnectionApproval setting is mismatched with the host-server /// and when scene management is enabled and disabled @@ -255,7 +253,6 @@ private void Server_OnClientConnectedCallback(ulong clientId) public IEnumerator ConnectionApprovalMismatchTest([Values(true, false)] bool enableSceneManagement, [Values(true,false)] bool connectionApproval) { m_ServerClientDisconnectedInvocations = 0; - m_ClientDisconnectedInvocation = 0; // Create Host and (numClients) clients Assert.True(MultiInstanceHelpers.Create(3, out NetworkManager server, out NetworkManager[] clients));