using TMPro; using UdonSharp; using UnityEngine; using UnityEngine.UI; using VRC.SDKBase; using VRC.Udon; using VRCBilliardsCE.Packages.com.vrcbilliards.vrcbce.Runtime.Scripts.Components; namespace VRCBilliardsCE.Packages.com.vrcbilliards.vrcbce.Runtime.Scripts { /// /// The script that handles most pool menus. Menus sometimes have their own scripts, however. /// [UdonBehaviourSyncMode(BehaviourSyncMode.None)] public class PoolMenu : UdonSharpBehaviour { private PoolStateManager manager; [Header("Style")] public Color selectedColor = Color.white; public Color unselectedColor = Color.gray; [Header("Menu / Buttons")] public bool useUnityUI; public Button player1UIButton; public Button player2UIButton; public Button player3UIButton; public Button player4UIButton; public GameObject resetGameButton; public GameObject lockMenu; public GameObject mainMenu; public GameObject startGameButton; [Header("Game Mode")] public TextMeshProUGUI gameModeTxt; public Image[] gameModeButtons = { }; public string uSA8BallString = "American 8-Ball"; public string uSA9BallString = "American 9-Ball"; public string jP4BallString = "Japanese 4-Ball"; public string kN4BallString = "Korean 4-Ball"; public string threeCushionCaromString = "Three Cushion Carom"; [Header("Guide Line")] public bool toggleGuideLineButtonsActive = true; public GameObject guideLineEnableButton; public GameObject guideLineDisableButton; public TextMeshProUGUI guidelineStatus; public Image[] guideLineButtons = { }; public string guidelineEnabledString = "Guideline On"; public string guidelineDisabledString = "Guideline Off"; [Header("Timer")] public TextMeshProUGUI timer; public string noTimerText = "No Limit"; public string timerValueText = "{}s Limit"; public Image timerButton, noTimerButton; public TextMeshProUGUI visibleTimerDuringGame; public Image timerCountdown; public string timerOutputFormat = "{}"; [Header("Teams")] public TextMeshProUGUI teamsTxt; public Image[] teamsButtons = { }; public string oneVOneString = "Teams: NO"; public string twoVTwoString = "Teams: YES"; [Header("Players")] public GameObject player1Button; public GameObject player2Button; public GameObject player3Button; public GameObject player4Button; public GameObject leaveButton; public string defaultEmptyPlayerSlotText = "Player {}"; public TextMeshProUGUI player1MenuText; public TextMeshProUGUI player2MenuText; public TextMeshProUGUI player3MenuText; public TextMeshProUGUI player4MenuText; [Header("Score")] [Tooltip("A specific score display that only shows during gameplay. If this is populated, the table info display will be hidden during gameplay.")] public GameObject inGameScoreDisplay; [Tooltip("The table information screen. This will be hidden during games if the in-game score display is populated.")] public GameObject tableInfoScreen; public GameObject[] scores; public GameObject player1Score; public GameObject player2Score; public GameObject player3Score; public GameObject player4Score; public GameObject teamAScore; public GameObject teamBScore; private TextMeshProUGUI[] player1Scores; private TextMeshProUGUI[] player2Scores; private TextMeshProUGUI[] player3Scores; private TextMeshProUGUI[] player4Scores; private TextMeshProUGUI[] teamAScores; private TextMeshProUGUI[] teamBScores; public TextMeshProUGUI winnerText; public string gameResetText = "The game was ended!"; [Header("UdonChips Integration")] public string defaultEmptyplayerSlotTextWithUdonChips = "{}uc to play"; private bool isTeams; private bool isSignedUpToPlay; private bool canStartGame; [SerializeField] private LookAtHead tableUI; public void Start() { manager = GetComponentInParent(); player1Scores = new TextMeshProUGUI[scores.Length]; player2Scores = new TextMeshProUGUI[scores.Length]; player3Scores = new TextMeshProUGUI[scores.Length]; player4Scores = new TextMeshProUGUI[scores.Length]; teamAScores = new TextMeshProUGUI[scores.Length]; teamBScores = new TextMeshProUGUI[scores.Length]; for (int i = 0; i < scores.Length; i++) { player1Scores[i] = scores[i].transform.Find(player1Score.name).GetComponent(); player2Scores[i] = scores[i].transform.Find(player2Score.name).GetComponent(); player3Scores[i] = scores[i].transform.Find(player3Score.name).GetComponent(); player4Scores[i] = scores[i].transform.Find(player4Score.name).GetComponent(); teamAScores[i] = scores[i].transform.Find(teamAScore.name).GetComponent(); teamBScores[i] = scores[i].transform.Find(teamBScore.name).GetComponent(); } } public void _UnlockTable() { manager._UnlockTable(); } public void _LockTable() { manager._LockTable(); } public void _SelectTeams() { manager._SelectTeams(); } public void _DeselectTeams() { manager._DeselectTeams(); } public void _Select4BallJapanese() { manager._Select4BallJapanese(); } public void _Select4BallKorean() { manager._Select4BallKorean(); } public void _SelectThreeCushionCarom() { manager._SelectThreeCushionCarom(); } public void _Select8Ball() { manager._Select8Ball(); } public void _Select9Ball() { manager._Select9Ball(); } public void _IncreaseTimer() { manager._IncreaseTimer(); } public void _DecreaseTimer() { manager._DecreaseTimer(); } public void _EnableGuideline() { manager._EnableGuideline(); } public void _DisableGuideline() { manager._DisableGuideline(); } public void _SignUpAsPlayer1() { if (!isSignedUpToPlay) { manager._JoinGame(0); } } public void _SignUpAsPlayer2() { if (!isSignedUpToPlay) { manager._JoinGame(1); } } public void _SignUpAsPlayer3() { if (!isSignedUpToPlay) { manager._JoinGame(2); } } public void _SignUpAsPlayer4() { if (!isSignedUpToPlay) { manager._JoinGame(3); } } public void _LeaveGame() { manager._LeaveGame(); } public void _StartGame() { if (canStartGame) { manager._StartNewGame(); } } public void _EndGame() { if (isSignedUpToPlay || Networking.IsMaster || Networking.IsInstanceOwner) manager._ForceReset(); } public void _EnableResetButton() { resetGameButton.SetActive(true); lockMenu.SetActive(false); mainMenu.SetActive(false); winnerText.text = ""; if (inGameScoreDisplay) { inGameScoreDisplay.SetActive(true); if (tableInfoScreen) { tableInfoScreen.SetActive(false); } } } public void _EnableUnlockTableButton() { resetGameButton.SetActive(false); lockMenu.SetActive(true); mainMenu.SetActive(false); ResetScoreScreen(); } public void _EnableMainMenu() { resetGameButton.SetActive(false); lockMenu.SetActive(false); mainMenu.SetActive(true); visibleTimerDuringGame.text = ""; if (inGameScoreDisplay) { inGameScoreDisplay.SetActive(false); } if (tableInfoScreen) { tableInfoScreen.SetActive(true); } } private void UpdateButtonColors(Image[] buttons, int selectedIndex) { if (buttons == null) return; for (var i = 0; i < buttons.Length; i++) { Image but = buttons[i]; if (!but) { continue; } but.color = i == selectedIndex ? selectedColor : unselectedColor; } } /// /// Receive a new set of data from the manager that can be displayed to viewers. /// public void _UpdateMainMenuView( bool newIsTeams, bool isTeam2Playing, GameMode gameMode, int timeSeconds, int player1ID, int player2ID, int player3ID, int player4ID, bool guideline ) { if (newIsTeams) { if (VRC.SDKBase.Utilities.IsValid(teamsTxt)) teamsTxt.text = twoVTwoString; isTeams = true; } else { if (VRC.SDKBase.Utilities.IsValid(teamsTxt)) teamsTxt.text = oneVOneString; isTeams = false; } UpdateButtonColors(teamsButtons, newIsTeams ? 0 : 1); switch (gameMode) { case GameMode.EightBall: if (VRC.SDKBase.Utilities.IsValid(gameModeTxt)) gameModeTxt.text = uSA8BallString; UpdateButtonColors(gameModeButtons, 0); break; case GameMode.NineBall: if (VRC.SDKBase.Utilities.IsValid(gameModeTxt)) gameModeTxt.text = uSA9BallString; UpdateButtonColors(gameModeButtons, 1); break; case GameMode.KoreanCarom: if (VRC.SDKBase.Utilities.IsValid(gameModeTxt)) gameModeTxt.text = kN4BallString; UpdateButtonColors(gameModeButtons, 3); break; case GameMode.JapaneseCarom: if (VRC.SDKBase.Utilities.IsValid(gameModeTxt)) gameModeTxt.text = jP4BallString; UpdateButtonColors(gameModeButtons, 2); break; case GameMode.ThreeCushionCarom: if (VRC.SDKBase.Utilities.IsValid(gameModeTxt)) gameModeTxt.text = threeCushionCaromString; UpdateButtonColors(gameModeButtons, 2); break; } if (Utilities.IsValid(timer)) { if (timeSeconds == 0) { timer.text = noTimerText; } else { timer.text = timerValueText.Replace("{}", timeSeconds.ToString()); } } if (Utilities.IsValid(timerButton)) { timerButton.color = timeSeconds > 0 ? selectedColor : unselectedColor; } if (Utilities.IsValid(noTimerButton)) { noTimerButton.color = timeSeconds <= 0 ? selectedColor : unselectedColor; } if (Utilities.IsValid(leaveButton)) { leaveButton.SetActive(false); } if (useUnityUI) { player1UIButton.interactable = false; player2UIButton.interactable = false; player3UIButton.interactable = false; player4UIButton.interactable = false; } else { player1Button.SetActive(false); player2Button.SetActive(false); player3Button.SetActive(false); player4Button.SetActive(false); } bool found = false; var defaultText = defaultEmptyPlayerSlotText; if (player1ID > 0) { found = HandlePlayerState(player1MenuText, player1Scores, VRCPlayerApi.GetPlayerById(player1ID)); } else { player1MenuText.text = defaultText.Replace("{}", "1"); foreach (var score in player1Scores) { score.text = ""; } } if (player2ID > 0) { found = HandlePlayerState(player2MenuText, player2Scores, VRCPlayerApi.GetPlayerById(player2ID)); } else { player2MenuText.text = defaultText.Replace("{}", "2"); foreach (var score in player2Scores) { score.text = ""; } } if (player3ID > 0) { found = HandlePlayerState(player3MenuText, player3Scores, VRCPlayerApi.GetPlayerById(player3ID)); } else { player3MenuText.text = newIsTeams ? defaultText.Replace("{}", "3") : ""; foreach (var score in player3Scores) { score.text = ""; } } if (player4ID > 0) { found = HandlePlayerState(player4MenuText, player4Scores, VRCPlayerApi.GetPlayerById(player4ID)); } else { player4MenuText.text = newIsTeams ? defaultText.Replace("{}", "4") : ""; foreach (var score in player4Scores) { score.text = ""; } } int id = Networking.LocalPlayer.playerId; if (id == player1ID || id == player2ID || id == player3ID || id == player4ID) { isSignedUpToPlay = true; if (id == player1ID) { canStartGame = true; startGameButton.SetActive(true); } else { canStartGame = false; startGameButton.SetActive(false); } } else { isSignedUpToPlay = false; canStartGame = false; startGameButton.SetActive(false); } if (!found) { if (useUnityUI) { player1UIButton.interactable = true; player2UIButton.interactable = true; } else { player1Button.SetActive(true); player2Button.SetActive(true); } if (newIsTeams) { if (useUnityUI) { player3UIButton.interactable = true; player4UIButton.interactable = true; } else { player3Button.SetActive(true); player4Button.SetActive(true); } } } if (guideline) { if (toggleGuideLineButtonsActive && !useUnityUI) { guideLineDisableButton.SetActive(true); guideLineEnableButton.SetActive(false); } UpdateButtonColors(guideLineButtons, 0); if (VRC.SDKBase.Utilities.IsValid(guidelineStatus)) guidelineStatus.text = guidelineEnabledString; } else { if (toggleGuideLineButtonsActive && !useUnityUI) { guideLineDisableButton.SetActive(false); guideLineEnableButton.SetActive(true); } UpdateButtonColors(guideLineButtons, 1); if (VRC.SDKBase.Utilities.IsValid(guidelineStatus)) guidelineStatus.text = guidelineDisabledString; } } private bool HandlePlayerState(TextMeshProUGUI menuText, TextMeshProUGUI[] scores, VRCPlayerApi player) { if (!VRC.SDKBase.Utilities.IsValid(player)) { return false; } menuText.text = player.displayName; foreach (var score in scores) { score.text = player.displayName; } if (player.playerId == Networking.LocalPlayer.playerId) { leaveButton.SetActive(true); if (useUnityUI) { player1UIButton.interactable = false; player2UIButton.interactable = false; player3UIButton.interactable = false; player4UIButton.interactable = false; } else { player1Button.SetActive(false); player2Button.SetActive(false); player3Button.SetActive(false); player4Button.SetActive(false); } return true; } return false; } public void _SetScore(bool isTeam2, int score) { if (score < 0) { foreach (var scoreText in teamAScores) { scoreText.text = ""; } foreach (var scoreText in teamBScores) { scoreText.text = ""; } return; } if (isTeam2) { foreach (var scoreText in teamBScores) { scoreText.text = $"{score}"; } } else { foreach (var scoreText in teamAScores) { scoreText.text = $"{score}"; } } } public void _GameWasReset(ResetReason reason) { winnerText.text = PoolStateManager.ToReasonString(reason); } public void _TeamWins(bool isTeam2) { var player1 = player1Scores[0].text; var player2 = player2Scores[0].text; var player3 = player3Scores[0].text; var player4 = player4Scores[0].text; if (isTeams) { if (isTeam2) { if (player2 == "" || player4 == "") { winnerText.text = "Team 2 wins!"; } else { winnerText.text = $"{(player2)} and {player4} win!"; } } else { if (player1 == "" || player3 == "") { winnerText.text = "Team 1 wins!"; } else { winnerText.text = $"{(player1)} and {player3} win!"; } } return; } if (isTeam2) { winnerText.text = player2 == "" ? "Player 2 wins!" : $"{player2} wins!"; return; } winnerText.text = player1 == "" ? "Player 1 wins!" : $"{player1} wins!"; } private void ResetScoreScreen() { foreach (TextMeshProUGUI score in player1Scores) { score.text = ""; } foreach (TextMeshProUGUI score in player2Scores) { score.text = ""; } foreach (TextMeshProUGUI score in player3Scores) { score.text = ""; } foreach (TextMeshProUGUI score in player4Scores) { score.text = ""; } foreach (TextMeshProUGUI score in teamAScores) { score.text = ""; } foreach (TextMeshProUGUI score in teamBScores) { score.text = ""; } winnerText.text = ""; } public void _EnteredFlatscreenPlayerCamera(UnityEngine.Transform camera) { if (!camera) { return; } tableUI._StopLookingAtHead(camera); } public void _LeftFlatscreenPlayerCamera() { tableUI._StartLookingAtHead(); } } }