From b139fb564a6ee0543e4f385e8bc85481e93b4991 Mon Sep 17 00:00:00 2001 From: Fernando Cortez Date: Mon, 26 Sep 2022 15:43:26 -0400 Subject: [PATCH 1/2] fix: shield charge trigger reset & reuse cooldown populated [MTT-4100] (#742) * reuse time added to shield buff action * resetting charge trigger when stopped * changelog addition --- Assets/GameData/Action/Tank/TankShieldBuff.asset | 4 ++-- .../Gameplay/Action/ConcreteActions/ChargedShieldAction.cs | 2 ++ CHANGELOG.md | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Assets/GameData/Action/Tank/TankShieldBuff.asset b/Assets/GameData/Action/Tank/TankShieldBuff.asset index ba10043a6..eea0fd96f 100644 --- a/Assets/GameData/Action/Tank/TankShieldBuff.asset +++ b/Assets/GameData/Action/Tank/TankShieldBuff.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c99ae90cda110563ebb4407b6b96e8922fd07b0ba644605b749e7c88a77fe0c8 -size 1416 +oid sha256:9d624e9a34d75bc544bd662ffd2d3404d4d8c4367d40bf2feb3aa0ac9497668d +size 1444 diff --git a/Assets/Scripts/Gameplay/Action/ConcreteActions/ChargedShieldAction.cs b/Assets/Scripts/Gameplay/Action/ConcreteActions/ChargedShieldAction.cs index a4d3ad69e..0146305c3 100644 --- a/Assets/Scripts/Gameplay/Action/ConcreteActions/ChargedShieldAction.cs +++ b/Assets/Scripts/Gameplay/Action/ConcreteActions/ChargedShieldAction.cs @@ -149,6 +149,8 @@ private void StopChargingUp(ServerCharacter parent) parent.serverAnimationHandler.NetworkAnimator.SetTrigger(Config.Anim2); + parent.serverAnimationHandler.NetworkAnimator.ResetTrigger(Config.Anim); + //tell the animator controller to enter "invincibility mode" (where we don't flinch from damage) if (Mathf.Approximately(GetPercentChargedUp(), 1f)) { diff --git a/CHANGELOG.md b/CHANGELOG.md index 65884afc1..46c088585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Additional documentation and release notes are available at [Multiplayer Documen * Some NetworkBehaviours are disabled instead of being destroyed (#718) - This preserves the index order for NetworkBehaviours between server and clients, resulting in no indexing issue for sending/receiving RPCs. * Scene Bootstrapper: future proofing bootstrap scene so we don't rely on Startup's path. MTT-3707. (#735) * Better instructions for host listen IP. (#738) Most useful cases are usually 127.0.0.1 and 0.0.0.0. +* Tank's shield charge animation not getting stuck due to multiple invocations. (#742) ## [v1.3.0-pre] - 2022-06-23 From e484dc64ad9c1d0f2e41d0d87ae3929f45d31f43 Mon Sep 17 00:00:00 2001 From: LPLafontaineB Date: Mon, 26 Sep 2022 17:40:03 -0400 Subject: [PATCH 2/2] feat: upgrade lobby [MTT-3962][MTT-4105][MTT-4052] (#737) * Upgrading to Lobby version 1.0.3 * replacing usage of deprecated Lobbies class with LobbyService * Using the reconnecting API to reconnect to a lobby instead of leaving it and re-joining * Adding attempts with cooldowns between them for reconnecting to lobby * simplifying lobby reconnect flow and adding comments * Adding changelog entry * fixing relay allocationId not properly sent to lobby --- .../ConnectionState/ClientConnectingState.cs | 4 +- .../ClientReconnectingState.cs | 37 ++++++++++++++----- .../ConnectionState/HostingState.cs | 5 --- .../Lobbies/LobbyAPIInterface.cs | 29 ++++++++------- .../Lobbies/LobbyServiceFacade.cs | 5 +++ CHANGELOG.md | 2 + .../Utilities/Net/UnityRelayUtilities.cs | 4 +- Packages/manifest.json | 2 +- Packages/packages-lock.json | 8 ++-- 9 files changed, 60 insertions(+), 36 deletions(-) diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs index beb17ce44..638a3d719 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs @@ -78,10 +78,10 @@ async Task JoinRelayServerAsync() try { - var (ipv4Address, port, allocationIdBytes, connectionData, hostConnectionData, key) = + var (ipv4Address, port, allocationIdBytes, allocationId, connectionData, hostConnectionData, key) = await UnityRelayUtilities.JoinRelayServerFromJoinCode(m_LocalLobby.RelayJoinCode); - await m_LobbyServiceFacade.UpdatePlayerRelayInfoAsync(allocationIdBytes.ToString(), m_LocalLobby.RelayJoinCode); + await m_LobbyServiceFacade.UpdatePlayerRelayInfoAsync(allocationId.ToString(), m_LocalLobby.RelayJoinCode); var utp = (UnityTransport)m_ConnectionManager.NetworkManager.NetworkConfig.NetworkTransport; utp.SetClientRelayData(ipv4Address, port, allocationIdBytes, key, connectionData, hostConnectionData, isSecure: true); } diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs index 115bcc0b0..8dd2d46f7 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs @@ -21,6 +21,8 @@ class ClientReconnectingState : ClientConnectingState string m_LobbyCode = ""; int m_NbAttempts; + const float k_TimeBetweenAttempts = 5; + public override void Enter() { m_LobbyCode = m_LobbyServiceFacade.CurrentUnityLobby != null ? m_LobbyServiceFacade.CurrentUnityLobby.LobbyCode : ""; @@ -71,6 +73,15 @@ public override void OnDisconnectReasonReceived(ConnectStatus disconnectReason) IEnumerator ReconnectCoroutine() { + // If not on first attempt, wait some time before trying again, so that if the issue causing the disconnect + // is temporary, it has time to fix itself before we try again. Here we are using a simple fixed cooldown + // but we could want to use exponential backoff instead, to wait a longer time between each failed attempt. + // See https://en.wikipedia.org/wiki/Exponential_backoff + if (m_NbAttempts > 0) + { + yield return new WaitForSeconds(k_TimeBetweenAttempts); + } + Debug.Log("Lost connection to host, trying to reconnect..."); m_ConnectionManager.NetworkManager.Shutdown(); @@ -79,26 +90,34 @@ IEnumerator ReconnectCoroutine() Debug.Log($"Reconnecting attempt {m_NbAttempts + 1}/{m_ConnectionManager.NbReconnectAttempts}..."); m_ReconnectMessagePublisher.Publish(new ReconnectMessage(m_NbAttempts, m_ConnectionManager.NbReconnectAttempts)); m_NbAttempts++; - if (!string.IsNullOrEmpty(m_LobbyCode)) + if (!string.IsNullOrEmpty(m_LobbyCode)) // Attempting to reconnect to lobby. { - var leavingLobby = m_LobbyServiceFacade.EndTracking(); - yield return new WaitUntil(() => leavingLobby.IsCompleted); - var joiningLobby = m_LobbyServiceFacade.TryJoinLobbyAsync("", m_LobbyCode); - yield return new WaitUntil(() => joiningLobby.IsCompleted); - if (joiningLobby.Result.Success) + // When using Lobby with Relay, if a user is disconnected from the Relay server, the server will notify + // the Lobby service and mark the user as disconnected, but will not remove them from the lobby. They + // then have some time to attempt to reconnect (defined by the "Disconnect removal time" parameter on + // the dashboard), after which they will be removed from the lobby completely. + // See https://docs.unity.com/lobby/reconnect-to-lobby.html + var reconnectingToLobby = m_LobbyServiceFacade.ReconnectToLobbyAsync(m_LocalLobby?.LobbyID); + yield return new WaitUntil(() => reconnectingToLobby.IsCompleted); + + // If succeeded, attempt to connect to Relay + if (!reconnectingToLobby.IsFaulted && reconnectingToLobby.Result != null) { - m_LobbyServiceFacade.SetRemoteLobby(joiningLobby.Result.Lobby); + // If this fails, the OnClientDisconnect callback will be invoked by Netcode var connectingToRelay = ConnectClientAsync(); yield return new WaitUntil(() => connectingToRelay.IsCompleted); } else { - Debug.Log("Failed joining lobby."); + Debug.Log("Failed reconnecting to lobby."); + // Calling OnClientDisconnect to mark this attempt as failed and either start a new one or give up + // and return to the Offline state OnClientDisconnect(0); } } - else + else // If not using Lobby, simply try to reconnect to the server directly { + // If this fails, the OnClientDisconnect callback will be invoked by Netcode var connectingClient = ConnectClientAsync(); yield return new WaitUntil(() => connectingClient.IsCompleted); } diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs index 8a60ece37..77a641b67 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs @@ -59,11 +59,6 @@ public override void OnClientDisconnect(ulong clientId) var playerId = SessionManager.Instance.GetPlayerId(clientId); if (playerId != null) { - if (m_LobbyServiceFacade.CurrentUnityLobby != null) - { - m_LobbyServiceFacade.RemovePlayerFromLobbyAsync(playerId, m_LobbyServiceFacade.CurrentUnityLobby.Id); - } - var sessionData = SessionManager.Instance.GetPlayerData(playerId); if (sessionData.HasValue) { diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs b/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs index 033dfe386..08d3d0471 100644 --- a/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs +++ b/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs @@ -9,8 +9,6 @@ namespace Unity.BossRoom.UnityServices.Lobbies { - using Lobbies = Unity.Services.Lobbies.Lobbies; - /// /// Wrapper for all the interactions with the Lobby API. /// @@ -82,24 +80,24 @@ public async Task CreateLobby(string requesterUasId, string lobbyName, in Data = lobbyData }; - return await ExceptionHandling(Lobbies.Instance.CreateLobbyAsync(lobbyName, maxPlayers, createOptions)); + return await ExceptionHandling(LobbyService.Instance.CreateLobbyAsync(lobbyName, maxPlayers, createOptions)); } public async Task DeleteLobby(string lobbyId) { - await ExceptionHandling(Lobbies.Instance.DeleteLobbyAsync(lobbyId)); + await ExceptionHandling(LobbyService.Instance.DeleteLobbyAsync(lobbyId)); } public async Task JoinLobbyByCode(string requesterUasId, string lobbyCode, Dictionary localUserData) { JoinLobbyByCodeOptions joinOptions = new JoinLobbyByCodeOptions { Player = new Player(id: requesterUasId, data: localUserData) }; - return await ExceptionHandling(Lobbies.Instance.JoinLobbyByCodeAsync(lobbyCode, joinOptions)); + return await ExceptionHandling(LobbyService.Instance.JoinLobbyByCodeAsync(lobbyCode, joinOptions)); } public async Task JoinLobbyById(string requesterUasId, string lobbyId, Dictionary localUserData) { JoinLobbyByIdOptions joinOptions = new JoinLobbyByIdOptions { Player = new Player(id: requesterUasId, data: localUserData) }; - return await ExceptionHandling(Lobbies.Instance.JoinLobbyByIdAsync(lobbyId, joinOptions)); + return await ExceptionHandling(LobbyService.Instance.JoinLobbyByIdAsync(lobbyId, joinOptions)); } public async Task QuickJoinLobby(string requesterUasId, Dictionary localUserData) @@ -110,14 +108,19 @@ public async Task QuickJoinLobby(string requesterUasId, Dictionary ReconnectToLobby(string lobbyId) + { + return await ExceptionHandling(LobbyService.Instance.ReconnectToLobbyAsync(lobbyId)); } public async Task RemovePlayerFromLobby(string requesterUasId, string lobbyId) { try { - await ExceptionHandling(Lobbies.Instance.RemovePlayerAsync(lobbyId, requesterUasId)); + await ExceptionHandling(LobbyService.Instance.RemovePlayerAsync(lobbyId, requesterUasId)); } catch (LobbyServiceException e) when (e is { Reason: LobbyExceptionReason.PlayerNotFound }) @@ -135,18 +138,18 @@ public async Task QueryAllLobbies() Order = m_Order }; - return await ExceptionHandling(Lobbies.Instance.QueryLobbiesAsync(queryOptions)); + return await ExceptionHandling(LobbyService.Instance.QueryLobbiesAsync(queryOptions)); } public async Task GetLobby(string lobbyId) { - return await ExceptionHandling(Lobbies.Instance.GetLobbyAsync(lobbyId)); + return await ExceptionHandling(LobbyService.Instance.GetLobbyAsync(lobbyId)); } public async Task UpdateLobby(string lobbyId, Dictionary data, bool shouldLock) { UpdateLobbyOptions updateOptions = new UpdateLobbyOptions { Data = data, IsLocked = shouldLock }; - return await ExceptionHandling(Lobbies.Instance.UpdateLobbyAsync(lobbyId, updateOptions)); + return await ExceptionHandling(LobbyService.Instance.UpdateLobbyAsync(lobbyId, updateOptions)); } public async Task UpdatePlayer(string lobbyId, string playerId, Dictionary data, string allocationId, string connectionInfo) @@ -157,12 +160,12 @@ public async Task UpdatePlayer(string lobbyId, string playerId, Dictionar AllocationId = allocationId, ConnectionInfo = connectionInfo }; - return await ExceptionHandling(Lobbies.Instance.UpdatePlayerAsync(lobbyId, playerId, updateOptions)); + return await ExceptionHandling(LobbyService.Instance.UpdatePlayerAsync(lobbyId, playerId, updateOptions)); } public async void SendHeartbeatPing(string lobbyId) { - await ExceptionHandling(Lobbies.Instance.SendHeartbeatPingAsync(lobbyId)); + await ExceptionHandling(LobbyService.Instance.SendHeartbeatPingAsync(lobbyId)); } } } diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs b/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs index a5e9e7681..382af59db 100644 --- a/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs +++ b/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs @@ -264,6 +264,11 @@ public async Task RetrieveAndPublishLobbyListAsync() } } + public async Task ReconnectToLobbyAsync(string lobbyId) + { + return await m_LobbyApiInterface.ReconnectToLobby(lobbyId); + } + /// /// Attempt to leave a lobby /// diff --git a/CHANGELOG.md b/CHANGELOG.md index 46c088585..aff2677f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,11 +32,13 @@ Additional documentation and release notes are available at [Multiplayer Documen * Instead of a NetworkBehaviour that carries a WinState netvar we now pass the win state on the server to the PostGame scene and it then stores that state in the netvar, eliminating the need to preserve a NetworkBehaviour-bearing gameObject across scenes. (#724) * Bump to NGO 1.0.1 (#720) * Reduced the MaxPacketQueueSize UTP parameter value from 512 to 256 (#728). This reduces the amount of memory used by UTP by around 1 MB. Boss Room does not need a bigger queue size than this because there can only be 7 clients connected to a host and UTP already limits the maximum number of in-flight packets to 32 per connection. +* Updated Lobby package to 1.0.3 and reworked our auto-reconnect flow to use the Reconnect feature from the Lobby API (#737). Now, clients do not leave the lobby when they are disconnected, and the host does not remove them from it. They are marked as disconnected by the Relay server and can attempt to reconnect to the lobby directly, until a certain timeout (specified by the Disconnect removal time parameer, set in the dashboard configuration). * Cleanup * Namespaces in the project have been changed to map to their assembly definitions (#732) * Numerous name changes for fields and variables to match their new type names (#732) * Removed DynamicNavObstacle - an unused class (#732) * Merged networked data classes into their Server counterparts. An example of that change is the contents of NetworkCharacterState getting moved into ServerCharacter, contents of NetworkDoorState getting moved into SwitchedDoor etc. (#732) +* ### Removed * ### Fixed diff --git a/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs b/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs index 5cc18f152..ca401330d 100644 --- a/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs +++ b/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs @@ -44,7 +44,7 @@ public static async } public static async - Task<(string ipv4address, ushort port, byte[] allocationIdBytes, byte[] connectionData, byte[] + Task<(string ipv4address, ushort port, byte[] allocationIdBytes, Guid allocationId, byte[] connectionData, byte[] hostConnectionData, byte[] key)> JoinRelayServerFromJoinCode(string joinCode) { JoinAllocation allocation; @@ -62,7 +62,7 @@ public static async Debug.Log($"client: {allocation.AllocationId}"); var dtlsEndpoint = allocation.ServerEndpoints.First(e => e.ConnectionType == k_KDtlsConnType); - return (dtlsEndpoint.Host, (ushort)dtlsEndpoint.Port, allocation.AllocationIdBytes, + return (dtlsEndpoint.Host, (ushort)dtlsEndpoint.Port, allocation.AllocationIdBytes, allocation.AllocationId, allocation.ConnectionData, allocation.HostConnectionData, allocation.Key); } } diff --git a/Packages/manifest.json b/Packages/manifest.json index 1c5207a2c..b38f2d6ee 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -15,7 +15,7 @@ "com.unity.postprocessing": "3.2.1", "com.unity.render-pipelines.universal": "12.1.6", "com.unity.services.authentication": "2.1.1", - "com.unity.services.lobby": "1.0.0-pre.6", + "com.unity.services.lobby": "1.0.3", "com.unity.services.relay": "1.0.3", "com.unity.test-framework": "1.1.31", "com.unity.textmeshpro": "3.0.6", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 8331f5fa7..f59216862 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -238,18 +238,18 @@ "url": "https://packages.unity.com" }, "com.unity.services.lobby": { - "version": "1.0.0-pre.6", + "version": "1.0.3", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.core": "1.1.0-pre.10", + "com.unity.services.core": "1.4.0", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.unitywebrequestassetbundle": "1.0.0", "com.unity.modules.unitywebrequestaudio": "1.0.0", "com.unity.modules.unitywebrequesttexture": "1.0.0", "com.unity.modules.unitywebrequestwww": "1.0.0", - "com.unity.nuget.newtonsoft-json": "2.0.0", - "com.unity.services.authentication": "1.0.0-pre.6" + "com.unity.nuget.newtonsoft-json": "3.0.2", + "com.unity.services.authentication": "2.0.0" }, "url": "https://packages.unity.com" },