using LobbyRooms.Rooms; using System; using System.Collections.Generic; using Unity.Services.Authentication; using Unity.Services.Rooms; using Unity.Services.Rooms.Models; using Utilities; namespace LobbyRooms { /// /// An abstraction layer between the direct calls into Rooms and the outcomes you actually want. E.g. you can request to get a readable list of /// current rooms and not need to make the query call directly. /// public class RoomsQuery { // Just doing a singleton since static access is all that's really necessary but we also need to be able to subscribe to the slow update loop. private static RoomsQuery s_instance; public static RoomsQuery Instance { get { if (s_instance == null) s_instance = new RoomsQuery(); return s_instance; } } private static bool IsSuccessful(Response response) { return response != null && response.Status >= 200 && response.Status < 300; // Uses HTTP status codes, so 2xx is a success. } // TODO: Reify async calls so they can be enqueued if calls are made before outstanding async operations complete? /// /// Attempt to create a new room and then join it. /// public void CreateRoomAsync(string roomName, int maxPlayers, Action onSuccess, Action onFailure) { string uasId = Authentication.PlayerId; RoomsInterface.CreateRoomAsync(uasId, roomName, maxPlayers, OnRoomCreated); void OnRoomCreated(Response response) { if (!IsSuccessful(response)) onFailure?.Invoke(); else { var pendingRoom = response.Result; onSuccess?.Invoke(pendingRoom); // The CreateRoom request automatically joins the room, so we need not take further action. } } } /// Attempt to join an existing room. ID xor code can be null. public void JoinRoomAsync(string roomId, string roomCode, Action onSuccess, Action onFailure) { string uasId = Authentication.PlayerId; RoomsInterface.JoinRoomAsync(uasId, roomId, roomCode, OnRoomJoined); void OnRoomJoined(Response response) { if (!IsSuccessful(response)) onFailure?.Invoke(); else onSuccess?.Invoke(response?.Result); } } /// If called with null, retrieval was unsuccessful. Else, this will be given a list of contents to display, as pairs of a room code and a display string for that room. public void RetrieveRoomListAsync(Action onListRetrieved) { string uasId = Authentication.PlayerId; RoomsInterface.QueryAllRoomsAsync(OnRoomListRetrieved); void OnRoomListRetrieved(Response response) { if (IsSuccessful(response)) onListRetrieved?.Invoke(response?.Result); } } /// If no room is retrieved, this is given null. public void RetrieveRoomAsync(string roomId, Action onComplete) { RoomsInterface.GetRoomAsync(roomId, OnGet); void OnGet(Response response) { onComplete?.Invoke(response?.Result); } } /// /// Attempt to leave a room, and then delete it if no players remain. /// /// Called once the request completes, regardless of success or failure. public void LeaveRoomAsync(string roomId, Action onComplete) { string uasId = Authentication.PlayerId; RoomsInterface.LeaveRoomAsync(uasId, roomId, OnLeftRoom); void OnLeftRoom(Response response) { onComplete?.Invoke(); // Rooms will automatically delete the room if unoccupied, so we don't need to take further action. } } /// Pass in the room from a RetrieveRoomAsync. (This prevents a 429 Too Many Requests if updating both player and room data, by using one retrieval.) /// Key-value pairs, which will overwrite any existing data for these keys. Presumed to be available to all room members but not publicly. public void UpdatePlayerDataAsync(Room room, Dictionary data, Action onComplete) { UpdateDataAsync(room, data, onComplete, false); } /// Pass in the room from a RetrieveRoomAsync. (This prevents a 429 Too Many Requests if updating both player and room data, by using one retrieval.) /// Key-value pairs, which will overwrite any existing data for these keys. Presumed to be available to all room members but not publicly. public void UpdateRoomDataAsync(Room room, Dictionary data, Action onComplete) { UpdateDataAsync(room, data, onComplete, true); } private void UpdateDataAsync(Room room, Dictionary data, Action onComplete, bool isRoom) { Dictionary dataCurr = room.Data ?? new Dictionary(); foreach (var dataNew in data) { DataObject dataObj = new DataObject(visibility: "Member", value: dataNew.Value); if (dataCurr.ContainsKey(dataNew.Key)) dataCurr[dataNew.Key] = dataObj; else dataCurr.Add(dataNew.Key, dataObj); } if (isRoom) RoomsInterface.UpdateRoomAsync(room.Id, dataCurr, (r) => { onComplete?.Invoke(); }); else RoomsInterface.UpdatePlayerAsync(room.Id, Locator.Get.Identity.GetSubIdentity(Auth.IIdentityType.Auth).GetContent("id"), dataCurr, (r) => { onComplete?.Invoke(); }); } } }