diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs b/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs index 08d3d0471..0b163be1b 100644 --- a/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs +++ b/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Unity.BossRoom.Infrastructure; using Unity.Services.Lobbies; using Unity.Services.Lobbies.Models; using UnityEngine; -using VContainer; namespace Unity.BossRoom.UnityServices.Lobbies { @@ -16,15 +14,11 @@ public class LobbyAPIInterface { const int k_MaxLobbiesToShow = 16; // If more are necessary, consider retrieving paginated results or using filters. - readonly IPublisher m_UnityServiceErrorMessagePublisher; readonly List m_Filters; readonly List m_Order; - [Inject] - public LobbyAPIInterface(IPublisher unityServiceErrorMessagePublisher) + public LobbyAPIInterface() { - m_UnityServiceErrorMessagePublisher = unityServiceErrorMessagePublisher; - // Filter for open lobbies only m_Filters = new List() { @@ -43,34 +37,6 @@ public LobbyAPIInterface(IPublisher unityServiceErrorM }; } - async Task ExceptionHandling(Task task) - { - try - { - return await task; - } - catch (Exception e) - { - var reason = $"{e.Message} ({e.InnerException?.Message})"; // Lobby error type, then HTTP error type. - m_UnityServiceErrorMessagePublisher.Publish(new UnityServiceErrorMessage("Lobby Error", reason, UnityServiceErrorMessage.Service.Lobby, e)); - throw; - } - } - - async Task ExceptionHandling(Task task) - { - try - { - await task; - } - catch (Exception e) - { - var reason = $"{e.Message} ({e.InnerException?.Message})"; // Lobby error type, then HTTP error type. - m_UnityServiceErrorMessagePublisher.Publish(new UnityServiceErrorMessage("Lobby Error", reason, UnityServiceErrorMessage.Service.Lobby, e)); - throw; - } - } - public async Task CreateLobby(string requesterUasId, string lobbyName, int maxPlayers, bool isPrivate, Dictionary hostUserData, Dictionary lobbyData) { CreateLobbyOptions createOptions = new CreateLobbyOptions @@ -80,24 +46,24 @@ public async Task CreateLobby(string requesterUasId, string lobbyName, in Data = lobbyData }; - return await ExceptionHandling(LobbyService.Instance.CreateLobbyAsync(lobbyName, maxPlayers, createOptions)); + return await LobbyService.Instance.CreateLobbyAsync(lobbyName, maxPlayers, createOptions); } public async Task DeleteLobby(string lobbyId) { - await ExceptionHandling(LobbyService.Instance.DeleteLobbyAsync(lobbyId)); + await 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(LobbyService.Instance.JoinLobbyByCodeAsync(lobbyCode, joinOptions)); + return await 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(LobbyService.Instance.JoinLobbyByIdAsync(lobbyId, joinOptions)); + return await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId, joinOptions); } public async Task QuickJoinLobby(string requesterUasId, Dictionary localUserData) @@ -108,19 +74,19 @@ public async Task QuickJoinLobby(string requesterUasId, Dictionary ReconnectToLobby(string lobbyId) { - return await ExceptionHandling(LobbyService.Instance.ReconnectToLobbyAsync(lobbyId)); + return await LobbyService.Instance.ReconnectToLobbyAsync(lobbyId); } public async Task RemovePlayerFromLobby(string requesterUasId, string lobbyId) { try { - await ExceptionHandling(LobbyService.Instance.RemovePlayerAsync(lobbyId, requesterUasId)); + await LobbyService.Instance.RemovePlayerAsync(lobbyId, requesterUasId); } catch (LobbyServiceException e) when (e is { Reason: LobbyExceptionReason.PlayerNotFound }) @@ -138,18 +104,18 @@ public async Task QueryAllLobbies() Order = m_Order }; - return await ExceptionHandling(LobbyService.Instance.QueryLobbiesAsync(queryOptions)); + return await LobbyService.Instance.QueryLobbiesAsync(queryOptions); } public async Task GetLobby(string lobbyId) { - return await ExceptionHandling(LobbyService.Instance.GetLobbyAsync(lobbyId)); + return await 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(LobbyService.Instance.UpdateLobbyAsync(lobbyId, updateOptions)); + return await LobbyService.Instance.UpdateLobbyAsync(lobbyId, updateOptions); } public async Task UpdatePlayer(string lobbyId, string playerId, Dictionary data, string allocationId, string connectionInfo) @@ -160,12 +126,12 @@ public async Task UpdatePlayer(string lobbyId, string playerId, Dictionar AllocationId = allocationId, ConnectionInfo = connectionInfo }; - return await ExceptionHandling(LobbyService.Instance.UpdatePlayerAsync(lobbyId, playerId, updateOptions)); + return await LobbyService.Instance.UpdatePlayerAsync(lobbyId, playerId, updateOptions); } public async void SendHeartbeatPing(string lobbyId) { - await ExceptionHandling(LobbyService.Instance.SendHeartbeatPingAsync(lobbyId)); + await LobbyService.Instance.SendHeartbeatPingAsync(lobbyId); } } } diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs b/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs index 382af59db..9b3eea329 100644 --- a/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs +++ b/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs @@ -91,9 +91,18 @@ public Task EndTracking() { CurrentUnityLobby = null; - if (!string.IsNullOrEmpty(m_LocalLobby?.LobbyID)) + var lobbyId = m_LocalLobby?.LobbyID; + + if (!string.IsNullOrEmpty(lobbyId)) { - task = LeaveLobbyAsync(m_LocalLobby?.LobbyID); + if (m_LocalUser.IsHost) + { + task = DeleteLobbyAsync(lobbyId); + } + else + { + task = LeaveLobbyAsync(lobbyId); + } } m_LocalUser.ResetState(); @@ -146,6 +155,10 @@ async void UpdateLobby(float unused) { m_RateLimitQuery.PutOnCooldown(); } + else if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. + { + PublishError(e); + } } } @@ -171,6 +184,10 @@ async void UpdateLobby(float unused) { m_RateLimitHost.PutOnCooldown(); } + else + { + PublishError(e); + } } return (false, null); @@ -207,6 +224,10 @@ async void UpdateLobby(float unused) { m_RateLimitJoin.PutOnCooldown(); } + else + { + PublishError(e); + } } return (false, null); @@ -234,6 +255,10 @@ async void UpdateLobby(float unused) { m_RateLimitQuickJoin.PutOnCooldown(); } + else + { + PublishError(e); + } } return (false, null); @@ -261,12 +286,29 @@ public async Task RetrieveAndPublishLobbyListAsync() { m_RateLimitQuery.PutOnCooldown(); } + else + { + PublishError(e); + } } } public async Task ReconnectToLobbyAsync(string lobbyId) { - return await m_LobbyApiInterface.ReconnectToLobby(lobbyId); + try + { + return await m_LobbyApiInterface.ReconnectToLobby(lobbyId); + } + catch (LobbyServiceException e) + { + // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. + if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) + { + PublishError(e); + } + } + + return null; } /// @@ -280,9 +322,12 @@ public async Task LeaveLobbyAsync(string lobbyId) await m_LobbyApiInterface.RemovePlayerFromLobby(uasId, lobbyId); } catch (LobbyServiceException e) - when (e is { Reason: LobbyExceptionReason.LobbyNotFound }) { - // If Lobby is not found, it has already been deleted. No need to throw here. + // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. + if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) + { + PublishError(e); + } } } @@ -291,7 +336,14 @@ public async void RemovePlayerFromLobbyAsync(string uasId, string lobbyId) { if (m_LocalUser.IsHost) { - await m_LobbyApiInterface.RemovePlayerFromLobby(uasId, lobbyId); + try + { + await m_LobbyApiInterface.RemovePlayerFromLobby(uasId, lobbyId); + } + catch (LobbyServiceException e) + { + PublishError(e); + } } else { @@ -299,11 +351,18 @@ public async void RemovePlayerFromLobbyAsync(string uasId, string lobbyId) } } - public async void DeleteLobbyAsync(string lobbyId) + public async Task DeleteLobbyAsync(string lobbyId) { if (m_LocalUser.IsHost) { - await m_LobbyApiInterface.DeleteLobby(lobbyId); + try + { + await m_LobbyApiInterface.DeleteLobby(lobbyId); + } + catch (LobbyServiceException e) + { + PublishError(e); + } } else { @@ -336,6 +395,10 @@ public async Task UpdatePlayerDataAsync(Dictionary dat { m_RateLimitQuery.PutOnCooldown(); } + else if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. + { + PublishError(e); + } } } @@ -359,6 +422,10 @@ public async Task UpdatePlayerRelayInfoAsync(string allocationId, string connect { m_RateLimitQuery.PutOnCooldown(); } + else + { + PublishError(e); + } //todo - retry logic? SDK is supposed to handle this eventually } @@ -406,6 +473,10 @@ public async Task UpdateLobbyDataAsync(Dictionary data) { m_RateLimitQuery.PutOnCooldown(); } + else + { + PublishError(e); + } } } @@ -418,8 +489,25 @@ public void DoLobbyHeartbeat(float dt) if (m_HeartbeatTime > k_HeartbeatPeriod) { m_HeartbeatTime -= k_HeartbeatPeriod; - m_LobbyApiInterface.SendHeartbeatPing(CurrentUnityLobby.Id); + try + { + m_LobbyApiInterface.SendHeartbeatPing(CurrentUnityLobby.Id); + } + catch (LobbyServiceException e) + { + // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. + if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) + { + PublishError(e); + } + } } } + + void PublishError(LobbyServiceException e) + { + var reason = $"{e.Message} ({e.InnerException?.Message})"; // Lobby error type, then HTTP error type. + m_UnityServiceErrorMessagePub.Publish(new UnityServiceErrorMessage("Lobby Error", reason, UnityServiceErrorMessage.Service.Lobby, e)); + } } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e4375691..898345513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,15 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). -## [unreleased] - yyy-mm-dd +## [unreleased] - aaaa-mm-dd + ### Added - * +* ### Changed - * +* Hosts now delete their lobby when shutting down instead of only leaving it (#772) Since Boss Room doesn't support host migration, there is no need to keep the lobby alive after the host shuts down. This also changes how LobbyServiceExceptions are handled to prevent popup messages on clients trying to leave a lobby that is already deleted, following the best practices outlined in this doc : https://docs.unity.com/lobby/delete-a-lobby.html +* ### Cleanup - * +* ### Fixed - * +* ## [2.0.2] - 2022-11-01 ### Fixed