using System.Collections.Generic; using Oculus.Platform.Models; using UnityEngine; using UnityEngine.UI; namespace Oculus.Platform.Samples.VrHoops { public class MatchController : MonoBehaviour { private enum State { UNKNOWN = 0, NONE = 1, WAITING_TO_START_PRACTICE = 2, PRACTICING = 3, VIEWING_RESULTS_PRACTICE = 4, WAITING_FOR_MATCH = 5, WAITING_TO_SETUP_MATCH = 6, PLAYING_MATCH = 7, VIEWING_MATCH_RESULTS = 8 } [SerializeField] private Text m_timerText; [SerializeField] private Camera m_camera; [SerializeField] private Transform m_idleCameraTransform; [SerializeField] private Text m_matchmakeButtonText; [SerializeField] private PlayerArea[] m_playerAreas = new PlayerArea[3]; [SerializeField] private uint PRACTICE_WARMUP_TIME = 5u; [SerializeField] private uint MATCH_WARMUP_TIME = 30u; [SerializeField] private uint MATCH_TIME = 20u; [SerializeField] private uint MATCH_COOLDOWN_TIME = 10u; [SerializeField] private GameObject m_mostWinsLeaderboard; [SerializeField] private GameObject m_highestScoresLeaderboard; [SerializeField] private GameObject m_leaderboardEntryPrefab; [SerializeField] private GameObject m_flytext; private State m_currentState; private float m_nextStateTransitionTime; private int m_localSlot; public float MatchStartTime { get { State currentState = m_currentState; if (currentState == State.WAITING_TO_START_PRACTICE || currentState == State.WAITING_TO_SETUP_MATCH) { return m_nextStateTransitionTime; } return 0f; } private set { m_nextStateTransitionTime = value; } } private void Start() { PlatformManager.Matchmaking.EnqueueResultCallback = OnMatchFoundCallback; PlatformManager.Matchmaking.MatchPlayerAddedCallback = MatchPlayerAddedCallback; PlatformManager.P2P.StartTimeOfferCallback = StartTimeOfferCallback; PlatformManager.Leaderboards.MostWinsLeaderboardUpdatedCallback = MostWinsLeaderboardCallback; PlatformManager.Leaderboards.HighScoreLeaderboardUpdatedCallback = HighestScoreLeaderboardCallback; TransitionToState(State.NONE); } private void Update() { UpdateCheckForNextTimedTransition(); UpdateMatchTimer(); } private void TransitionToState(State newState) { Debug.LogFormat("MatchController State {0} -> {1}", m_currentState, newState); if (m_currentState != newState) { State currentState = m_currentState; m_currentState = newState; switch (newState) { case State.NONE: SetupForIdle(); MoveCameraToIdlePosition(); PlatformManager.TransitionToState(PlatformManager.State.WAITING_TO_PRACTICE_OR_MATCHMAKE); m_matchmakeButtonText.text = "Play Online"; break; case State.WAITING_TO_START_PRACTICE: SetupForPractice(); MoveCameraToMatchPosition(); PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION); m_nextStateTransitionTime = Time.time + (float)PRACTICE_WARMUP_TIME; break; case State.PRACTICING: PlatformManager.TransitionToState(PlatformManager.State.PLAYING_A_LOCAL_MATCH); m_nextStateTransitionTime = Time.time + (float)MATCH_TIME; break; case State.VIEWING_RESULTS_PRACTICE: PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION); m_nextStateTransitionTime = Time.time + (float)MATCH_COOLDOWN_TIME; m_timerText.text = "0:00.00"; break; case State.WAITING_FOR_MATCH: PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION); m_matchmakeButtonText.text = "Cancel"; break; case State.WAITING_TO_SETUP_MATCH: m_nextStateTransitionTime = Time.time + (float)MATCH_WARMUP_TIME; break; case State.PLAYING_MATCH: PlatformManager.TransitionToState(PlatformManager.State.PLAYING_A_NETWORKED_MATCH); m_nextStateTransitionTime = Time.time + (float)MATCH_TIME; break; case State.VIEWING_MATCH_RESULTS: PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION); m_nextStateTransitionTime = Time.time + (float)MATCH_COOLDOWN_TIME; m_timerText.text = "0:00.00"; CalculateMatchResults(); break; } } } private void UpdateCheckForNextTimedTransition() { if (m_currentState != State.NONE && Time.time >= m_nextStateTransitionTime) { switch (m_currentState) { case State.WAITING_TO_START_PRACTICE: TransitionToState(State.PRACTICING); break; case State.PRACTICING: TransitionToState(State.VIEWING_RESULTS_PRACTICE); break; case State.VIEWING_RESULTS_PRACTICE: TransitionToState(State.NONE); break; case State.WAITING_TO_SETUP_MATCH: TransitionToState(State.PLAYING_MATCH); break; case State.PLAYING_MATCH: TransitionToState(State.VIEWING_MATCH_RESULTS); break; case State.VIEWING_MATCH_RESULTS: PlatformManager.Matchmaking.EndMatch(); TransitionToState(State.NONE); break; case State.WAITING_FOR_MATCH: break; } } } private void UpdateMatchTimer() { if (Time.time <= m_nextStateTransitionTime) { switch (m_currentState) { case State.WAITING_TO_START_PRACTICE: case State.WAITING_TO_SETUP_MATCH: m_timerText.text = string.Format("{0:0}", Mathf.Ceil(Time.time - MatchStartTime)); break; case State.PRACTICING: case State.PLAYING_MATCH: { float num = m_nextStateTransitionTime - Time.time; m_timerText.text = string.Format("{0:#0}:{1:#00}.{2:00}", Mathf.Floor(num / 60f), Mathf.Floor(num) % 60f, Mathf.Floor(num * 100f) % 100f); break; } case State.VIEWING_RESULTS_PRACTICE: case State.WAITING_FOR_MATCH: break; } } } private void SetupForIdle() { for (int i = 0; i < m_playerAreas.Length; i++) { m_playerAreas[i].SetupForPlayer("* AI *"); } } private void SetupForPractice() { m_localSlot = Random.Range(0, m_playerAreas.Length - 1); for (int i = 0; i < m_playerAreas.Length; i++) { if (i == m_localSlot) { m_playerAreas[i].SetupForPlayer(PlatformManager.MyOculusID); } else { m_playerAreas[i].SetupForPlayer("* AI *"); } } } private Player MatchPlayerAddedCallback(int slot, User user) { Player result = null; if (m_currentState == State.WAITING_TO_SETUP_MATCH && slot < m_playerAreas.Length) { if (user.ID == PlatformManager.MyID) { LocalPlayer localPlayer = m_playerAreas[slot].SetupForPlayer(user.OculusID); MoveCameraToMatchPosition(); result = localPlayer; m_localSlot = slot; } else { RemotePlayer remotePlayer = m_playerAreas[slot].SetupForPlayer(user.OculusID); remotePlayer.User = user; result = remotePlayer; } } return result; } private void MoveCameraToIdlePosition() { BallEjector componentInChildren = m_camera.gameObject.GetComponentInChildren(); if ((bool)componentInChildren) { componentInChildren.transform.SetParent(m_camera.transform.parent, false); m_camera.transform.SetParent(m_idleCameraTransform, false); } } private void MoveCameraToMatchPosition() { PlayerArea[] playerAreas = m_playerAreas; foreach (PlayerArea playerArea in playerAreas) { LocalPlayer componentInChildren = playerArea.GetComponentInChildren(); if ((bool)componentInChildren) { BallEjector componentInChildren2 = componentInChildren.GetComponentInChildren(); m_camera.transform.SetParent(componentInChildren.transform, false); componentInChildren2.transform.SetParent(m_camera.transform, false); break; } } DisplayAchievementFlytext(); } public void StartPracticeMatch() { if (m_currentState == State.NONE) { TransitionToState(State.WAITING_TO_START_PRACTICE); } } public void PlayOnlineOrCancel() { Debug.Log("Play online or Cancel"); if (m_currentState == State.NONE) { PlatformManager.Matchmaking.QueueForMatch(); TransitionToState(State.WAITING_FOR_MATCH); } else if (m_currentState == State.WAITING_FOR_MATCH) { PlatformManager.Matchmaking.LeaveQueue(); TransitionToState(State.NONE); } } private void OnMatchFoundCallback(bool success) { if (success) { TransitionToState(State.WAITING_TO_SETUP_MATCH); } else { TransitionToState(State.NONE); } } private float StartTimeOfferCallback(float remoteTime) { if (m_currentState == State.WAITING_TO_SETUP_MATCH && remoteTime > MatchStartTime && remoteTime - 60f < MatchStartTime) { Debug.Log("Moving Start time by " + (remoteTime - MatchStartTime)); MatchStartTime = remoteTime; } return MatchStartTime; } private void MostWinsLeaderboardCallback(SortedDictionary entries) { foreach (Transform item in m_mostWinsLeaderboard.transform) { Object.Destroy(item.gameObject); } foreach (LeaderboardEntry value in entries.Values) { GameObject gameObject = Object.Instantiate(m_leaderboardEntryPrefab); gameObject.transform.SetParent(m_mostWinsLeaderboard.transform, false); gameObject.GetComponent().text = string.Format("{0} - {1} - {2}", value.Rank, value.User.OculusID, value.Score); } } private void HighestScoreLeaderboardCallback(SortedDictionary entries) { foreach (Transform item in m_highestScoresLeaderboard.transform) { Object.Destroy(item.gameObject); } foreach (LeaderboardEntry value in entries.Values) { GameObject gameObject = Object.Instantiate(m_leaderboardEntryPrefab); gameObject.transform.SetParent(m_highestScoresLeaderboard.transform, false); gameObject.GetComponent().text = string.Format("{0} - {1} - {2}", value.Rank, value.User.OculusID, value.Score); } } private void CalculateMatchResults() { LocalPlayer localPlayer = null; RemotePlayer remotePlayer = null; PlayerArea[] playerAreas = m_playerAreas; foreach (PlayerArea playerArea in playerAreas) { if (playerArea.Player is LocalPlayer) { localPlayer = playerArea.Player as LocalPlayer; } else if (playerArea.Player is RemotePlayer && (remotePlayer == null || playerArea.Player.Score > remotePlayer.Score)) { remotePlayer = playerArea.Player as RemotePlayer; } } if ((bool)localPlayer && (bool)remotePlayer) { bool flag = localPlayer.Score > remotePlayer.Score; PlatformManager.Leaderboards.SubmitMatchScores(flag, localPlayer.Score); if (flag) { PlatformManager.Achievements.RecordWinForLocalUser(); } } } private void DisplayAchievementFlytext() { if (PlatformManager.Achievements.LikesToWin) { GameObject gameObject = Object.Instantiate(m_flytext); gameObject.GetComponent().text = "Likes to Win!"; gameObject.transform.position = Vector3.up * 40f; gameObject.transform.SetParent(m_playerAreas[m_localSlot].NameText.transform, false); } } } }