243 lines
9.2 KiB
C#
243 lines
9.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Firebase.Database;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
|
|
public class VotingPage : MonoBehaviour
|
|
{
|
|
[Header("Scene References")]
|
|
public PropositionFrame proposition1;
|
|
public PropositionFrame proposition2;
|
|
public TextMeshProUGUI currentPromptLabel;
|
|
public TextMeshProUGUI timerLabel;
|
|
|
|
[Header("Asset References")]
|
|
public PromptList promptList;
|
|
|
|
[Header("Settings")]
|
|
public float votingTime = 20;
|
|
|
|
private Queue<Question> remainingQuestions = new Queue<Question>();
|
|
private Question currentQuestion = null;
|
|
|
|
private DatabaseReference roomRef;
|
|
private Dictionary<string, Player> currentPlayers; // All the current playing players
|
|
|
|
private DateTime endOfTimer = DateTime.MinValue;
|
|
|
|
private Action OnVoteEnded;
|
|
|
|
private bool allPlayersHaveVotedForCurrentQuestion = false;
|
|
|
|
/// <summary>
|
|
/// Is the number of questions for this game sessions
|
|
/// </summary>
|
|
private int numberOfQuestions = 0;
|
|
|
|
private void Update()
|
|
{
|
|
// If there is no question displayed or the timer is not started, return early.
|
|
if (currentQuestion == null || endOfTimer == DateTime.MinValue)
|
|
return;
|
|
|
|
if (DateTime.Now < endOfTimer)
|
|
{
|
|
TimeSpan duration = endOfTimer - DateTime.Now;
|
|
timerLabel.text = ((int)duration.TotalSeconds).ToString("D2");
|
|
|
|
if (allPlayersHaveVotedForCurrentQuestion && endOfTimer > DateTime.Now.AddSeconds(4))
|
|
{
|
|
Debug.Log("All players have voted. So I put only 4sec to look at the winner.", this);
|
|
endOfTimer = DateTime.Now.AddSeconds(4);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EndCurrentQuestion();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// End current question and timer and go to next question (or end the vote if there is no more questions)
|
|
/// </summary>
|
|
private void EndCurrentQuestion()
|
|
{
|
|
timerLabel.text = "0";
|
|
if (remainingQuestions.Count > 0)
|
|
{
|
|
currentQuestion = remainingQuestions.Dequeue();
|
|
ShowNextQuestion();
|
|
}
|
|
else
|
|
{
|
|
OnVoteEnded?.Invoke();
|
|
OnVoteEnded = null;
|
|
gameObject.SetActive(false);
|
|
|
|
for (int i = 0; i < numberOfQuestions; i++)
|
|
{
|
|
roomRef.Child("questions").Child(i.ToString()).ValueChanged -= OnQuestionDataUpdate;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes the voting page with necessary data, such as the room reference, current players,
|
|
/// questions, and a callback function for when the voting ends.
|
|
/// </summary>
|
|
/// <param name="_roomRef">Reference to the Firebase room database.</param>
|
|
/// <param name="_currentPlayers">Dictionary of current players.</param>
|
|
/// <param name="_questions">Dictionary of questions associated with their IDs.</param>
|
|
/// <param name="_callback_OnVoteEnded">Callback function to invoke when the voting ends.</param>
|
|
public void ShowVotingPage(DatabaseReference _roomRef, Dictionary<string, Player> _currentPlayers, Dictionary<int, Question> _questions, Action _callback_OnVoteEnded)
|
|
{
|
|
Debug.Log("Initializing voting page");
|
|
roomRef = _roomRef;
|
|
currentPlayers = _currentPlayers;
|
|
OnVoteEnded = _callback_OnVoteEnded;
|
|
allPlayersHaveVotedForCurrentQuestion = false;
|
|
endOfTimer = DateTime.MinValue;
|
|
remainingQuestions.Clear();
|
|
currentQuestion = null;
|
|
|
|
Question[] _questionArray = _questions.Values.ToArray();
|
|
numberOfQuestions = _questionArray.Length;
|
|
|
|
for (int i = 0; i < _questionArray.Length; i++)
|
|
{
|
|
remainingQuestions.Enqueue(_questionArray[i]);
|
|
roomRef.Child("questions").Child(i.ToString()).ValueChanged += OnQuestionDataUpdate;
|
|
}
|
|
|
|
gameObject.SetActive(true);
|
|
currentQuestion = remainingQuestions.Dequeue();
|
|
ShowNextQuestion();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Displays the next question on the screen, updating the prompt, timer, and proposition frames.
|
|
/// </summary>
|
|
private void ShowNextQuestion()
|
|
{
|
|
// Set the current question ID in the Firebase room database.
|
|
roomRef.Child("currentQuestionId").SetValueAsync(currentQuestion.index);
|
|
|
|
// Update the prompt text based on the current question's prompt ID.
|
|
Debug.Log($"Show Question {currentQuestion.promptId}", this);
|
|
Prompt currentPrompt = promptList.GetPromptById(currentQuestion.promptId);
|
|
currentPromptLabel.text = RoomManager.Instance.myRoom.promptsLanguage == "en" ? currentPrompt.en : currentPrompt.fr;
|
|
|
|
Debug.Log($"Prompt is {currentPromptLabel.text}", this);
|
|
|
|
// Initialize the proposition frames with proposition data.
|
|
InitializeProposition(proposition1, currentQuestion.propositions[0]);
|
|
InitializeProposition(proposition2, currentQuestion.propositions[1]);
|
|
|
|
// Set the timer to end after the specified voting time.
|
|
endOfTimer = DateTime.Now.AddSeconds(votingTime);
|
|
|
|
//reset the count of voters
|
|
allPlayersHaveVotedForCurrentQuestion = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a proposition frame with the provided proposition data, updating it if available,
|
|
/// or handling the case when there is no proposition.
|
|
/// </summary>
|
|
/// <param name="proposition">The PropositionFrame to initialize or update.</param>
|
|
/// <param name="propositionData">The Proposition data to use for initialization or update.</param>
|
|
private void InitializeProposition(PropositionFrame proposition, Proposition propositionData)
|
|
{
|
|
if (propositionData != null)
|
|
{
|
|
proposition.SetProposition(propositionData);
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("User has given no proposition", this);
|
|
proposition.SetNoProposition();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles updates to a question, such as when someone has voted for it.
|
|
/// </summary>
|
|
/// <param name="sender">The sender of the event.</param>
|
|
/// <param name="_questionRef">The ValueChangedEventArgs containing the updated question reference.</param>
|
|
private void OnQuestionDataUpdate(object sender, ValueChangedEventArgs _questionRef)
|
|
{
|
|
string JSON = _questionRef.Snapshot.GetRawJsonValue();
|
|
|
|
if (string.IsNullOrEmpty(JSON))
|
|
return;
|
|
|
|
Question question = Newtonsoft.Json.JsonConvert.DeserializeObject<Question>(JSON);
|
|
|
|
// If someone succeeded in voting for another question than the one displayed, ignore it.
|
|
if (question.index != currentQuestion.index)
|
|
return;
|
|
|
|
currentQuestion.propositions = question.propositions;
|
|
|
|
if (currentQuestion.propositions.Count > 0)
|
|
{
|
|
// Update the proposition voters for both propositions.
|
|
UpdatePropositionVoters(proposition1, currentQuestion.propositions[0]);
|
|
UpdatePropositionVoters(proposition2, currentQuestion.propositions[1]);
|
|
}
|
|
|
|
//every players BUT the one who have created the propositions
|
|
if (RoomManager.Instance.myRoom.NumbersOfVotersForQuestion(currentQuestion) >= currentPlayers.Count - 2)
|
|
{
|
|
allPlayersHaveVotedForCurrentQuestion = true;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the voters for a specific proposition frame based on the provided proposition data.
|
|
/// If the proposition data is not null, it retrieves the list of voters and updates the frame.
|
|
/// If there is no proposition data, it logs a message indicating that the user has not given a proposition.
|
|
/// </summary>
|
|
/// <param name="proposition">The PropositionFrame to update.</param>
|
|
/// <param name="propositionData">The Proposition data used to update voters for the proposition frame.</param>
|
|
private void UpdatePropositionVoters(PropositionFrame proposition, Proposition propositionData)
|
|
{
|
|
if (propositionData != null)
|
|
{
|
|
List<Player> voters = GetVotersForProposition(propositionData);
|
|
proposition.UpdateVoters(voters);
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("User has given no proposition", this);
|
|
// Handle the case when there is no proposition
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the list of players who have voted for a specific proposition based on the provided proposition data.
|
|
/// It checks if the proposition data contains a list of voters and then looks up player information in the current players dictionary.
|
|
/// </summary>
|
|
/// <param name="propositionData">The Proposition data for which to retrieve voters.</param>
|
|
/// <returns>The list of players who voted for the proposition.</returns>
|
|
private List<Player> GetVotersForProposition(Proposition propositionData)
|
|
{
|
|
List<Player> voters = new List<Player>();
|
|
|
|
if (propositionData.voters != null)
|
|
{
|
|
foreach (string playerId in propositionData.voters)
|
|
{
|
|
voters.Add(currentPlayers[playerId]);
|
|
Debug.Log($"updating number of voters for: {propositionData.owner.name}'s propositions. They are now {voters.Count}.");
|
|
}
|
|
}
|
|
|
|
return voters;
|
|
}
|
|
}
|
|
|