using System; using System.Collections.Generic; using UnityEngine; namespace LobbyRelaySample { [Flags] // Some UI elements will want to specify multiple states in which to be active, so this is Flags. public enum LobbyState { Lobby = 1, CountDown = 2, InGame = 4 } public enum LobbyColor { None = 0, Orange = 1, Green = 2, Blue = 3 } /// /// A local wrapper around a lobby's remote data, with additional functionality for providing that data to UI elements and tracking local player objects. /// (The way that the Lobby service handles its data doesn't necessarily match our needs, so we need to map from that to this LocalLobby for use in the sample code.) /// [System.Serializable] public class LocalLobby : Observed { Dictionary m_LobbyUsers = new Dictionary(); public Dictionary LobbyUsers => m_LobbyUsers; #region LocalLobbyData public struct LobbyData { public string LobbyID { get; set; } public string LobbyCode { get; set; } public string RelayCode { get; set; } public string LobbyName { get; set; } public bool Private { get; set; } public int MaxPlayerCount { get; set; } public LobbyState State { get; set; } public LobbyColor Color { get; set; } public LobbyData(LobbyData existing) { LobbyID = existing.LobbyID; LobbyCode = existing.LobbyCode; RelayCode = existing.RelayCode; LobbyName = existing.LobbyName; Private = existing.Private; MaxPlayerCount = existing.MaxPlayerCount; State = existing.State; Color = existing.Color; } public LobbyData(string lobbyCode) { LobbyID = null; LobbyCode = lobbyCode; RelayCode = null; LobbyName = null; Private = false; MaxPlayerCount = -1; State = LobbyState.Lobby; Color = LobbyColor.None; } } private LobbyData m_data; public LobbyData Data { get { return new LobbyData(m_data); } } float m_CountDownTime; public float CountDownTime { get { return m_CountDownTime; } set { m_CountDownTime = value; OnChanged(this); } } ServerAddress m_relayServer; /// Used only for visual output of the Relay connection info. The obfuscated Relay server IP is obtained during allocation in the RelayUtpSetup. public ServerAddress RelayServer { get => m_relayServer; set { m_relayServer = value; OnChanged(this); } } #endregion public void AddPlayer(LobbyUser user) { if (m_LobbyUsers.ContainsKey(user.ID)) { Debug.LogError($"Cant add player {user.DisplayName}({user.ID}) to lobby: {LobbyID} twice"); return; } DoAddPlayer(user); OnChanged(this); } private void DoAddPlayer(LobbyUser user) { m_LobbyUsers.Add(user.ID, user); user.onChanged += OnChangedUser; } public void RemovePlayer(LobbyUser user) { DoRemoveUser(user); OnChanged(this); } private void DoRemoveUser(LobbyUser user) { if (!m_LobbyUsers.ContainsKey(user.ID)) { Debug.LogWarning($"Player {user.DisplayName}({user.ID}) does not exist in lobby: {LobbyID}"); return; } m_LobbyUsers.Remove(user.ID); user.onChanged -= OnChangedUser; } private void OnChangedUser(LobbyUser user) { OnChanged(this); } public string LobbyID { get => m_data.LobbyID; set { m_data.LobbyID = value; OnChanged(this); } } public string LobbyCode { get => m_data.LobbyCode; set { m_data.LobbyCode = value; OnChanged(this); } } public string RelayCode { get => m_data.RelayCode; set { m_data.RelayCode = value; OnChanged(this); } } public string LobbyName { get => m_data.LobbyName; set { m_data.LobbyName = value; OnChanged(this); } } public LobbyState State { get => m_data.State; set { m_data.State = value; OnChanged(this); } } public bool Private { get => m_data.Private; set { m_data.Private = value; OnChanged(this); } } public int PlayerCount => m_LobbyUsers.Count; public int MaxPlayerCount { get => m_data.MaxPlayerCount; set { m_data.MaxPlayerCount = value; OnChanged(this); } } public LobbyColor Color { get => m_data.Color; set { if (m_data.Color != value) { m_data.Color = value; OnChanged(this); } } } public void CopyObserved(LobbyData data, Dictionary currUsers) { m_data = data; if (currUsers == null) m_LobbyUsers = new Dictionary(); else { List toRemove = new List(); foreach (var oldUser in m_LobbyUsers) { if (currUsers.ContainsKey(oldUser.Key)) oldUser.Value.CopyObserved(currUsers[oldUser.Key]); else toRemove.Add(oldUser.Value); } foreach (var remove in toRemove) { DoRemoveUser(remove); } foreach (var currUser in currUsers) { if (!m_LobbyUsers.ContainsKey(currUser.Key)) DoAddPlayer(currUser.Value); } } OnChanged(this); } // This ends up being called from the lobby list when we get data about a lobby without having joined it yet. public override void CopyObserved(LocalLobby oldObserved) { CopyObserved(oldObserved.Data, oldObserved.m_LobbyUsers); } } }