using Fusion; using System.Collections.Generic; using Fusion.Photon.Realtime; using UnityEngine; using TMPro; using Unity.Services.Matchmaker.Models; #pragma warning disable 4014 namespace TPSBR.UI { public class UIMultiplayerView : UICloseView { // PRIVATE MEMBERS [SerializeField] private UISession _sessionDetail; [SerializeField] private UIButton _createSessionButton; [SerializeField] private UIButton _quickPlayButton; [SerializeField] private UIButton _cancelQuickPlayButton; [SerializeField] private UIButton _joinButton; [SerializeField] private UIButton _settingsButton; [SerializeField] private TMP_Dropdown _regionDropdown; [SerializeField] private UIBehaviour _refreshingGroup; [SerializeField] private UIBehaviour _noSessionsGroup; [SerializeField] private TextMeshProUGUI _errorText; [SerializeField] private TextMeshProUGUI _applicationVersion; private UISessionList _sessionList; private UIMatchmakerView _matchmakerView; private List _sessionInfo = new List(32); private SessionInfo _selectedSession; private SimpleAnimation _joinButtonAnimation; // PUBLIC METHODS public void StartQuickPlay() { OnQuickPlayButton(); } // UIView INTEFACE protected override void OnInitialize() { base.OnInitialize(); _sessionList = GetComponentInChildren(); _sessionList.SelectionChanged += OnSessionSelectionChanged; _sessionList.UpdateContent += OnUpdateSessionListContent; _createSessionButton.onClick.AddListener(OnCreateGameButton); _quickPlayButton.onClick.AddListener(OnQuickPlayButton); _cancelQuickPlayButton.onClick.AddListener(OnCancelQuickPlay); _joinButton.onClick.AddListener(OnJoinButton); _settingsButton.onClick.AddListener(OnSettingsButton); _regionDropdown.onValueChanged.AddListener(OnRegionChanged); _sessionDetail.SetActive(false); _applicationVersion.text = $"Version {Application.version}"; _joinButtonAnimation = _joinButton.GetComponent(); PrepareRegionDropdown(); } protected override void OnDeinitialize() { _sessionList.SelectionChanged -= OnSessionSelectionChanged; _sessionList.UpdateContent -= OnUpdateSessionListContent; _createSessionButton.onClick.RemoveListener(OnCreateGameButton); _quickPlayButton.onClick.RemoveListener(OnQuickPlayButton); _cancelQuickPlayButton.onClick.RemoveListener(OnCancelQuickPlay); _joinButton.onClick.RemoveListener(OnJoinButton); _settingsButton.onClick.RemoveListener(OnSettingsButton); _regionDropdown.onValueChanged.RemoveListener(OnRegionChanged); base.OnDeinitialize(); } protected override void OnOpen() { base.OnOpen(); Context.Matchmaking.SessionListUpdated += OnSessionListUpdated; Context.Matchmaking.LobbyJoined += OnLobbyJoined; Context.Matchmaking.LobbyJoinFailed += OnLobbyJoinFailed; Context.Matchmaking.LobbyLeft += OnLobbyLeft; Context.Matchmaker.MatchFound += OnMatchFound; Context.Matchmaker.MatchmakerFailed += OnMatchmakerFailed; OnLobbyLeft(); TryJoinLobby(true); var currentRegion = Context.RuntimeSettings.Region; int regionIndex = System.Array.FindIndex(Context.Settings.Network.Regions, t => t.Region == currentRegion); _regionDropdown.SetValueWithoutNotify(regionIndex); } protected override void OnClose() { Context.Matchmaking.SessionListUpdated -= OnSessionListUpdated; Context.Matchmaking.LobbyJoined -= OnLobbyJoined; Context.Matchmaking.LobbyJoinFailed -= OnLobbyJoinFailed; Context.Matchmaking.LobbyLeft -= OnLobbyLeft; Context.Matchmaker.MatchFound -= OnMatchFound; Context.Matchmaker.MatchmakerFailed -= OnMatchmakerFailed; Context.Matchmaking.LeaveLobby(); base.OnClose(); } protected override void OnTick() { base.OnTick(); _refreshingGroup.SetActive(Context.Matchmaking.IsJoiningToLobby); bool canJoin = CanJoinSession(_selectedSession); _joinButton.interactable = canJoin; _joinButtonAnimation.enabled = canJoin; } // PRIVATE METHODS private void TryJoinLobby(bool force) { if (PhotonAppSettings.Global.AppSettings.AppIdFusion.HasValue() == true) { Context.Matchmaking.JoinLobby(force); } else { var errorDialog = Open(); errorDialog.Title.text = "Missing App Id"; errorDialog.Description.text = "Fusion App Id is not assigned in the Photon App Settings asset.\n\nPlease follow instructions in the Fusion BR200 documentation on how to create and assign App Id."; errorDialog.HasClosed += () => { #if UNITY_EDITOR UnityEditor.Selection.activeObject = PhotonAppSettings.Global; UnityEditor.EditorGUIUtility.PingObject(PhotonAppSettings.Global); #endif Close(); }; } } private void OnSessionListUpdated(NetworkRunner runner, List sessionInfo) { string selectedSessionName = _selectedSession != null ? _selectedSession.Name : string.Empty; _sessionInfo.Clear(); for (int i = 0; i < sessionInfo.Count; i++) { var session = sessionInfo[i]; // Do not show invalid sessions if (session.IsValid == false || session.IsOpen == false || session.IsVisible == false) continue; _sessionInfo.Add(session); } _sessionList.Refresh(_sessionInfo.Count); _sessionList.Selection = _sessionInfo.FindIndex(t => t.Name == selectedSessionName); _noSessionsGroup.SetActive(_sessionInfo.Count == 0); _selectedSession = _sessionList.Selection >= 0 ? _sessionInfo[_sessionList.Selection] : null; UpdateSessionDetail(); } private void OnLobbyJoined() { _errorText.text = string.Empty; } private void OnLobbyJoinFailed(string region) { var regionInfo = Context.Settings.Network.GetRegionInfo(region); var regionText = regionInfo != null ? $"{regionInfo.DisplayName} ({regionInfo.Region})" : "Unknown"; _errorText.text = $"Joining lobby in region {regionText} failed"; } private void OnLobbyLeft() { _errorText.text = string.Empty; _noSessionsGroup.SetActive(false); ClearSessions(); } private void ClearSessions() { _sessionList.Clear(); _sessionInfo.Clear(); _selectedSession = null; _sessionDetail.SetActive(false); } private void OnCreateGameButton() { if (ApplicationSettings.IsPublicBuild == true && ApplicationSettings.IsModerator == false) { UIJokeDialogView jokeDialog = Open(); jokeDialog.Title.text = "Moderators Only"; jokeDialog.Description.text = "You are not allowed to create a game in public build."; jokeDialog.JokeButton01Text.text = "I'm moderator!"; jokeDialog.JokeButton02Text.text = "I'm moderator!"; } else { Open(); } } private async void OnQuickPlayButton() { if (Context.PlayerData.UnityID.HasValue() == true) { _errorText.text = string.Empty; _matchmakerView = Open(); await Context.Matchmaker.StartMatchmaker(Global.Settings.Network.GetCustomOrDefaultQueueName()); } else { var infoDialog = Open(); infoDialog.Title.text = "Unity Gaming Services"; infoDialog.Description.text = "For matchmaking functionality Unity Gaming Services need to be configured.\n\nPlease follow instructions in the Fusion BR200 documentation on how to add Unity Game Server Hosting support."; } } private async void OnCancelQuickPlay() { await Context.Matchmaker.CancelMatchmaker(); } private void OnMatchFound(MultiplayAssignment assignment) { Context.Matchmaking.JoinSession("mm-" + assignment.MatchId); if (_matchmakerView != null) { _matchmakerView.Close(); _matchmakerView = null; } } private void OnMatchmakerFailed(string message) { _errorText.text = message; if (_matchmakerView != null) { _matchmakerView.Close(); _matchmakerView = null; } } private void OnSessionSelectionChanged(int index) { _selectedSession = index >= 0 ? _sessionInfo[index] : null; UpdateSessionDetail(); } private void OnUpdateSessionListContent(int index, UISession content) { content.SetData(_sessionInfo[index]); } private void OnJoinButton() { Context.Matchmaking.JoinSession(_selectedSession); } private void OnSettingsButton() { Open(); } private void OnRegionChanged(int regionIndex) { var region = Context.Settings.Network.Regions[regionIndex].Region; Context.RuntimeSettings.Region = region; TryJoinLobby(false); } private void UpdateSessionDetail() { if (_selectedSession == null) { _sessionDetail.SetActive(false); } else { _sessionDetail.SetActive(true); _sessionDetail.SetData(_selectedSession); _joinButton.interactable = CanJoinSession(_selectedSession); } } private bool CanJoinSession(SessionInfo session) { if (session == null) return false; if (session.PlayerCount >= session.MaxPlayers) return false; if (session.IsOpen == false || session.IsVisible == false) return false; if (session.HasMap() == false) return false; return true; } private void PrepareRegionDropdown() { var options = ListPool.Get(16); var regions = Context.Settings.Network.Regions; for (int i = 0; i < regions.Length; i++) { var regionInfo = regions[i]; var optionData = new TMP_Dropdown.OptionData(); optionData.text = regionInfo.DisplayName; optionData.image = regionInfo.Icon; options.Add(optionData); } _regionDropdown.ClearOptions(); _regionDropdown.AddOptions(options); ListPool.Return(options); } } }