-
Notifications
You must be signed in to change notification settings - Fork 461
fix: preventing issues with game code registering multiple ConnectionApprovalCallbacks [MTT-3496]
#1972
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: preventing issues with game code registering multiple ConnectionApprovalCallbacks [MTT-3496]
#1972
Changes from 1 commit
5e1330b
3a935c0
8d70bdb
a2e2593
22a10f0
92b5fc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -358,21 +358,54 @@ public IReadOnlyList<ulong> ConnectedClientsIds | |
| public event Action OnServerStarted = null; | ||
|
|
||
| /// <summary> | ||
| /// Delegate type called when connection has been approved. This only has to be set on the server. | ||
| /// Connection Approval Result | ||
| /// </summary> | ||
| /// <param name="createPlayerObject">If true, a player object will be created. Otherwise the client will have no object.</param> | ||
| /// <param name="playerPrefabHash">The prefabHash to use for the client. If createPlayerObject is false, this is ignored. If playerPrefabHash is null, the default player prefab is used.</param> | ||
| /// <param name="approved">Whether or not the client was approved</param> | ||
| /// <param name="position">The position to spawn the client at. If null, the prefab position is used.</param> | ||
| /// <param name="rotation">The rotation to spawn the client with. If null, the prefab position is used.</param> | ||
| public delegate void ConnectionApprovedDelegate(bool createPlayerObject, uint? playerPrefabHash, bool approved, Vector3? position, Quaternion? rotation); | ||
| /// <param name="Approved">Whether or not the client was approved</param> | ||
| /// <param name="CreatePlayerObject">If true, a player object will be created. Otherwise the client will have no object.</param> | ||
| /// <param name="PlayerPrefabHash">The prefabHash to use for the client. If createPlayerObject is false, this is ignored. If playerPrefabHash is null, the default player prefab is used.</param> | ||
| /// <param name="Position">The position to spawn the client at. If null, the prefab position is used.</param> | ||
| /// <param name="Rotation">The rotation to spawn the client with. If null, the prefab position is used.</param> | ||
| public struct ConnectionApprovalResult | ||
| { | ||
| public bool Approved; | ||
| public bool CreatePlayerObject; | ||
| public uint? PlayerPrefabHash; | ||
| public Vector3? Position; | ||
| public Quaternion? Rotation; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Connection Approval Request | ||
| /// </summary> | ||
| /// <param name="Payload">The connection data payload</param> | ||
| /// <param name="ClientNetworkId">The Client Network Id of the client we are about to approve</param> | ||
| public struct ConnectionApprovalRequest | ||
| { | ||
| public byte[] Payload; | ||
| public ulong ClientNetworkId; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The callback to invoke during connection approval | ||
| /// The callback to invoke during connection approval. Allows client code to decide to allow a client in or not | ||
| /// </summary> | ||
| public event Action<byte[], ulong, ConnectionApprovedDelegate> ConnectionApprovalCallback = null; | ||
| public Func<ConnectionApprovalRequest, ConnectionApprovalResult> ConnectionApprovalHandler | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
| { | ||
| get => m_ConnectionApprovalHandler; | ||
| set | ||
| { | ||
| if (value != null && value.GetInvocationList().Length > 1) | ||
| { | ||
| Debug.LogError( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. throw an
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/instead/additionally ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. an unhandled exception is eventually an error/exception log in Unity console anyway
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so still, instead
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I mean to say is that
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, good, we should be good to go now. Please let me know if I missed any bits or parts. |
||
| $"Only one connection approval handler is supported in {nameof(m_ConnectionApprovalHandler)}. Rejecting further adds."); | ||
| } | ||
| else | ||
| { | ||
| m_ConnectionApprovalHandler = value; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| internal void InvokeConnectionApproval(byte[] payload, ulong clientId, ConnectionApprovedDelegate action) => ConnectionApprovalCallback?.Invoke(payload, clientId, action); | ||
| private Func<ConnectionApprovalRequest, ConnectionApprovalResult> m_ConnectionApprovalHandler; | ||
|
|
||
| /// <summary> | ||
| /// The current NetworkConfig | ||
|
|
@@ -970,27 +1003,28 @@ public bool StartHost() | |
| IsClient = true; | ||
| IsListening = true; | ||
|
|
||
| if (NetworkConfig.ConnectionApproval) | ||
| if (NetworkConfig.ConnectionApproval && ConnectionApprovalHandler != null) | ||
| { | ||
| InvokeConnectionApproval(NetworkConfig.ConnectionData, ServerClientId, | ||
| (createPlayerObject, playerPrefabHash, approved, position, rotation) => | ||
| var decision = ConnectionApprovalHandler(new ConnectionApprovalRequest { Payload = NetworkConfig.ConnectionData, ClientNetworkId = ServerClientId }); | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
|
|
||
| if (!decision.Approved) | ||
| { | ||
| if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) | ||
| { | ||
| // You cannot decline the local server. Force approved to true | ||
| if (!approved) | ||
| { | ||
| if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) | ||
| { | ||
| NetworkLog.LogWarning( | ||
| "You cannot decline the host connection. The connection was automatically approved."); | ||
| } | ||
| } | ||
| NetworkLog.LogWarning( | ||
| "You cannot decline the host connection. The connection was automatically approved."); | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
|
|
||
| HandleApproval(ServerClientId, createPlayerObject, playerPrefabHash, true, position, rotation); | ||
| }); | ||
| decision.Approved = true; | ||
| HandleApproval(ServerClientId, decision); | ||
| } | ||
| else | ||
| { | ||
| HandleApproval(ServerClientId, NetworkConfig.PlayerPrefab != null, null, true, null, null); | ||
| var decision = new ConnectionApprovalResult(); | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
| decision.Approved = true; | ||
| decision.CreatePlayerObject = NetworkConfig.PlayerPrefab != null; | ||
| HandleApproval(ServerClientId, decision); | ||
| } | ||
|
|
||
| SpawnManager.ServerSpawnSceneObjectsOnStartSweep(); | ||
|
|
@@ -1023,7 +1057,7 @@ private bool CanStart(StartType type) | |
| // Clients don't invoke the ConnectionApprovalCallback | ||
| if (NetworkConfig.ConnectionApproval && type != StartType.Client) | ||
| { | ||
| if (ConnectionApprovalCallback == null) | ||
| if (ConnectionApprovalHandler == null) | ||
| { | ||
| if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) | ||
| { | ||
|
|
@@ -1033,7 +1067,7 @@ private bool CanStart(StartType type) | |
| } | ||
| } | ||
|
|
||
| if (ConnectionApprovalCallback != null) | ||
| if (ConnectionApprovalHandler != null) | ||
| { | ||
| if (!NetworkConfig.ConnectionApproval) | ||
| { | ||
|
|
@@ -1819,14 +1853,10 @@ private void SyncTime() | |
| /// Server Side: Handles the approval of a client | ||
| /// </summary> | ||
| /// <param name="ownerClientId">client being approved</param> | ||
| /// <param name="createPlayerObject">whether we want to create a player or not</param> | ||
| /// <param name="playerPrefabHash">the GlobalObjectIdHash value for the Network Prefab to create as the player</param> | ||
| /// <param name="approved">Is the player approved or not?</param> | ||
| /// <param name="position">Used when createPlayerObject is true, position of the player when spawned </param> | ||
| /// <param name="rotation">Used when createPlayerObject is true, rotation of the player when spawned</param> | ||
| internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? playerPrefabHash, bool approved, Vector3? position, Quaternion? rotation) | ||
| /// <param name="decision">the decision to allow the player in or not, with its parameters</param> | ||
| internal void HandleApproval(ulong ownerClientId, ConnectionApprovalResult decision) | ||
|
jeffreyrainy marked this conversation as resolved.
Outdated
|
||
| { | ||
| if (approved) | ||
| if (decision.Approved) | ||
| { | ||
| // Inform new client it got approved | ||
| PendingClients.Remove(ownerClientId); | ||
|
|
@@ -1836,10 +1866,14 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? | |
| m_ConnectedClientsList.Add(client); | ||
| m_ConnectedClientIds.Add(client.ClientId); | ||
|
|
||
| if (createPlayerObject) | ||
| if (decision.CreatePlayerObject) | ||
| { | ||
| var networkObject = SpawnManager.CreateLocalNetworkObject(false, playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash, ownerClientId, null, null, position, rotation); | ||
| SpawnManager.SpawnNetworkObjectLocally(networkObject, SpawnManager.GetNetworkObjectId(), false, true, ownerClientId, false); | ||
| var networkObject = SpawnManager.CreateLocalNetworkObject(false, | ||
| decision.PlayerPrefabHash ?? | ||
| NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash, ownerClientId, | ||
| null, null, decision.Position, decision.Rotation); | ||
| SpawnManager.SpawnNetworkObjectLocally(networkObject, SpawnManager.GetNetworkObjectId(), false, | ||
| true, ownerClientId, false); | ||
|
|
||
| ConnectedClients[ownerClientId].PlayerObject = networkObject; | ||
| } | ||
|
|
@@ -1879,13 +1913,13 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? | |
| InvokeOnClientConnectedCallback(ownerClientId); | ||
| } | ||
|
|
||
| if (!createPlayerObject || (playerPrefabHash == null && NetworkConfig.PlayerPrefab == null)) | ||
| if (!decision.CreatePlayerObject || (decision.PlayerPrefabHash == null && NetworkConfig.PlayerPrefab == null)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Separating this into a contained function call for potential further future separation of when this notification is sent. | ||
| ApprovedPlayerSpawn(ownerClientId, playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash); | ||
| ApprovedPlayerSpawn(ownerClientId, decision.PlayerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash); | ||
| } | ||
| else | ||
| { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.