using System; using System.Collections.Generic; using System.Globalization; using UnityEngine; public class LocalPlayerData { /// <summary> /// last known email used /// </summary> public string LastKnownEmail = ""; /// <summary> /// last known username used /// </summary> public string LastKnownUsername = "Guest"; /// <summary> /// queue of the 10 most recent local scores /// </summary> public Queue<Score> RecentLocalScores = new(10); /// <summary> /// queue of the 10 most recent online scores, /// used in user rating calculation and accuracy display stats /// </summary> public Queue<Score> RecentOnlineScores = new(10); /// <summary> /// queue of the best online scores, /// used in user rating calculation and accuracy display stats /// </summary> public Queue<Score> BestOnlineScores = new(30); /// <summary> /// loads player data from player prefs and database /// </summary> public void LoadFromTheWorld() { // load user data, possibly from the backend var possibleUser = GameManager.Instance.Backend.GetUser(); var currentKnownEmail = string.Empty; var currentKnownUsername = string.Empty; if (possibleUser != null) { currentKnownEmail = possibleUser.Email; currentKnownUsername = GameManager.Instance.Backend.GetUsername(); } var lastStoredEmail = PlayerPrefs.GetString("LastKnownEmail", ""); var lastStoredUsername = PlayerPrefs.GetString("LastKnownUsername", "Guest"); LastKnownEmail = string.IsNullOrEmpty(currentKnownEmail) ? lastStoredEmail : currentKnownEmail; LastKnownUsername = string.IsNullOrEmpty(currentKnownUsername) ? lastStoredUsername : currentKnownUsername; // load local scores RecentLocalScores.Clear(); for (var idx = 0; idx < 10; idx++) { var timestampRaw = PlayerPrefs.GetString($"RecentLocalScores_{idx}_Timestamp", ""); if (timestampRaw == "") continue; var timestamp = DateTime.TryParseExact(timestampRaw, "s", CultureInfo.InvariantCulture, DateTimeStyles.None, out var t) ? t : DateTime.MinValue; if (timestamp == DateTime.MinValue) continue; var noOfRounds = PlayerPrefs.GetInt($"RecentLocalScores_{idx}_NoOfRounds", -1); var l = PlayerPrefs.GetFloat($"RecentLocalScores_{idx}_AvgLightnessAccuracy", -1f); var c = PlayerPrefs.GetFloat($"RecentLocalScores_{idx}_AvgChromaAccuracy", -1f); var h = PlayerPrefs.GetFloat($"RecentLocalScores_{idx}_AvgHueAccuracy", -1f); // if any of the values are invalid, don't add the score if (noOfRounds < 0 || l < 0 || c < 0 || h < 0) continue; RegisterLocalScore(new Score(timestamp, noOfRounds, l, c, h)); } // load online scores RecentOnlineScores.Clear(); GameManager.Instance.Backend.GetRecentScores((dtr, recentOnlineScores) => { foreach (var onlineScore in recentOnlineScores) { if (RecentOnlineScores.Count > 10) RecentOnlineScores.Dequeue(); RecentOnlineScores.Enqueue(onlineScore); } }); } /// <summary> /// registers a score to the player's local data /// </summary> /// <param name="score">the score to register</param> public void RegisterLocalScore(Score score) { if (RecentLocalScores.Count > 10) RecentLocalScores.Dequeue(); RecentLocalScores.Enqueue(score); } /// <summary> /// saves player data to player prefs /// </summary> public void SaveToTheWorld() { PlayerPrefs.SetString("LastKnownEmail", LastKnownEmail); PlayerPrefs.SetString("LastKnownUsername", LastKnownUsername); var idx = 0; foreach (var score in RecentLocalScores) { PlayerPrefs.SetString($"RecentLocalScores_{idx}_Timestamp", score.Timestamp.ToString("s", CultureInfo.InvariantCulture)); PlayerPrefs.SetInt($"RecentLocalScores_{idx}_NoOfRounds", score.NoOfRounds); PlayerPrefs.SetFloat($"RecentLocalScores_{idx}_AvgLightnessAccuracy", score.AvgLightnessAccuracy); PlayerPrefs.SetFloat($"RecentLocalScores_{idx}_AvgChromaAccuracy", score.AvgChromaAccuracy); PlayerPrefs.SetFloat($"RecentLocalScores_{idx}_AvgHueAccuracy", score.AvgHueAccuracy); idx++; } // online scores are already saved in the backend } public struct Score { /// <summary> /// timestamp of the score /// </summary> public DateTime Timestamp; /// <summary> /// number of rounds played (0-100) /// </summary> public int NoOfRounds; /// <summary> /// average lightness accuracy across all rounds (0-100) /// </summary> public float AvgLightnessAccuracy; /// <summary> /// average chroma accuracy across all rounds (0-100) /// </summary> public float AvgChromaAccuracy; /// <summary> /// average hue accuracy across all rounds (0-100) /// </summary> public float AvgHueAccuracy; /// <summary> /// constructor for the score struct /// </summary> /// <param name="timestamp">timestamp of the score</param> /// <param name="noOfRounds">number of rounds played (0-100)</param> /// <param name="l">average lightness accuracy across all rounds (0-100)</param> /// <param name="c">average chroma accuracy across all rounds (0-100)</param> /// <param name="h">average hue accuracy across all rounds (0-100)</param> public Score(DateTime timestamp = new(), int noOfRounds = 1, float l = 100.0f, float c = 100.0f, float h = 100.0f) { Timestamp = timestamp; NoOfRounds = noOfRounds; AvgLightnessAccuracy = l; AvgChromaAccuracy = c; AvgHueAccuracy = h; } } }