using System; using System.Collections.Generic; using System.Linq; using Firebase.Database; using Firebase.Extensions; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TMPro; using UnityEngine; /// /// This is the game state manager on the phone side /// public class GameManager : MonoBehaviour { private List players = new(); public Player currentPlayer = null; [Header("Other component")] public float explanationTime = 4f; private float currentExplanationTime = 0; [Header("Home Connection Component")] public TMP_InputField roomCodeField; public TextMeshProUGUI roomError; public TMP_InputField playerNameField; public TextMeshProUGUI nameError; public UnityEngine.UI.Button submitNewPlayer; [Header("WaitingRoom Component")] public TextMeshProUGUI listPlayersUI; public GameObject submitStartGame; [Header("Explanation Component")] public TextMeshProUGUI counterExplanation; [Header("MakeProposition Component")] public TextMeshProUGUI counterMakeProposition; [Header("Pages")] public GameObject HomeConnection; public GameObject WaitingRoom; public GameObject BeforeStart; public GameObject TakePicture; public GameObject VotePicture; public GameObject WaitingOtherPlayers; public GameObject EndGame; private DatabaseReference realtimeDB; public Room myRoom; private DatabaseReference myOnlineRoom; private DateTime endOfViewDate = DateTime.MinValue; private void Awake() { FirebaseInitializer.Instance.onFirebaseReady += Initialize; } private void Start() { currentExplanationTime = explanationTime; HomeConnection.SetActive(true); WaitingRoom.SetActive(false); BeforeStart.SetActive(false); TakePicture.SetActive(false); VotePicture.SetActive(false); WaitingOtherPlayers.SetActive(false); EndGame.SetActive(false); submitNewPlayer.interactable = false; } private void OnApplicationQuit() { myOnlineRoom.Child("players").Child(currentPlayer.id).RemoveValueAsync().ContinueWithOnMainThread(task => { Debug.Log($"delete player {currentPlayer.name}"); if (myOnlineRoom != null) { myOnlineRoom.ValueChanged -= OnRoomUpdate; } }); } private void Update() { if (myRoom.currentState == (int)GameState.Explanation && endOfViewDate != DateTime.MinValue) { TimeSpan duration = endOfViewDate - DateTime.Now; counterExplanation.text = ((int)duration.TotalSeconds).ToString("D1"); if (duration.TotalMilliseconds <= 0) { Debug.Log("It's time to make proposition !"); endOfViewDate = DateTime.MinValue; } } if (myRoom.currentState == (int)GameState.MakeProposition && endOfViewDate != DateTime.MinValue) { TimeSpan duration = endOfViewDate - DateTime.Now; counterMakeProposition.text = ((int)duration.TotalSeconds).ToString("D1"); if (duration.TotalMilliseconds <= 0) { Debug.Log("It's time to finish proposition !"); endOfViewDate = DateTime.MinValue; } } } private void Initialize() { FirebaseInitializer.Instance.onFirebaseReady -= Initialize; realtimeDB = FirebaseDatabase.DefaultInstance.RootReference; Debug.Log("Realtime DB initialized"); submitNewPlayer.interactable = true; } /// /// Send your name and game room to the server /// public void PlayerValidateNameAndServerRoom(string _name, string _code) { nameError.gameObject.SetActive(false); roomError.gameObject.SetActive(false); if (string.IsNullOrEmpty(_name)) { Debug.LogError("Player name is empty", this); nameError.text = "You have to put a valid name"; nameError.gameObject.SetActive(true); return; } if (string.IsNullOrEmpty(_code)) { Debug.LogError("Room code is empty", this); roomError.text = "You have to put a room code"; roomError.gameObject.SetActive(true); return; } currentPlayer = new Player(_name); //check if the room exists, if not display an error message CheckIfRoomExists(_code, room => { if (room == null) { Debug.LogError("The room doesn't exists"); roomError.text = "Error: the room doesn't exists"; roomError.gameObject.SetActive(true); } else { myOnlineRoom = realtimeDB.Child("rooms").Child(_code); //subscribe to it myOnlineRoom.ValueChanged += OnRoomUpdate; //if room exists, join it JoinRoom(() => { myRoom.currentState = (int)GameState.WaitingForOtherPlayersToJoin; players.Add(currentPlayer); WaitingRoom.SetActive(true); HomeConnection.SetActive(false); }); } }); } private void CheckIfRoomExists(string _roomCode, Action callback_Room) { realtimeDB.Child("rooms").Child(_roomCode).GetValueAsync().ContinueWithOnMainThread(task => { if (task.IsFaulted) { Debug.LogException(task.Exception); } else if (task.IsCompleted) { DataSnapshot snapshot = task.Result; if (snapshot == null) { callback_Room?.Invoke(null); } else { callback_Room?.Invoke(JsonUtility.FromJson(snapshot.GetRawJsonValue())); } } }); } /// /// Add this player to the room /// private void JoinRoom(Action callback_OnRoomJoined) { string JSON = JsonUtility.ToJson(currentPlayer); Debug.Log(JSON); try { myOnlineRoom.Child("players").Child(currentPlayer.id).SetRawJsonValueAsync(JSON).ContinueWithOnMainThread(task => { if (task.IsFaulted) { Debug.LogException(task.Exception); } else { Debug.Log($"{currentPlayer.name} has been added to the room", this); callback_OnRoomJoined?.Invoke(); } }); } catch (Exception ex) { Debug.LogException(ex); } } /// /// Call this only by the first player /// public void StartGame() { // send Start Game myRoom.SetPlayersAreReady(1); string JSON = JsonUtility.ToJson(myRoom); Debug.Log(JSON); try { SendCurrentState(GameState.Explanation, () => { Debug.Log($"start the game", this); myRoom.currentState = (int)GameState.Explanation; WaitingRoom.SetActive(false); BeforeStart.SetActive(true); }); } catch (Exception ex) { Debug.LogException(ex); } } /// /// Dislay on the screen the current prompt ask to you and another player /// Also show all the camera stuff /// /// The prompt to display public void MakeAProposition(Prompt _prompt) { //currentState = GameState.MakeProposition; } /// /// Create a proposition from the picture taken and send it to server. /// Then go to next proposition (if any) or the page "WaitingForOtherPlayers" /// public void SubmitProposition() { Proposition temp = new Proposition(); } /// /// Display the voting page /// public void StartToVote() { } /// /// Choose one result and send it to the server /// Then go to the next vote (if any) or to the page "WaitingForOtherPlayers" /// public void Vote() { } /// /// Display the UI of the end screen /// public void DisplayEndScreen() { } /// /// Automatically called when something change in your room /// private void OnRoomUpdate(object sender, ValueChangedEventArgs e) { Debug.Log("begin OnRoomUpdate"); try { if (e?.Snapshot?.GetRawJsonValue() != null) { string JSON = e.Snapshot.GetRawJsonValue(); myRoom = JsonConvert.DeserializeObject(e.Snapshot.GetRawJsonValue()); } } catch (Exception ex) { Debug.LogException(ex); } if (myRoom == null) { Debug.Log("myroom is null"); return; } switch (myRoom.currentState) { case (int)GameState.EnteringName: { if (EndGame.activeInHierarchy) { EndGame.SetActive(false); HomeConnection.SetActive(true); } break; } case (int)GameState.WaitingForOtherPlayersToJoin: { CheckIfIAmTheFirst(myRoom.GetPlayerList()); UpdateDisplayedListUser(myRoom.GetPlayerList()); break; } case (int)GameState.Explanation: { if (EndGame.activeInHierarchy) { EndGame.SetActive(false); } WaitingRoom.SetActive(false); BeforeStart.SetActive(true); endOfViewDate = DateTime.Now.AddSeconds(4); break; } case (int)GameState.MakeProposition: { if (BeforeStart.activeInHierarchy) { BeforeStart.SetActive(false); TakePicture.SetActive(true); endOfViewDate = DateTime.Now.AddSeconds(60); } break; } } } private void UpdateDisplayedListUser(List players) { listPlayersUI.text = string.Empty; for (int i = 0; i < players.Count; i++) { listPlayersUI.text += "\n" + players[i].name; } } private void CheckIfIAmTheFirst(List players) { bool isFirst = false; if (players.Count > 1) { List sortedList = players.OrderBy(x => x.creationDate).ToList(); if (sortedList[0].id == currentPlayer.id) { isFirst = true; } } if (isFirst) { submitStartGame.SetActive(true); } } public void SendCurrentState(GameState state, Action callback_oncCurrentStateSent) { myOnlineRoom.Child("currentState").SetValueAsync((int)state).ContinueWithOnMainThread(task => { if (task.IsFaulted) { Debug.LogException(task.Exception); } else { callback_oncCurrentStateSent?.Invoke(); } }); ; } public void OnClickSubmitSignIn() { string playerName = playerNameField.text; string roomCode = roomCodeField.text; PlayerValidateNameAndServerRoom(playerName, roomCode); } public void onClickSamePlayers() { myRoom.currentState = (int)GameState.Explanation; myRoom.currentQuestion = 2; myRoom.questions = null; string json = JsonUtility.ToJson(myRoom); myOnlineRoom.SetRawJsonValueAsync(json).ContinueWithOnMainThread(task => { if (task.IsFaulted) { Debug.LogException(task.Exception); } }); } public void onClickNewPlayers() { myRoom.currentState = (int)GameState.EnteringName; myRoom.currentQuestion = 0; myRoom.questions = null; myRoom.players = null; string json = JsonUtility.ToJson(myRoom); myOnlineRoom.SetRawJsonValueAsync(json).ContinueWithOnMainThread(task => { if (task.IsFaulted) { Debug.LogException(task.Exception); } }); } } public enum GameState { EnteringName = 0, WaitingForOtherPlayersToJoin = 1, Explanation = 2, MakeProposition = 3, PropositionsSent = 4, MakeVote = 5, VoteSent = 6, Score = 7 }