Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Assets/Readme.asset
Git LFS file not shown
60 changes: 13 additions & 47 deletions Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand All @@ -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<UnityServiceErrorMessage> m_UnityServiceErrorMessagePublisher;
readonly List<QueryFilter> m_Filters;
readonly List<QueryOrder> m_Order;

[Inject]
public LobbyAPIInterface(IPublisher<UnityServiceErrorMessage> unityServiceErrorMessagePublisher)
public LobbyAPIInterface()
{
m_UnityServiceErrorMessagePublisher = unityServiceErrorMessagePublisher;

// Filter for open lobbies only
m_Filters = new List<QueryFilter>()
{
Expand All @@ -43,34 +37,6 @@ public LobbyAPIInterface(IPublisher<UnityServiceErrorMessage> unityServiceErrorM
};
}

async Task<T> ExceptionHandling<T>(Task<T> 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<Lobby> CreateLobby(string requesterUasId, string lobbyName, int maxPlayers, bool isPrivate, Dictionary<string, PlayerDataObject> hostUserData, Dictionary<string, DataObject> lobbyData)
{
CreateLobbyOptions createOptions = new CreateLobbyOptions
Expand All @@ -80,24 +46,24 @@ public async Task<Lobby> 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<Lobby> JoinLobbyByCode(string requesterUasId, string lobbyCode, Dictionary<string, PlayerDataObject> 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<Lobby> JoinLobbyById(string requesterUasId, string lobbyId, Dictionary<string, PlayerDataObject> 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<Lobby> QuickJoinLobby(string requesterUasId, Dictionary<string, PlayerDataObject> localUserData)
Expand All @@ -108,19 +74,19 @@ public async Task<Lobby> QuickJoinLobby(string requesterUasId, Dictionary<string
Player = new Player(id: requesterUasId, data: localUserData)
};

return await ExceptionHandling(LobbyService.Instance.QuickJoinLobbyAsync(joinRequest));
return await LobbyService.Instance.QuickJoinLobbyAsync(joinRequest);
}

public async Task<Lobby> 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 })
Expand All @@ -138,18 +104,18 @@ public async Task<QueryResponse> QueryAllLobbies()
Order = m_Order
};

return await ExceptionHandling(LobbyService.Instance.QueryLobbiesAsync(queryOptions));
return await LobbyService.Instance.QueryLobbiesAsync(queryOptions);
}

public async Task<Lobby> GetLobby(string lobbyId)
{
return await ExceptionHandling(LobbyService.Instance.GetLobbyAsync(lobbyId));
return await LobbyService.Instance.GetLobbyAsync(lobbyId);
}

public async Task<Lobby> UpdateLobby(string lobbyId, Dictionary<string, DataObject> 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<Lobby> UpdatePlayer(string lobbyId, string playerId, Dictionary<string, PlayerDataObject> data, string allocationId, string connectionInfo)
Expand All @@ -160,12 +126,12 @@ public async Task<Lobby> 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);
}
}
}
106 changes: 97 additions & 9 deletions Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}
}

Expand All @@ -171,6 +184,10 @@ async void UpdateLobby(float unused)
{
m_RateLimitHost.PutOnCooldown();
}
else
{
PublishError(e);
}
}

return (false, null);
Expand Down Expand Up @@ -207,6 +224,10 @@ async void UpdateLobby(float unused)
{
m_RateLimitJoin.PutOnCooldown();
}
else
{
PublishError(e);
}
}

return (false, null);
Expand Down Expand Up @@ -234,6 +255,10 @@ async void UpdateLobby(float unused)
{
m_RateLimitQuickJoin.PutOnCooldown();
}
else
{
PublishError(e);
}
}

return (false, null);
Expand Down Expand Up @@ -261,12 +286,29 @@ public async Task RetrieveAndPublishLobbyListAsync()
{
m_RateLimitQuery.PutOnCooldown();
}
else
{
PublishError(e);
}
}
}

public async Task<Lobby> 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;
}

/// <summary>
Expand All @@ -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);
}
}

}
Expand All @@ -291,19 +336,33 @@ 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
{
Debug.LogError("Only the host can remove other players from the lobby.");
}
}

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
{
Expand Down Expand Up @@ -336,6 +395,10 @@ public async Task UpdatePlayerDataAsync(Dictionary<string, PlayerDataObject> 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);
}
}
}

Expand All @@ -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
}
Expand Down Expand Up @@ -406,6 +473,10 @@ public async Task UpdateLobbyDataAsync(Dictionary<string, DataObject> data)
{
m_RateLimitQuery.PutOnCooldown();
}
else
{
PublishError(e);
}
}
}

Expand All @@ -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));
}
}
}
Loading