game: fiddle around with execution order
generally found - Awake -> init - OnEnable -> init + register callbacks - Start -> do anything that might call a callback
This commit is contained in:
parent
e8091632c4
commit
872f3f263e
|
@ -78,22 +78,11 @@ public class AccountUI : MonoBehaviour
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Button _usernameUpdateButton;
|
private Button _usernameUpdateButton;
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
GameManager.Instance.Backend.RegisterOnSignInCallback(OnSignInCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
if (state == State.UnassociatedState) throw new Exception("unreachable state");
|
|
||||||
|
|
||||||
// GameManager.Instance.Backend.RegisterOnSignInCallback(OnSignInCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// function to subscribe button events to their respective functions
|
/// function called when the object is enabled,
|
||||||
|
/// subscribes button events to their respective functions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
var ui = GetComponent<UIDocument>().rootVisualElement;
|
var ui = GetComponent<UIDocument>().rootVisualElement;
|
||||||
|
|
||||||
|
@ -121,17 +110,18 @@ public void OnEnable()
|
||||||
_secondaryActionButton.clicked += OnSecondaryActionButtonClick;
|
_secondaryActionButton.clicked += OnSecondaryActionButtonClick;
|
||||||
|
|
||||||
TransitionStateTo(State.NotSignedIn);
|
TransitionStateTo(State.NotSignedIn);
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSignInCallback(FirebaseUser user)
|
if (state == State.UnassociatedState) throw new Exception("unreachable state");
|
||||||
{
|
GameManager.Instance.Backend.RegisterOnSignInCallback(_ =>
|
||||||
Debug.Log("sign in account ui callback");
|
{
|
||||||
|
Debug.Log("post-authentication callback, updating AccountView fields");
|
||||||
var username = GameManager.Instance.Backend.GetUsername();
|
var username = GameManager.Instance.Backend.GetUsername();
|
||||||
_usernameField.value = username;
|
_header.text = $"Signed in as {username}";
|
||||||
_emailField.value = GameManager.Instance.Backend.GetUser().Email;
|
_passwordField.value = "";
|
||||||
_passwordField.value = "";
|
_usernameField.value = username;
|
||||||
_header.text = $"Signed in as {username}";
|
_emailField.value = GameManager.Instance.Backend.GetUser().Email;
|
||||||
|
});
|
||||||
|
GameManager.Instance.RegisterOnLocalPlayerDataChangeCallback(PopulateFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TransitionStateTo(State newState, bool keepAccompanyingText = false)
|
private void TransitionStateTo(State newState, bool keepAccompanyingText = false)
|
||||||
|
@ -619,6 +609,18 @@ private void OnSecondaryActionButtonClick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// populate the fields with the given username and email,
|
||||||
|
/// used as a callback to when local player data is changed
|
||||||
|
/// </summary>
|
||||||
|
public void PopulateFields(LocalPlayerData data)
|
||||||
|
{
|
||||||
|
Debug.Log(
|
||||||
|
$"populating AccountView fields with lkUsername={data.LastKnownUsername} and lkEmail={data.LastKnownEmail}");
|
||||||
|
_usernameField.value = data.LastKnownUsername;
|
||||||
|
_emailField.value = data.LastKnownEmail;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// state of the account view
|
/// state of the account view
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -4,7 +4,7 @@ MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: -10
|
||||||
icon: {instanceID: 0}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
|
|
|
@ -60,12 +60,18 @@ public enum UserAccountDetailTargetEnum
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// callback functions to be invoked when the user signs in
|
/// callback functions to be invoked when the user signs in
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly List<Action<FirebaseUser>> _onSignInCallback = new();
|
private readonly List<Action<FirebaseUser>> _onSignInCallbacks = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// callback functions to be invoked when the user signs out
|
/// callback functions to be invoked when the user signs out
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly List<Action> _onSignOutCallback = new();
|
private readonly List<Action> _onSignOutCallbacks = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// callback functions to be invoked when the user signs in
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private readonly List<Action<FirebaseConnectionStatus>> _onConnectionStatusChangedCallbacks = new ();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// the firebase authentication object
|
/// the firebase authentication object
|
||||||
|
@ -100,9 +106,9 @@ public enum UserAccountDetailTargetEnum
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// variable initialisation function
|
/// variable initialisation function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Initialise()
|
public void Initialise(Action<FirebaseConnectionStatus> callback)
|
||||||
{
|
{
|
||||||
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
|
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
|
||||||
{
|
{
|
||||||
// cher is this robust enough
|
// cher is this robust enough
|
||||||
switch (task.Result)
|
switch (task.Result)
|
||||||
|
@ -112,6 +118,7 @@ public void Initialise()
|
||||||
_auth.StateChanged += AuthStateChanged;
|
_auth.StateChanged += AuthStateChanged;
|
||||||
_db = FirebaseDatabase.DefaultInstance.RootReference;
|
_db = FirebaseDatabase.DefaultInstance.RootReference;
|
||||||
Status = FirebaseConnectionStatus.Connected;
|
Status = FirebaseConnectionStatus.Connected;
|
||||||
|
callback(Status);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DependencyStatus.UnavailableDisabled:
|
case DependencyStatus.UnavailableDisabled:
|
||||||
|
@ -119,21 +126,25 @@ public void Initialise()
|
||||||
case DependencyStatus.UnavilableMissing:
|
case DependencyStatus.UnavilableMissing:
|
||||||
case DependencyStatus.UnavailablePermission:
|
case DependencyStatus.UnavailablePermission:
|
||||||
Status = FirebaseConnectionStatus.ExternalError;
|
Status = FirebaseConnectionStatus.ExternalError;
|
||||||
|
callback(Status);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DependencyStatus.UnavailableUpdating:
|
case DependencyStatus.UnavailableUpdating:
|
||||||
Status = FirebaseConnectionStatus.Updating;
|
Status = FirebaseConnectionStatus.Updating;
|
||||||
RetryInitialiseAfterDelay();
|
callback(Status);
|
||||||
|
RetryInitialiseAfterDelay(callback);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DependencyStatus.UnavailableUpdaterequired:
|
case DependencyStatus.UnavailableUpdaterequired:
|
||||||
Status = FirebaseConnectionStatus.UpdateRequired;
|
Status = FirebaseConnectionStatus.UpdateRequired;
|
||||||
|
callback(Status);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DependencyStatus.UnavailableOther:
|
case DependencyStatus.UnavailableOther:
|
||||||
default:
|
default:
|
||||||
Status = FirebaseConnectionStatus.InternalError;
|
Status = FirebaseConnectionStatus.InternalError;
|
||||||
Debug.LogError("firebase ??? blew up or something," + task.Result);
|
Debug.LogError("firebase ??? blew up or something," + task.Result);
|
||||||
|
callback(Status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,8 +157,8 @@ public void Initialise()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void FireOnSignInCallbacks()
|
private void FireOnSignInCallbacks()
|
||||||
{
|
{
|
||||||
Debug.Log($"firing on sign in callbacks ({_onSignInCallback.Count})");
|
Debug.Log($"firing OnSignInCallbacks ({_onSignInCallbacks.Count})");
|
||||||
foreach (var callback in _onSignInCallback)
|
foreach (var callback in _onSignInCallbacks)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -155,18 +166,18 @@ private void FireOnSignInCallbacks()
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogError(e);
|
Debug.LogError($"error invoking OnSignInCallback: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// function to fire all on sign out callbacks
|
/// function to fire all on sign-out callbacks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void FireOnSignOutCallbacks()
|
private void FireOnSignOutCallbacks()
|
||||||
{
|
{
|
||||||
Debug.Log($"firing on sign out callbacks ({_onSignOutCallback.Count})");
|
Debug.Log($"firing OnSignOutCallbacks ({_onSignOutCallbacks.Count})");
|
||||||
foreach (var callback in _onSignOutCallback)
|
foreach (var callback in _onSignOutCallbacks)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -174,7 +185,7 @@ private void FireOnSignOutCallbacks()
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogError(e);
|
Debug.LogError($"error invoking OnSignOutCallback: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,10 +193,10 @@ private void FireOnSignOutCallbacks()
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// async function to retry initialisation after a delay
|
/// async function to retry initialisation after a delay
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async void RetryInitialiseAfterDelay()
|
private async void RetryInitialiseAfterDelay(Action<FirebaseConnectionStatus> callback)
|
||||||
{
|
{
|
||||||
await Task.Delay(TimeSpan.FromSeconds(10));
|
await Task.Delay(TimeSpan.FromSeconds(10));
|
||||||
Initialise();
|
Initialise(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -235,25 +246,24 @@ private void AuthStateChanged(object sender, EventArgs eventArgs)
|
||||||
/// <param name="callback">callback function that takes in a <c>FirebaseUser</c> object</param>
|
/// <param name="callback">callback function that takes in a <c>FirebaseUser</c> object</param>
|
||||||
public void RegisterOnSignInCallback(Action<FirebaseUser> callback)
|
public void RegisterOnSignInCallback(Action<FirebaseUser> callback)
|
||||||
{
|
{
|
||||||
Debug.Log("registering on sign in callback");
|
_onSignInCallbacks.Add(callback);
|
||||||
_onSignInCallback.Add(callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// <summary>
|
/// <summary>
|
||||||
// /// function to register a callback for when the user signs out
|
/// function to register a callback for when the user signs out
|
||||||
// /// </summary>
|
/// </summary>
|
||||||
// /// <param name="callback">callback function</param>
|
/// <param name="callback">callback function</param>
|
||||||
// public void RegisterOnSignOutCallback(Action callback)
|
public void RegisterOnSignOutCallback(Action callback)
|
||||||
// {
|
{
|
||||||
// _onSignOutCallback.Add(callback);
|
_onSignOutCallbacks.Add(callback);
|
||||||
// }
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// abstraction function to authenticate the user
|
/// abstraction function to authenticate the user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="email">email string</param>
|
/// <param name="email">email string</param>
|
||||||
/// <param name="password">user raw password string</param>
|
/// <param name="password">user raw password string</param>
|
||||||
/// <param name="callback">callback function that takes in an AuthenticationResult argument</param>
|
/// <param name="callback">callback function that takes in an <c>AuthenticationResult</c> enum</param>
|
||||||
/// <param name="registerUser">whether to treat authentication as registration</param>
|
/// <param name="registerUser">whether to treat authentication as registration</param>
|
||||||
/// <param name="registeringUsername">username string if registering</param>
|
/// <param name="registeringUsername">username string if registering</param>
|
||||||
public void AuthenticateUser(
|
public void AuthenticateUser(
|
||||||
|
@ -472,8 +482,7 @@ public void ForgotPassword(string email, Action<bool> callback)
|
||||||
/// abstraction function to get the user's recent scores from the database
|
/// abstraction function to get the user's recent scores from the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callback">
|
/// <param name="callback">
|
||||||
/// callback function that takes in a DatabaseTransactionResult and List of LocalPlayerData.Score
|
/// callback function that takes in a <c>DatabaseTransactionResult</c> enum and a <c>List<LocalPlayerData.Score></c>
|
||||||
/// argument
|
|
||||||
/// </param>
|
/// </param>
|
||||||
public void GetRecentScores(Action<DatabaseTransactionResult, List<LocalPlayerData.Score>> callback)
|
public void GetRecentScores(Action<DatabaseTransactionResult, List<LocalPlayerData.Score>> callback)
|
||||||
{
|
{
|
||||||
|
@ -485,7 +494,7 @@ public void GetRecentScores(Action<DatabaseTransactionResult, List<LocalPlayerDa
|
||||||
/// abstraction function to submit a score to the database
|
/// abstraction function to submit a score to the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="score">score</param>
|
/// <param name="score">score</param>
|
||||||
/// <param name="callback">callback function that takes in one DatabaseTransactionResult argument</param>
|
/// <param name="callback">callback function that takes in a <c>DatabaseTransactionResult</c> enum </param>
|
||||||
public void SubmitScore(
|
public void SubmitScore(
|
||||||
LocalPlayerData.Score score,
|
LocalPlayerData.Score score,
|
||||||
Action<DatabaseTransactionResult> callback)
|
Action<DatabaseTransactionResult> callback)
|
||||||
|
@ -497,7 +506,7 @@ public void GetRecentScores(Action<DatabaseTransactionResult, List<LocalPlayerDa
|
||||||
/// abstraction function to get and calculate the user's rating from the database
|
/// abstraction function to get and calculate the user's rating from the database
|
||||||
/// calculation is done locally, call UpdateUserRating to update the user's rating in the database
|
/// calculation is done locally, call UpdateUserRating to update the user's rating in the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callback">callback function that takes in a DatabaseTransactionResult and float (user rating) argument</param>
|
/// <param name="callback">callback function that takes in a <c>DatabaseTransactionResult</c> enum and a user rating <c>float</c></param>
|
||||||
public void CalculateUserRating(
|
public void CalculateUserRating(
|
||||||
Action<DatabaseTransactionResult, float> callback)
|
Action<DatabaseTransactionResult, float> callback)
|
||||||
{
|
{
|
||||||
|
@ -508,7 +517,7 @@ public void GetRecentScores(Action<DatabaseTransactionResult, List<LocalPlayerDa
|
||||||
/// abstraction function to update the user's rating in the database
|
/// abstraction function to update the user's rating in the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newRating">new user rating value as a float</param>
|
/// <param name="newRating">new user rating value as a float</param>
|
||||||
/// <param name="callback">callback function that takes in one DatabaseTransactionResult argument</param>
|
/// <param name="callback">callback function that takes in a <c>DatabaseTransactionResult</c> enum </param>
|
||||||
public void UpdateUserRating(
|
public void UpdateUserRating(
|
||||||
float newRating,
|
float newRating,
|
||||||
Action<DatabaseTransactionResult> callback)
|
Action<DatabaseTransactionResult> callback)
|
||||||
|
@ -520,7 +529,7 @@ public void GetRecentScores(Action<DatabaseTransactionResult, List<LocalPlayerDa
|
||||||
/// abstraction function to get the leaderboard from the database
|
/// abstraction function to get the leaderboard from the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callback">
|
/// <param name="callback">
|
||||||
/// callback function that takes in a DatabaseTransactionResult and LeaderboardEntry[] argument
|
/// callback function that takes in a <c>DatabaseTransactionResult</c> enum and a <c>List<LeaderboardEntry></c>
|
||||||
/// </param>
|
/// </param>
|
||||||
public void GetLeaderboard(
|
public void GetLeaderboard(
|
||||||
Action<DatabaseTransactionResult, LeaderboardEntry[]> callback)
|
Action<DatabaseTransactionResult, LeaderboardEntry[]> callback)
|
||||||
|
@ -533,7 +542,7 @@ public void GetRecentScores(Action<DatabaseTransactionResult, List<LocalPlayerDa
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">the target account detail to update</param>
|
/// <param name="target">the target account detail to update</param>
|
||||||
/// <param name="newValue">the new value for the target account detail</param>
|
/// <param name="newValue">the new value for the target account detail</param>
|
||||||
/// <param name="callback">callback function that takes in one DatabaseTransactionResult argument</param>
|
/// <param name="callback">callback function that takes in a <c>DatabaseTransactionResult</c> enum</param>
|
||||||
/// <exception cref="ArgumentOutOfRangeException">thrown when the target is not a valid UserAccountDetailTargetEnum</exception>
|
/// <exception cref="ArgumentOutOfRangeException">thrown when the target is not a valid UserAccountDetailTargetEnum</exception>
|
||||||
public void UpdateUserAccountDetail(
|
public void UpdateUserAccountDetail(
|
||||||
UserAccountDetailTargetEnum target,
|
UserAccountDetailTargetEnum target,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
@ -20,7 +21,17 @@ public class GameManager : MonoBehaviour
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// the local player data object for storing player data
|
/// the local player data object for storing player data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private LocalPlayerData _localPlayerData;
|
private LocalPlayerData _data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// read-only property for accessing the local player data outside of this class
|
||||||
|
/// </summary>
|
||||||
|
public LocalPlayerData Data => _data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// list of callbacks to call when the local player data changes
|
||||||
|
/// </summary>
|
||||||
|
private readonly List<Action<LocalPlayerData>> _onLocalPlayerDataChangeCallbacks = new List<Action<LocalPlayerData>>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// backend object for handling communication with the firebase backend
|
/// backend object for handling communication with the firebase backend
|
||||||
|
@ -47,40 +58,55 @@ private void Awake()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
// load the local player data and refresh the ui
|
|
||||||
_localPlayerData = new LocalPlayerData();
|
|
||||||
_localPlayerData.LoadFromTheWorld();
|
|
||||||
PopulateFields();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RenderFromPlayerData();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// TODO: remove this once the bug is fixed
|
|
||||||
Debug.LogWarning("handling known exception, remove this once the bug is fixed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// register a callback to refresh the ui when the player signs in
|
|
||||||
Backend.RegisterOnSignInCallback(_ =>
|
|
||||||
{
|
|
||||||
Debug.Log("sign in callback, refreshing GameManager-controlled SideView UI");
|
|
||||||
_localPlayerData.LoadFromTheWorld();
|
|
||||||
PopulateFields();
|
|
||||||
RenderFromPlayerData();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// called when the game object is enabled, initialises variables
|
/// called when the game object is enabled, initialises variables
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
Backend = new Backend();
|
|
||||||
Backend.Initialise();
|
|
||||||
ui = UIManager.Instance;
|
ui = UIManager.Instance;
|
||||||
|
|
||||||
|
// load the local player data and refresh the ui
|
||||||
|
_data = new LocalPlayerData();
|
||||||
|
|
||||||
|
Backend = new Backend();
|
||||||
|
Backend.Initialise(status =>
|
||||||
|
{
|
||||||
|
Debug.Log("initialised backend, setting connection status text");
|
||||||
|
|
||||||
|
ui.UI.Q<Label>("ConnectionStatusText").text = status switch
|
||||||
|
{
|
||||||
|
Backend.FirebaseConnectionStatus.Connected => "Status: Connected",
|
||||||
|
Backend.FirebaseConnectionStatus.Updating => "Status: Updating... (Retrying in a bit!)",
|
||||||
|
Backend.FirebaseConnectionStatus.NotConnected => "Status: Disconnected",
|
||||||
|
Backend.FirebaseConnectionStatus.UpdateRequired =>
|
||||||
|
"Status: Disconnected (Device Component Update Required)",
|
||||||
|
Backend.FirebaseConnectionStatus.ExternalError => "Status: Disconnected (External/Device Error)",
|
||||||
|
Backend.FirebaseConnectionStatus.InternalError => "Status: Disconnected (Internal Error)",
|
||||||
|
_ => "Status: Disconnected (unknown fcs state, this is unreachable and a bug)"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (status == Backend.FirebaseConnectionStatus.Connected) return;
|
||||||
|
|
||||||
|
// if we're not connected, hide any online 'features'
|
||||||
|
ui.UI.Q<Button>("LeaderboardButton").style.display = DisplayStyle.None;
|
||||||
|
ui.UI.Q<Button>("AccountButton").style.display = DisplayStyle.None;
|
||||||
|
});
|
||||||
|
|
||||||
|
// register a callback to refresh the ui when the player signs in
|
||||||
|
Backend.RegisterOnSignInCallback(_ =>
|
||||||
|
{
|
||||||
|
Debug.Log("sign in callback, refreshing GameManager-controlled SideView UI");
|
||||||
|
_data.LoadFromTheWorld(FireLocalPlayerDataChangeCallbacks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// load in stuff
|
||||||
|
/// </summary>
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
Debug.Log("GameManager starts here");
|
||||||
|
_data.LoadFromTheWorld(FireLocalPlayerDataChangeCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -90,76 +116,35 @@ private void OnApplicationQuit()
|
||||||
{
|
{
|
||||||
Debug.Log("running deferred cleanup/save functions");
|
Debug.Log("running deferred cleanup/save functions");
|
||||||
Backend.Cleanup();
|
Backend.Cleanup();
|
||||||
_localPlayerData.SaveToTheWorld();
|
_data.SaveToTheWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// populate the fields with the given username and email, used by GameManager after local player data is loaded
|
/// function to register a callback to be called when the local player data changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void PopulateFields()
|
/// <param name="callback">callback function that takes a <c>LocalPlayerData</c> object</param>
|
||||||
|
public void RegisterOnLocalPlayerDataChangeCallback(Action<LocalPlayerData> callback)
|
||||||
{
|
{
|
||||||
Debug.Log(
|
_onLocalPlayerDataChangeCallbacks.Add(callback);
|
||||||
$"populating AccountView fields with lkUsername={_localPlayerData.LastKnownUsername} and lkEmail={_localPlayerData.LastKnownEmail}");
|
Debug.Log($"registering LocalPlayerDataChangeCallback ({_onLocalPlayerDataChangeCallbacks.Count})");
|
||||||
ui.UI.Q<TextField>("UsernameField").value = _localPlayerData.LastKnownUsername;
|
|
||||||
ui.UI.Q<TextField>("EmailField").value = _localPlayerData.LastKnownEmail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// function to update the ui with the latest data
|
/// function to fire all local player data change callbacks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void RenderFromPlayerData()
|
private void FireLocalPlayerDataChangeCallbacks(LocalPlayerData data)
|
||||||
{
|
{
|
||||||
// calculate averages from both recent local scores and online scores
|
Debug.Log($"firing LocalPlayerDataChangeCallbacks ({_onLocalPlayerDataChangeCallbacks.Count})");
|
||||||
var totalLightnessAcc = 0f;
|
foreach (var callback in _onLocalPlayerDataChangeCallbacks)
|
||||||
var totalChromaAcc = 0f;
|
|
||||||
var totalHueAcc = 0f;
|
|
||||||
var totalRounds = 0;
|
|
||||||
|
|
||||||
// average out all the scores we have to get a stable-ish average
|
|
||||||
|
|
||||||
foreach (var localScore in _localPlayerData.RecentLocalScores)
|
|
||||||
{
|
{
|
||||||
totalLightnessAcc += localScore.AvgLightnessAccuracy;
|
try
|
||||||
totalChromaAcc += localScore.AvgChromaAccuracy;
|
{
|
||||||
totalHueAcc += localScore.AvgHueAccuracy;
|
callback.Invoke(data);
|
||||||
totalRounds += localScore.NoOfRounds;
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogError($"error invoking LocalPlayerDataChangeCallback: {e.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var onlineScore in _localPlayerData.RecentOnlineScores)
|
|
||||||
{
|
|
||||||
totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
|
|
||||||
totalChromaAcc += onlineScore.AvgChromaAccuracy;
|
|
||||||
totalHueAcc += onlineScore.AvgHueAccuracy;
|
|
||||||
totalRounds += onlineScore.NoOfRounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var onlineScore in _localPlayerData.BestOnlineScores)
|
|
||||||
{
|
|
||||||
totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
|
|
||||||
totalChromaAcc += onlineScore.AvgChromaAccuracy;
|
|
||||||
totalHueAcc += onlineScore.AvgHueAccuracy;
|
|
||||||
totalRounds += onlineScore.NoOfRounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.Log($"tL={totalLightnessAcc} tC={totalChromaAcc} tH={totalHueAcc} tR={totalRounds}");
|
|
||||||
if (totalRounds == 0) totalRounds = 1;
|
|
||||||
var lightnessAcc = totalLightnessAcc / totalRounds;
|
|
||||||
var chromaAcc = totalChromaAcc / totalRounds;
|
|
||||||
var hueAcc = totalHueAcc / totalRounds;
|
|
||||||
var playerText = Backend.IsSignedIn ? _localPlayerData.LastKnownUsername : $"{_localPlayerData.LastKnownUsername} (Not Signed In)";
|
|
||||||
|
|
||||||
// finally, set the labels
|
|
||||||
ui.UI.Q<Label>("PlayerText").text = playerText;
|
|
||||||
ui.UI.Q<Label>("LightnessAccuracyText").text = $"{lightnessAcc:F}";
|
|
||||||
ui.UI.Q<Label>("ChromaAccuracyText").text = $"{chromaAcc:F}";
|
|
||||||
ui.UI.Q<Label>("HueAccuracyText").text = $"{hueAcc:F}";
|
|
||||||
|
|
||||||
// and set the player rating, but after we get it from the backend
|
|
||||||
// (god I LOVE async (I am LYING out of my teeth))
|
|
||||||
Backend.CalculateUserRating((dtr, rating) =>
|
|
||||||
{
|
|
||||||
if (dtr != Backend.DatabaseTransactionResult.Ok) return;
|
|
||||||
ui.UI.Q<Label>("RatingText").text = $"{rating:F}";
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: -10
|
executionOrder: -50
|
||||||
icon: {instanceID: 0}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class LocalPlayerData
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// loads player data from player prefs and database
|
/// loads player data from player prefs and database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void LoadFromTheWorld()
|
public void LoadFromTheWorld(Action<LocalPlayerData> callback)
|
||||||
{
|
{
|
||||||
// load user data, possibly from the backend
|
// load user data, possibly from the backend
|
||||||
var possibleUser = GameManager.Instance.Backend.GetUser();
|
var possibleUser = GameManager.Instance.Backend.GetUser();
|
||||||
|
@ -91,7 +91,8 @@ public void LoadFromTheWorld()
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Log(
|
Debug.Log(
|
||||||
$"loaded lpdata from the world ({LastKnownUsername} <{LastKnownEmail}> with RLS.Count={RecentLocalScores.Count}), ROS.Count={RecentOnlineScores.Count}");
|
$"loaded lpdata from the world ({LastKnownUsername} <{LastKnownEmail}> with RLS.Count={RecentLocalScores.Count}, ROS.Count={RecentOnlineScores.Count}");
|
||||||
|
callback(this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
@ -21,6 +22,36 @@ public class SideViewUI : MonoBehaviour
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Button _playButton;
|
private Button _playButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// connection status label for showing the connection status
|
||||||
|
/// </summary>
|
||||||
|
private Label _connectionStatusLabel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// text label for showing the player's known name
|
||||||
|
/// </summary>
|
||||||
|
private Label _playerText;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// text label for showing the player's rating
|
||||||
|
/// </summary>
|
||||||
|
private Label _ratingText;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// text label for showing the player's stable-ish lightness accuracy
|
||||||
|
/// </summary>
|
||||||
|
private Label _lightnessAccuracyText;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// text label for showing the player's stable-ish chroma accuracy
|
||||||
|
/// </summary>
|
||||||
|
private Label _chromaAccuracyText;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// text label for showing the player's stable-ish hue accuracy
|
||||||
|
/// </summary>
|
||||||
|
private Label _hueAccuracyText;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// function to subscribe button events to their respective functions
|
/// function to subscribe button events to their respective functions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -36,6 +67,21 @@ private void OnEnable()
|
||||||
|
|
||||||
_accountButton = ui.Q<Button>("AccountButton");
|
_accountButton = ui.Q<Button>("AccountButton");
|
||||||
_accountButton.clicked += OnAccountButtonClicked;
|
_accountButton.clicked += OnAccountButtonClicked;
|
||||||
|
|
||||||
|
_connectionStatusLabel = ui.Q<Label>("ConnectionStatusLabel");
|
||||||
|
|
||||||
|
_playerText = ui.Q<Label>("PlayerText");
|
||||||
|
_ratingText = ui.Q<Label>("RatingText");
|
||||||
|
|
||||||
|
_lightnessAccuracyText = ui.Q<Label>("LightnessAccuracyText");
|
||||||
|
_chromaAccuracyText = ui.Q<Label>("ChromaAccuracyText");
|
||||||
|
_hueAccuracyText = ui.Q<Label>("HueAccuracyText");
|
||||||
|
|
||||||
|
GameManager.Instance.Backend.RegisterOnSignOutCallback(() =>
|
||||||
|
{
|
||||||
|
RenderFromPlayerData(GameManager.Instance.Data);
|
||||||
|
});
|
||||||
|
GameManager.Instance.RegisterOnLocalPlayerDataChangeCallback(RenderFromPlayerData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -61,4 +107,65 @@ private static void OnAccountButtonClicked()
|
||||||
{
|
{
|
||||||
GameManager.Instance.ui.SetDisplayState(UIManager.DisplayState.AccountView);
|
GameManager.Instance.ui.SetDisplayState(UIManager.DisplayState.AccountView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// function to update the ui with the latest data
|
||||||
|
/// </summary>
|
||||||
|
private void RenderFromPlayerData(LocalPlayerData data)
|
||||||
|
{
|
||||||
|
// calculate averages from both recent local scores and online scores
|
||||||
|
var totalLightnessAcc = 0f;
|
||||||
|
var totalChromaAcc = 0f;
|
||||||
|
var totalHueAcc = 0f;
|
||||||
|
var totalRounds = 0;
|
||||||
|
|
||||||
|
// average out all the scores we have to get a stable-ish average
|
||||||
|
|
||||||
|
foreach (var localScore in data.RecentLocalScores)
|
||||||
|
{
|
||||||
|
totalLightnessAcc += localScore.AvgLightnessAccuracy;
|
||||||
|
totalChromaAcc += localScore.AvgChromaAccuracy;
|
||||||
|
totalHueAcc += localScore.AvgHueAccuracy;
|
||||||
|
totalRounds += localScore.NoOfRounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var onlineScore in data.RecentOnlineScores)
|
||||||
|
{
|
||||||
|
totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
|
||||||
|
totalChromaAcc += onlineScore.AvgChromaAccuracy;
|
||||||
|
totalHueAcc += onlineScore.AvgHueAccuracy;
|
||||||
|
totalRounds += onlineScore.NoOfRounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var onlineScore in data.BestOnlineScores)
|
||||||
|
{
|
||||||
|
totalLightnessAcc += onlineScore.AvgLightnessAccuracy;
|
||||||
|
totalChromaAcc += onlineScore.AvgChromaAccuracy;
|
||||||
|
totalHueAcc += onlineScore.AvgHueAccuracy;
|
||||||
|
totalRounds += onlineScore.NoOfRounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"tL={totalLightnessAcc} tC={totalChromaAcc} tH={totalHueAcc} tR={totalRounds}");
|
||||||
|
if (totalRounds == 0) totalRounds = 1;
|
||||||
|
var lightnessAcc = totalLightnessAcc / totalRounds;
|
||||||
|
var chromaAcc = totalChromaAcc / totalRounds;
|
||||||
|
var hueAcc = totalHueAcc / totalRounds;
|
||||||
|
var playerText = GameManager.Instance.Backend.IsSignedIn
|
||||||
|
? data.LastKnownUsername
|
||||||
|
: $"{data.LastKnownUsername} (Not Signed In)";
|
||||||
|
|
||||||
|
// finally, set the labels
|
||||||
|
_playerText.text = playerText;
|
||||||
|
_lightnessAccuracyText.text = $"{lightnessAcc:F}";
|
||||||
|
_chromaAccuracyText.text = $"{chromaAcc:F}";
|
||||||
|
_hueAccuracyText.text = $"{hueAcc:F}";
|
||||||
|
|
||||||
|
// and set the player rating, but after we get it from the backend
|
||||||
|
// (god I LOVE async (I am LYING out of my teeth))
|
||||||
|
GameManager.Instance.Backend.CalculateUserRating((dtr, rating) =>
|
||||||
|
{
|
||||||
|
if (dtr != Backend.DatabaseTransactionResult.Ok) return;
|
||||||
|
_ratingText.text = $"{rating:F}";
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: -20
|
||||||
icon: {instanceID: 0}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
|
|
|
@ -4,7 +4,7 @@ MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: -15
|
executionOrder: -60
|
||||||
icon: {instanceID: 0}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
|
|
Reference in a new issue