Resolve WES-117 "Persistent data handling"
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:e83ddf9a537a96b4a804a16bb7872ec1",
|
||||
"GUID:7f2d0ee6dd21e1d4eb25b71b7a749d25"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
|
||||
@@ -22,11 +22,6 @@ public class ChangeUserScreen : MonoBehaviour
|
||||
/// </summary>
|
||||
public GameObject error;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the user list
|
||||
/// </summary>
|
||||
public UserList userList;
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current selected user in the UserList
|
||||
/// </summary>
|
||||
@@ -42,7 +37,7 @@ public class ChangeUserScreen : MonoBehaviour
|
||||
/// </summary>
|
||||
void Start()
|
||||
{
|
||||
userList.Load();
|
||||
PersistentDataController.GetInstance().Load();
|
||||
error.SetActive(false);
|
||||
DisplayUsers();
|
||||
}
|
||||
@@ -57,8 +52,8 @@ public class ChangeUserScreen : MonoBehaviour
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
List<User> users = userList.GetUsers();
|
||||
currentUserIndex = userList.GetCurrentUserIndex();
|
||||
List<User> users = UserList.GetUsers();
|
||||
int currentUserIndex = UserList.IndexOf(UserList.GetCurrentUser().GetUsername());
|
||||
for (int i = 0; i < users.Count; i++)
|
||||
{
|
||||
User user = users[i];
|
||||
@@ -99,8 +94,7 @@ public class ChangeUserScreen : MonoBehaviour
|
||||
/// </summary>
|
||||
public void IChooseYou()
|
||||
{
|
||||
userList.ChangeCurrentUser(currentUserIndex);
|
||||
userList.Save();
|
||||
UserList.ChangeCurrentUser(currentUserIndex);
|
||||
SystemController.GetInstance().BackToPreviousScene();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public class CourseProgressCard : MonoBehaviour
|
||||
/// <summary>
|
||||
/// Reference to the progress so we can display a progress bar
|
||||
/// </summary>
|
||||
public Progress courseProgress;
|
||||
public PersistentDataController.SavedCourseProgress courseProgress;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the list of courses so we can query the correct course
|
||||
@@ -48,11 +48,11 @@ public class CourseProgressCard : MonoBehaviour
|
||||
/// </summary>
|
||||
void Start()
|
||||
{
|
||||
Course course = courseList.GetCourseByIndex(courseProgress.Get<CourseIndex>("courseIndex"));
|
||||
Course course = courseList.GetCourseByIndex(courseProgress.courseIndex);
|
||||
|
||||
thumbnail.sprite = course.thumbnail;
|
||||
title.text = course.title;
|
||||
progressBar.value = courseProgress.Get<float>("courseProgress");
|
||||
progressBar.value = courseProgress.progress;
|
||||
button.onClick.AddListener(selectActivity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class MinigameProgressCard : MonoBehaviour
|
||||
/// <summary>
|
||||
/// Reference to the minigame progress
|
||||
/// </summary>
|
||||
public Progress minigameProgress;
|
||||
public PersistentDataController.SavedMinigameProgress minigameProgress;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the minigame list
|
||||
@@ -49,11 +49,11 @@ public class MinigameProgressCard : MonoBehaviour
|
||||
/// </summary>
|
||||
void Start()
|
||||
{
|
||||
Minigame minigame = minigameList.GetMinigameByIndex(minigameProgress.Get<MinigameIndex>("minigameIndex"));
|
||||
Minigame minigame = minigameList.GetMinigameByIndex(minigameProgress.minigameIndex);
|
||||
|
||||
thumbnail.sprite = minigame.thumbnail;
|
||||
title.text = minigame.title;
|
||||
List<Score> highscores = minigameProgress.Get<List<Score>>("highestScores");
|
||||
List<Score> highscores = minigameProgress.highestScores;
|
||||
int score = highscores.Count > 0 ? highscores[0].scoreValue : 0;
|
||||
highscore.text = $"Topscore: {score}";
|
||||
button.onClick.AddListener(selectActivity);
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// A class for holding all progress belonging to a user
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Progress
|
||||
{
|
||||
/// <summary>
|
||||
/// A helper class for handling the stored progress
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
protected class DataEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The key, used to reference the data object
|
||||
/// </summary>
|
||||
public string key;
|
||||
|
||||
/// <summary>
|
||||
/// The object, representated as a list of byte (which can be serialized)
|
||||
/// </summary>
|
||||
public List<byte> bytes = new List<byte>();
|
||||
|
||||
public DataEntry(string key, byte[] data)
|
||||
{
|
||||
this.key = key;
|
||||
this.bytes = new List<byte>(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entries in the <c>Progress</c> object
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private List<DataEntry> entries = new List<DataEntry>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the value of a certain key,
|
||||
/// or add a new value if the key was not present
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the data to be added/updated</typeparam>
|
||||
/// <param name="key">The key, used for referencing the data</param>
|
||||
/// <param name="data">The object of type <typeparamref name="T"/></param>
|
||||
/// <returns><c>true</c> if successful, <c>false</c> otherwise</returns>
|
||||
public bool AddOrUpdate<T>(string key, T data)
|
||||
{
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
DataEntry entry = entries.Find(x => x.key == key);
|
||||
|
||||
// Hacky serialization stuff
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
bf.Serialize(ms, data);
|
||||
if (entry != null)
|
||||
{
|
||||
entry.bytes.Clear();
|
||||
entry.bytes.AddRange(ms.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(new DataEntry(key, ms.ToArray()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the data object of a certain key
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the data object</typeparam>
|
||||
/// <param name="key">The key referencing the data object</param>
|
||||
/// <returns>The data, cast to a type <typeparamref name="T"/></returns>
|
||||
/// <exception cref="KeyNotFoundException"></exception>
|
||||
public T Get<T>(string key)
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
// Find the correct key
|
||||
foreach (DataEntry entry in entries)
|
||||
{
|
||||
if (entry.key == key)
|
||||
{
|
||||
// Hacky serialization stuff
|
||||
byte[] data = entry.bytes.ToArray();
|
||||
ms.Write(data, 0, data.Length);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
return (T)bf.Deserialize(ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Raise an exception when key is not found
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether a key is present
|
||||
/// </summary>
|
||||
/// <param name="key">The key to check</param>
|
||||
/// <returns>true if a item can be found with the specified key</returns>
|
||||
public bool Has(string key)
|
||||
{
|
||||
return entries.Find(x => x.key == key) != null;
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
/// <summary>
|
||||
/// SystemController singleton
|
||||
/// </summary>
|
||||
public class SystemController
|
||||
{
|
||||
/// <summary>
|
||||
/// The instance controlling the singleton
|
||||
/// </summary>
|
||||
private static SystemController instance = null;
|
||||
|
||||
/// <summary>
|
||||
/// Stack of the loaded scenes, used to easily go back to previous scenes
|
||||
/// </summary>
|
||||
private Stack<int> sceneStack = new Stack<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Get the instance loaded by the singleton
|
||||
/// </summary>
|
||||
/// <returns>SystemController instance</returns>
|
||||
public static SystemController GetInstance()
|
||||
{
|
||||
// Create a new instance if non exists
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new SystemController();
|
||||
instance.sceneStack.Push(SceneManager.GetActiveScene().buildIndex);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the scene and push on the stack
|
||||
/// </summary>
|
||||
/// <param name="scenePath">Path of the scene</param>
|
||||
public void LoadNextScene(string scenePath)
|
||||
{
|
||||
LoadNextScene(SceneUtility.GetBuildIndexByScenePath(scenePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the scene and push on the stack
|
||||
/// </summary>
|
||||
/// <param name="sceneIndex">Buildindex of the scene</param>
|
||||
public void LoadNextScene(int sceneIndex)
|
||||
{
|
||||
sceneStack.Push(sceneIndex);
|
||||
SceneManager.LoadScene(sceneIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swap the current scene with the new scene on the stack
|
||||
/// </summary>
|
||||
/// <param name="scenePath">Path of the scene</param>
|
||||
public void SwapScene(string scenePath)
|
||||
{
|
||||
SwapScene(SceneUtility.GetBuildIndexByScenePath(scenePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swap the current scene with the new scene on the stack
|
||||
/// </summary>
|
||||
/// <param name="sceneIndex">Buildindex of the scene</param>
|
||||
public void SwapScene(int sceneIndex)
|
||||
{
|
||||
sceneStack.Pop();
|
||||
LoadNextScene(sceneIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go back to the previous scene and unload the current scene
|
||||
/// </summary>
|
||||
public void BackToPreviousScene()
|
||||
{
|
||||
sceneStack.Pop();
|
||||
|
||||
if (sceneStack.Count > 0) SceneManager.LoadScene(sceneStack.Peek());
|
||||
else Application.Quit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go back to a specific scene, unloading all the scenes on the way
|
||||
/// </summary>
|
||||
/// <param name="scenePath">Path of the scene</param>
|
||||
public void BackToScene(string scenePath)
|
||||
{
|
||||
BackToScene(SceneUtility.GetBuildIndexByScenePath(scenePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go back to a specific scene, unloading all the scene on the way
|
||||
/// </summary>
|
||||
/// <param name="sceneIndex">Buildindex of the scene</param>
|
||||
public void BackToScene(int sceneIndex)
|
||||
{
|
||||
while (0 < sceneStack.Count && sceneStack.Peek() != sceneIndex) sceneStack.Pop();
|
||||
|
||||
if (sceneStack.Count > 0) SceneManager.LoadScene(sceneStack.Peek());
|
||||
else Application.Quit();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf5ea73aa43049e45a0ad926db15f315
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -2,40 +2,45 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using static PersistentDataController;
|
||||
|
||||
/// <summary>
|
||||
/// A class holding all information of a user
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class User
|
||||
{
|
||||
/// <summary>
|
||||
/// User nickname
|
||||
/// Reference to the user stored data record
|
||||
/// </summary>
|
||||
public string username;
|
||||
private SavedUserData storedUserData;
|
||||
|
||||
/// <summary>
|
||||
/// The avatar of the user
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public Sprite avatar;
|
||||
/// <param name="data">Reference to the user stored data record</param>
|
||||
public User(SavedUserData data)
|
||||
{
|
||||
this.storedUserData = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The total playtime of the user
|
||||
/// Get the username
|
||||
/// </summary>
|
||||
/// <remarks>TODO: needs to be implemented</remarks>
|
||||
public double playtime;
|
||||
/// <returns></returns>
|
||||
public string GetUsername() { return storedUserData.username; }
|
||||
|
||||
/// <summary>
|
||||
/// List of courses a user started/completed
|
||||
/// Get the total playtime
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public List<Progress> courses = new List<Progress>();
|
||||
/// <returns></returns>
|
||||
public double GetPlaytime() { return storedUserData.playtime; }
|
||||
|
||||
/// <summary>
|
||||
/// List of minigames a user played
|
||||
/// Get the avatar
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public List<Progress> minigames = new List<Progress>();
|
||||
/// <returns></returns>
|
||||
public Sprite GetAvatar() { return UserList.AVATARS[storedUserData.avatarIndex]; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all recently started courses
|
||||
@@ -46,10 +51,10 @@ public class User
|
||||
{
|
||||
// TODO: return better results (for now only return all courses)
|
||||
List<Tuple<CourseIndex, float>> recentCourses = new List<Tuple<CourseIndex, float>>();
|
||||
foreach (Progress courseProgress in courses)
|
||||
foreach (var courseProgress in storedUserData.courses)
|
||||
{
|
||||
CourseIndex idx = courseProgress.Get<CourseIndex>("courseIndex");
|
||||
float progress = courseProgress.Get<float>("courseProgress");
|
||||
CourseIndex idx = courseProgress.courseIndex;
|
||||
float progress = courseProgress.progress;
|
||||
recentCourses.Add(Tuple.Create<CourseIndex, float>(idx, progress));
|
||||
}
|
||||
return recentCourses.Take(3).ToList();
|
||||
@@ -63,31 +68,58 @@ public class User
|
||||
public List<Tuple<CourseIndex, float>> GetRecommendedCourses()
|
||||
{
|
||||
List<Tuple<CourseIndex, float>> recommenedCourses = new List<Tuple<CourseIndex, float>>();
|
||||
if (courses.Count == 0)
|
||||
if (storedUserData.courses.Count == 0)
|
||||
{
|
||||
recommenedCourses.Add(Tuple.Create<CourseIndex, float>(CourseIndex.FINGERSPELLING, 0.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: return better results (for now only return all courses)
|
||||
foreach (Progress courseProgress in courses)
|
||||
foreach (var courseProgress in storedUserData.courses)
|
||||
{
|
||||
CourseIndex idx = courseProgress.Get<CourseIndex>("courseIndex");
|
||||
float progress = courseProgress.Get<float>("courseProgress");
|
||||
CourseIndex idx = courseProgress.courseIndex;
|
||||
float progress = courseProgress.progress;
|
||||
recommenedCourses.Add(Tuple.Create<CourseIndex, float>(idx, progress));
|
||||
}
|
||||
}
|
||||
return recommenedCourses.Take(3).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the progress of all courses the user did
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<SavedCourseProgress> GetCourses()
|
||||
{
|
||||
return storedUserData.courses;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the progress of a certain course
|
||||
/// </summary>
|
||||
/// <param name="courseIndex">Index of course</param>
|
||||
/// <returns><c>Progress</c> belonging to the <c>courseIndex</c>, <c>null</c> if course was not found</returns>
|
||||
public Progress GetCourseProgress(CourseIndex courseIndex)
|
||||
public SavedCourseProgress GetCourseProgress(CourseIndex courseIndex)
|
||||
{
|
||||
return courses.Find((p) => p.Get<CourseIndex>("courseIndex") == courseIndex);
|
||||
return storedUserData.courses.Find((p) => p.courseIndex == courseIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add new progress of a course
|
||||
/// </summary>
|
||||
/// <param name="progress">SavedCourseProgress data record</param>
|
||||
public void AddCourseProgress(SavedCourseProgress progress)
|
||||
{
|
||||
storedUserData.courses.Add(progress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the progress of all minigames the user did
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<SavedMinigameProgress> GetMinigames()
|
||||
{
|
||||
return storedUserData.minigames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -95,8 +127,17 @@ public class User
|
||||
/// </summary>
|
||||
/// <param name="minigameIndex">Index of the minigame</param>
|
||||
/// <returns><c>Progress</c> belonging to the <c>minigameIndex</c>, <c>null</c> if minigame was not found</returns>
|
||||
public Progress GetMinigameProgress(MinigameIndex minigameIndex)
|
||||
public SavedMinigameProgress GetMinigameProgress(MinigameIndex minigameIndex)
|
||||
{
|
||||
return minigames.Find((p) => p.Get<MinigameIndex>("minigameIndex") == minigameIndex);
|
||||
return storedUserData.minigames.Find((p) => p.minigameIndex == minigameIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add new progress of a minigame
|
||||
/// </summary>
|
||||
/// <param name="progress">SavedMinigameProgress data record</param>
|
||||
public void AddMinigameProgress(SavedMinigameProgress progress)
|
||||
{
|
||||
storedUserData.minigames.Add(progress);
|
||||
}
|
||||
}
|
||||
|
||||
19
Assets/Accounts/Scripts/UserAvatarList.cs
Normal file
19
Assets/Accounts/Scripts/UserAvatarList.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Container to hold a reference to all possible user avatar sprites
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Create new Scriptable/User Avatar List")]
|
||||
public class UserAvatarList : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// List of avatar sprites
|
||||
/// </summary>
|
||||
public List<Sprite> avatars = new List<Sprite>();
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
UserList.AVATARS = avatars;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d887bc641cc7a8f4abf9d4eb34d26923
|
||||
guid: 81765ea55baf15d45b01b02187b02429
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -8,11 +8,6 @@ using UnityEngine.UI;
|
||||
/// </summary>
|
||||
public class UserCard : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Reference to the userlist
|
||||
/// </summary>
|
||||
public UserList userList;
|
||||
|
||||
/// <summary>
|
||||
/// User to upload info into this card
|
||||
/// </summary>
|
||||
@@ -53,8 +48,8 @@ public class UserCard : MonoBehaviour
|
||||
/// </summary>
|
||||
void Start()
|
||||
{
|
||||
avatar.sprite = user.avatar;
|
||||
username.text = user.username;
|
||||
avatar.sprite = user.GetAvatar();
|
||||
username.text = user.GetUsername();
|
||||
button.onClick.AddListener(selectUser);
|
||||
}
|
||||
|
||||
@@ -63,10 +58,9 @@ public class UserCard : MonoBehaviour
|
||||
/// </summary>
|
||||
public void DeleteUser()
|
||||
{
|
||||
if (userList.DeleteUser(user))
|
||||
if (UserList.DeleteUser(user.GetUsername()))
|
||||
{
|
||||
// User is removed, update and save
|
||||
userList.Save();
|
||||
updateUserCardContainer();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -34,20 +34,9 @@ public class UserCreationScreen : MonoBehaviour
|
||||
/// </summary>
|
||||
public GameObject avatarPrefab;
|
||||
|
||||
/// <summary>
|
||||
/// List of all sprites that are supported as avatars
|
||||
/// </summary>
|
||||
public List<Sprite> sprites = new List<Sprite>();
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the UserList ScriptableObject
|
||||
/// </summary>
|
||||
public UserList users;
|
||||
|
||||
/// <summary>
|
||||
/// Current selected avatar
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private int selectedAvatar = 0;
|
||||
|
||||
/// <summary>
|
||||
@@ -63,7 +52,7 @@ public class UserCreationScreen : MonoBehaviour
|
||||
{
|
||||
errorMessage.SetActive(false);
|
||||
|
||||
for (int i = 0; i < sprites.Count; i++)
|
||||
for (int i = 0; i < UserList.AVATARS.Count; i++)
|
||||
{
|
||||
// Create instance of prefab
|
||||
GameObject instance = GameObject.Instantiate(avatarPrefab, avatarsContainer);
|
||||
@@ -79,7 +68,7 @@ public class UserCreationScreen : MonoBehaviour
|
||||
// Set background color
|
||||
background.color = selectedAvatar == i ? Color.blue : Color.gray;
|
||||
// Find correct component for setting the sprite
|
||||
instance.transform.Find("Image").GetComponent<Image>().sprite = sprites[i];
|
||||
instance.transform.Find("Image").GetComponent<Image>().sprite = UserList.AVATARS[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,10 +102,10 @@ public class UserCreationScreen : MonoBehaviour
|
||||
string username = inputName.text;
|
||||
if (IsValidUsername(username))
|
||||
{
|
||||
if (users.GetUserByUsername(username) == null)
|
||||
if (UserList.GetUserByUsername(username) == null)
|
||||
{
|
||||
// Create a new entry in the UserList ScriptableObject
|
||||
users.ChangeCurrentUser(users.CreateAndAddNewUser(username, sprites[selectedAvatar]));
|
||||
UserList.AddUser(username, UserList.AVATARS[selectedAvatar]);
|
||||
SystemController.GetInstance().BackToPreviousScene();
|
||||
}
|
||||
// Warn user that username already exists
|
||||
|
||||
@@ -1,87 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Keep track of all users
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Create new Scriptable/UserList")]
|
||||
public class UserList : ScriptableObject
|
||||
public static class UserList
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to enable serialization of the UserList class
|
||||
/// (<c>ScriptableObject</c>s cannot be serialized)
|
||||
/// List of possible avatar sprites
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class StoredUserList
|
||||
{
|
||||
/// <summary>
|
||||
/// The index of the current/last logged in user in the <c>storedUsers</c> list
|
||||
/// </summary>
|
||||
public int currentUserIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// A list containing all users (which can be serialized)
|
||||
/// </summary>
|
||||
public List<User> storedUsers = new List<User>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the serializable version of <c>UserList</c>
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private StoredUserList storedUserList = new StoredUserList();
|
||||
|
||||
/// <summary>
|
||||
/// Path of the <c>.json</c>-file to store all serialized data
|
||||
/// </summary>
|
||||
public static string PATH = null;
|
||||
|
||||
/// <summary>
|
||||
/// OnEnable will make sure the <c>PATH</c>-variable is correctly initialized
|
||||
/// </summary>
|
||||
void OnEnable()
|
||||
{
|
||||
// The PATH variable can be set by the testing framework,
|
||||
// so we don't overwrite the actual userlist with test data
|
||||
if (PATH == null)
|
||||
{
|
||||
PATH = $"{Application.persistentDataPath}/users.json";
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new user
|
||||
/// </summary>
|
||||
/// <param name="name">The username of the new user</param>
|
||||
/// <param name="avatar">Reference to the user avatar</param>
|
||||
/// <returns>A newly created user</returns>
|
||||
public User CreateNewUser(string name, Sprite avatar)
|
||||
{
|
||||
User user = new User();
|
||||
user.username = name;
|
||||
user.avatar = avatar;
|
||||
return user;
|
||||
}
|
||||
public static List<Sprite> AVATARS = new List<Sprite>();
|
||||
|
||||
/// <summary>
|
||||
/// Create a new user and save (add to list)
|
||||
/// </summary>
|
||||
/// <param name="name">The username of the new user</param>
|
||||
/// <param name="username">The username of the new user</param>
|
||||
/// <param name="avatar">Reference to the user avatar</param>
|
||||
/// <returns>A newly created user</returns>
|
||||
public User CreateAndAddNewUser(string name, Sprite avatar)
|
||||
public static User AddUser(string username, Sprite avatar)
|
||||
{
|
||||
User user = CreateNewUser(name, avatar);
|
||||
storedUserList.storedUsers.Add(user);
|
||||
if (storedUserList.storedUsers.Count == 1)
|
||||
{
|
||||
storedUserList.currentUserIndex = 0;
|
||||
}
|
||||
Save();
|
||||
return user;
|
||||
PersistentDataController pdc = PersistentDataController.GetInstance();
|
||||
PersistentDataController.SavedUserData data = new PersistentDataController.SavedUserData();
|
||||
data.username = username;
|
||||
data.playtime = 0.0;
|
||||
data.avatarIndex = AVATARS.IndexOf(avatar);
|
||||
|
||||
pdc.AddUser(data);
|
||||
return new User(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,43 +35,61 @@ public class UserList : ScriptableObject
|
||||
/// </summary>
|
||||
/// <param name="username">The username of the user</param>
|
||||
/// <returns><c>User</c>-object if a user with such username was found, <c>null</c> otherwise</returns>
|
||||
public User GetUserByUsername(string username)
|
||||
public static User GetUserByUsername(string username)
|
||||
{
|
||||
foreach (User user in storedUserList.storedUsers)
|
||||
if (user.username == username) return user;
|
||||
foreach (User user in GetUsers())
|
||||
if (user.GetUsername() == username) return user;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a user by index
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the user</param>
|
||||
/// <returns>User object</returns>
|
||||
/// <exception cref="IndexOutOfRangeException"></exception>
|
||||
public static User GetUserByIndex(int index)
|
||||
{
|
||||
List<User> users = GetUsers();
|
||||
if (index < 0 || users.Count <= index)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return users[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all users currently stored
|
||||
/// </summary>
|
||||
/// <returns>A list of all users</returns>
|
||||
public List<User> GetUsers()
|
||||
public static List<User> GetUsers()
|
||||
{
|
||||
return storedUserList.storedUsers;
|
||||
PersistentDataController pdc = PersistentDataController.GetInstance();
|
||||
return pdc.GetUsers().ConvertAll((d) => new User(d));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current logged in user
|
||||
/// </summary>
|
||||
/// <returns>The current logged in user</returns>
|
||||
public User GetCurrentUser()
|
||||
public static User GetCurrentUser()
|
||||
{
|
||||
if (storedUserList.storedUsers.Count == 0)
|
||||
{
|
||||
List<User> users = GetUsers();
|
||||
if (users.Count == 0)
|
||||
return null;
|
||||
}
|
||||
return storedUserList.storedUsers[storedUserList.currentUserIndex];
|
||||
return users[PersistentDataController.GetInstance().GetCurrentUser()];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index in the userlist of the current playing user
|
||||
/// Get the index in the userlist of a user
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetCurrentUserIndex()
|
||||
public static int IndexOf(string username)
|
||||
{
|
||||
return storedUserList.currentUserIndex;
|
||||
int idx = GetUsers().FindIndex((e) => e.GetUsername() == username);
|
||||
if (idx < 0)
|
||||
throw new KeyNotFoundException();
|
||||
return idx;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -133,89 +97,66 @@ public class UserList : ScriptableObject
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the user in the userlist</param>
|
||||
/// <exception cref="IndexOutOfRangeException"></exception>
|
||||
public void ChangeCurrentUser(int index)
|
||||
public static void ChangeCurrentUser(int index)
|
||||
{
|
||||
if (0 <= index && index < storedUserList.storedUsers.Count)
|
||||
{
|
||||
storedUserList.currentUserIndex = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index < 0 || GetUsers().Count <= index)
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
PersistentDataController.GetInstance().SetCurrentUser(index, true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Change the current user
|
||||
/// </summary>
|
||||
/// <param name="user">Reference to the user in the userlist</param>
|
||||
/// <param name="index">Username of the user</param>
|
||||
/// <exception cref="KeyNotFoundException"></exception>
|
||||
public void ChangeCurrentUser(User user)
|
||||
public static void ChangeCurrentUser(string username)
|
||||
{
|
||||
int idx = storedUserList.storedUsers.IndexOf(user);
|
||||
if (idx < 0)
|
||||
{
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
storedUserList.currentUserIndex = idx;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the user
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the user in the userlist</param>
|
||||
/// <returns>true if user was successful removed, false otherwise</returns
|
||||
public bool DeleteUser(int index)
|
||||
{
|
||||
if (0 <= index && index < storedUserList.storedUsers.Count)
|
||||
{
|
||||
return DeleteUser(storedUserList.storedUsers[index]);
|
||||
}
|
||||
return false;
|
||||
int index = GetUsers().FindIndex((e) => e.GetUsername() == username);
|
||||
try { ChangeCurrentUser(index); }
|
||||
catch (IndexOutOfRangeException) { throw new KeyNotFoundException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// I am inevitable, *snap*
|
||||
/// </summary>
|
||||
/// <param name="user">Reference to the user to be removed</param>
|
||||
/// <param name="index">The index of the user in the userlist</param>
|
||||
/// <returns>true if the user was successful removed, false otherwise</returns>
|
||||
public bool DeleteUser(User user)
|
||||
/// <exception cref="IndexOutOfRangeException"></exception>
|
||||
public static bool DeleteUser(int index)
|
||||
{
|
||||
if (1 < storedUserList.storedUsers.Count)
|
||||
{
|
||||
if (storedUserList.currentUserIndex == storedUserList.storedUsers.Count - 1)
|
||||
{
|
||||
storedUserList.currentUserIndex--;
|
||||
}
|
||||
List<User> users = GetUsers();
|
||||
if (index < 0 || users.Count <= index)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return storedUserList.storedUsers.Remove(user);
|
||||
if (1 < users.Count)
|
||||
{
|
||||
PersistentDataController.GetInstance().DeleteUser(index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the users
|
||||
/// Delete a user from the userliset
|
||||
/// </summary>
|
||||
public void Save()
|
||||
/// <param name="username">Username of the user</param>
|
||||
/// <returns>true if the user was successful removed, false otherwise</returns>
|
||||
/// <exception cref="KeyNotFoundException"></exception>
|
||||
public static bool DeleteUser(string username)
|
||||
{
|
||||
string json = JsonUtility.ToJson(storedUserList);
|
||||
File.CreateText(PATH).Close();
|
||||
File.WriteAllText(PATH, json);
|
||||
int index = GetUsers().FindIndex((e) => e.GetUsername() == username);
|
||||
|
||||
try { return DeleteUser(index); }
|
||||
catch (IndexOutOfRangeException) { throw new KeyNotFoundException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override the current content of the userlist by what is stored on disk
|
||||
/// Save the current UserList
|
||||
/// </summary>
|
||||
public void Load()
|
||||
public static void Save()
|
||||
{
|
||||
storedUserList.storedUsers.Clear();
|
||||
storedUserList.currentUserIndex = -1;
|
||||
|
||||
if (!File.Exists(PATH))
|
||||
{
|
||||
Save();
|
||||
}
|
||||
string text = File.ReadAllText(PATH);
|
||||
storedUserList = JsonUtility.FromJson<StoredUserList>(text);
|
||||
PersistentDataController.GetInstance().Save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,6 @@ using UnityEngine.UI;
|
||||
/// </summary>
|
||||
public class UserProgressScreen : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Reference to the userlist
|
||||
/// </summary>
|
||||
public UserList userList;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the current user
|
||||
/// </summary>
|
||||
@@ -112,12 +107,12 @@ public class UserProgressScreen : MonoBehaviour
|
||||
void Start()
|
||||
{
|
||||
// Assign the current user
|
||||
userList.Load();
|
||||
user = userList.GetCurrentUser();
|
||||
PersistentDataController.GetInstance().Load();
|
||||
user = UserList.GetCurrentUser();
|
||||
|
||||
// Set correct displayed items
|
||||
username.text = user.username;
|
||||
avatar.sprite = user.avatar;
|
||||
username.text = user.GetUsername();
|
||||
avatar.sprite = user.GetAvatar();
|
||||
// TODO: implement total playtime
|
||||
//playtime.text = $"Totale speeltijd: {user.playtime.ToString("0.00")}";
|
||||
|
||||
@@ -126,9 +121,10 @@ public class UserProgressScreen : MonoBehaviour
|
||||
|
||||
int i = 0;
|
||||
// Display courses
|
||||
coursesContainer.SetActive(user.courses.Count > 0);
|
||||
emptyCourses.SetActive(user.courses.Count <= 0);
|
||||
foreach (Progress courseProgress in user.courses)
|
||||
var courses = user.GetCourses();
|
||||
coursesContainer.SetActive(courses.Count > 0);
|
||||
emptyCourses.SetActive(courses.Count <= 0);
|
||||
foreach (var courseProgress in courses)
|
||||
{
|
||||
// Create instance of prefab
|
||||
GameObject instance = GameObject.Instantiate(courseCardPrefab, coursesContainer.transform.Find("Viewport").Find("Content").transform);
|
||||
@@ -142,13 +138,14 @@ public class UserProgressScreen : MonoBehaviour
|
||||
// Store reference to background so we can apply fancy coloring
|
||||
Image background = instance.GetComponent<Image>();
|
||||
background.color = Color.gray;
|
||||
activities.Add(Tuple.Create(background, (int)courseProgress.Get<CourseIndex>("courseIndex")));
|
||||
activities.Add(Tuple.Create(background, (int)courseProgress.courseIndex));
|
||||
}
|
||||
|
||||
// Display minigames
|
||||
minigamesContainer.SetActive(user.minigames.Count > 0);
|
||||
emptyMinigames.SetActive(user.minigames.Count <= 0);
|
||||
foreach (Progress minigameProgress in user.minigames)
|
||||
var minigames = user.GetMinigames();
|
||||
minigamesContainer.SetActive(minigames.Count > 0);
|
||||
emptyMinigames.SetActive(minigames.Count <= 0);
|
||||
foreach (var minigameProgress in minigames)
|
||||
{
|
||||
// Create instance of prefab
|
||||
GameObject instance = GameObject.Instantiate(minigameCardPrefab, minigamesContainer.transform.Find("Viewport").Find("Content").transform);
|
||||
@@ -162,7 +159,7 @@ public class UserProgressScreen : MonoBehaviour
|
||||
// Store reference to background so we can apply fancy coloring
|
||||
Image background = instance.GetComponent<Image>();
|
||||
background.color = Color.gray;
|
||||
activities.Add(Tuple.Create(background, (int)minigameProgress.Get<MinigameIndex>("minigameIndex")));
|
||||
activities.Add(Tuple.Create(background, (int)minigameProgress.minigameIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +180,7 @@ public class UserProgressScreen : MonoBehaviour
|
||||
|
||||
selectedActivity = newActivity;
|
||||
activities[selectedActivity].Item1.color = Color.blue;
|
||||
if (selectedActivity < user.courses.Count)
|
||||
if (selectedActivity < user.GetCourses().Count)
|
||||
{
|
||||
// TODO: create a better graph
|
||||
//DisplayCourseGraph((CourseIndex)activities[selectedActivity].Item2);
|
||||
@@ -211,9 +208,9 @@ public class UserProgressScreen : MonoBehaviour
|
||||
/// <param name="minigameIndex">Index of the minigame</param>
|
||||
private void DisplayMinigameGraph(MinigameIndex minigameIndex)
|
||||
{
|
||||
Progress progress = user.GetMinigameProgress(minigameIndex);
|
||||
List<Score> latestScores = progress.Get<List<Score>>("latestScores");
|
||||
List<Score> highestScores = progress.Get<List<Score>>("highestScores");
|
||||
var progress = user.GetMinigameProgress(minigameIndex);
|
||||
List<Score> latestScores = progress.latestScores;
|
||||
List<Score> highestScores = progress.highestScores;
|
||||
if (0 < highestScores.Count)
|
||||
{
|
||||
PlotGraph(latestScores.ConvertAll<double>((s) => (double)s.scoreValue), highestScores[0].scoreValue);
|
||||
|
||||
Reference in New Issue
Block a user