using UdonSharp; using UnityEngine; using VRC.SDK3.Data; using VRC.SDK3.UdonNetworkCalling; using VRC.Udon.Common.Interfaces; using VRC.SDKBase; using System.Linq; using VRC.SDK3.StringLoading; using System.Runtime.CompilerServices; using TMPro; public enum MusicEventType { None, WhereInTheWorld, RockapellaIdent } public enum SFXEventType { None, Buzzer } [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class GameManager : UdonSharpBehaviour { [UdonSynced] public VRCUrl QuestionURL; [SerializeField] private TextMeshProUGUI _InfoHeader; [SerializeField] private TextMeshProUGUI[] _InfoClues; [SerializeField] private TextMeshProUGUI[] _InfoChoices; [SerializeField] private GameObject _AdminPanel; [UdonSynced] private bool BuzzInAllowed = false; [UdonSynced] private bool[] PlayerBuzzInAllowed; [UdonSynced] private int _BuzzedInPlayer = -1; public PlayerPodium[] PlayerPodiums; [Header("Audio")] [SerializeField] private AudioClip BuzzerSound = null; [SerializeField] private AudioClip WhereInTheWorld = null; [SerializeField] private AudioClip RockapellaIdent = null; [SerializeField] private AudioSource MusicPlayer = null; [SerializeField] private AudioSource SFXPlayer = null; void Start() { PlayerBuzzInAllowed = new bool[PlayerPodiums.Length]; ResetBuzzers(); // Download our test question. VRCStringDownloader.LoadUrl(QuestionURL, (IUdonEventReceiver)this); } public override void OnStringLoadSuccess(IVRCStringDownload DownloadedString) { string JSONString = DownloadedString.Result; if (VRCJson.TryDeserializeFromJson(JSONString, out DataToken JSONResult)) { if (JSONResult.TokenType == TokenType.DataDictionary) { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.All, nameof(UpdateInfoCard), JSONString); } } else { Debug.LogError("The question should be a Dictionary type."); } } [NetworkCallable] public void UpdateInfoCard(string Data) { if (VRCJson.TryDeserializeFromJson(Data, out DataToken ResultToken)) { DataDictionary Result = ResultToken.DataDictionary; _InfoChoices[0].text = Result["Choices"].DataList[0].ToString(); _InfoChoices[1].text = Result["Choices"].DataList[1].ToString(); _InfoChoices[2].text = Result["Choices"].DataList[2].ToString(); } } public void EnableBuzzInPeriodForAllPlayers() { BuzzInAllowed = true; ResetBuzzers(); } [NetworkCallable] public void PlayerBuzzedIn(int PlayerNumber) { int PlayerIndex = PlayerNumber - 1; if (!BuzzInAllowed || !PlayerBuzzInAllowed[PlayerIndex]) { return; } // Prevent new buzz-ins and store which player is currently buzzed in. BuzzInAllowed = false; PlayerBuzzInAllowed[PlayerIndex] = false; _BuzzedInPlayer = PlayerNumber; RequestSerialization(); NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)PlayerPodiums[PlayerIndex], NetworkEventTarget.All, "EnableBuzzInEffect", true); // Play the buzzer sound globally. SendCustomNetworkEvent(NetworkEventTarget.All, nameof(PlaySFX), SFXEventType.Buzzer); } public void WaitForBuzzInsWithoutLastPlayer() { BuzzInAllowed = true; NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)PlayerPodiums[_BuzzedInPlayer - 1], NetworkEventTarget.All, "EnableBuzzInEffect", false); _BuzzedInPlayer = -1; RequestSerialization(); } public void EndBuzzInPeriod() { BuzzInAllowed = false; ResetBuzzers(); } public void ResetBuzzers() { for (int i = 0; i < PlayerPodiums.Length; i++) { PlayerBuzzInAllowed[i] = true; } _BuzzedInPlayer = -1; } public void PlayWhereInTheWorld() { SendCustomNetworkEvent(NetworkEventTarget.All, nameof(PlayMusic), MusicEventType.WhereInTheWorld); } public void PlayRockapellaIdent() { SendCustomNetworkEvent(NetworkEventTarget.All, nameof(PlayMusic), MusicEventType.RockapellaIdent); } [NetworkCallable] public void PlayMusic(MusicEventType MusicEvent) { MusicPlayer.Stop(); switch (MusicEvent) { case MusicEventType.WhereInTheWorld: MusicPlayer.clip = WhereInTheWorld; break; case MusicEventType.RockapellaIdent: MusicPlayer.clip = RockapellaIdent; break; default: MusicPlayer.clip = null; break; } if (MusicPlayer.clip != null) MusicPlayer.Play(); } [NetworkCallable] public void PlaySFX(SFXEventType SFXEvent) { SFXPlayer.Stop(); switch (SFXEvent) { case SFXEventType.Buzzer: SFXPlayer.clip = BuzzerSound; break; default: SFXPlayer.clip = null; break; } if (SFXPlayer.clip != null) SFXPlayer.Play(); } public override void OnPickupUseDown() { _AdminPanel.SetActive(!_AdminPanel.activeSelf); base.OnPickupUseDown(); } }