From 872f3f263e16c709c672fd64108e9d8ddf809c6e Mon Sep 17 00:00:00 2001 From: Mark Joshwel Date: Mon, 18 Nov 2024 00:16:53 +0800 Subject: [PATCH] game: fiddle around with execution order generally found - Awake -> init - OnEnable -> init + register callbacks - Start -> do anything that might call a callback --- ColourMeOKGame/Assets/Scripts/AccountUI.cs | 52 +++--- .../Assets/Scripts/AccountUI.cs.meta | 2 +- ColourMeOKGame/Assets/Scripts/Backend.cs | 73 ++++---- ColourMeOKGame/Assets/Scripts/GameManager.cs | 171 ++++++++---------- .../Assets/Scripts/GameManager.cs.meta | 2 +- .../Assets/Scripts/LocalPlayerData.cs | 5 +- ColourMeOKGame/Assets/Scripts/SideViewUI.cs | 107 +++++++++++ .../Assets/Scripts/SideViewUI.cs.meta | 2 +- .../Assets/Scripts/UIManager.cs.meta | 2 +- 9 files changed, 260 insertions(+), 156 deletions(-) diff --git a/ColourMeOKGame/Assets/Scripts/AccountUI.cs b/ColourMeOKGame/Assets/Scripts/AccountUI.cs index bf8cb65..6f7fac0 100644 --- a/ColourMeOKGame/Assets/Scripts/AccountUI.cs +++ b/ColourMeOKGame/Assets/Scripts/AccountUI.cs @@ -78,22 +78,11 @@ public class AccountUI : MonoBehaviour /// 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); - } - /// - /// function to subscribe button events to their respective functions + /// function called when the object is enabled, + /// subscribes button events to their respective functions /// - public void OnEnable() + private void OnEnable() { var ui = GetComponent().rootVisualElement; @@ -121,17 +110,18 @@ public void OnEnable() _secondaryActionButton.clicked += OnSecondaryActionButtonClick; TransitionStateTo(State.NotSignedIn); - } - - private void OnSignInCallback(FirebaseUser user) - { - Debug.Log("sign in account ui callback"); - - var username = GameManager.Instance.Backend.GetUsername(); - _usernameField.value = username; - _emailField.value = GameManager.Instance.Backend.GetUser().Email; - _passwordField.value = ""; - _header.text = $"Signed in as {username}"; + + if (state == State.UnassociatedState) throw new Exception("unreachable state"); + GameManager.Instance.Backend.RegisterOnSignInCallback(_ => + { + Debug.Log("post-authentication callback, updating AccountView fields"); + var username = GameManager.Instance.Backend.GetUsername(); + _header.text = $"Signed in as {username}"; + _passwordField.value = ""; + _usernameField.value = username; + _emailField.value = GameManager.Instance.Backend.GetUser().Email; + }); + GameManager.Instance.RegisterOnLocalPlayerDataChangeCallback(PopulateFields); } private void TransitionStateTo(State newState, bool keepAccompanyingText = false) @@ -618,6 +608,18 @@ private void OnSecondaryActionButtonClick() throw new ArgumentOutOfRangeException(); } } + + /// + /// populate the fields with the given username and email, + /// used as a callback to when local player data is changed + /// + 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; + } /// /// state of the account view diff --git a/ColourMeOKGame/Assets/Scripts/AccountUI.cs.meta b/ColourMeOKGame/Assets/Scripts/AccountUI.cs.meta index ac9fded..db998f3 100644 --- a/ColourMeOKGame/Assets/Scripts/AccountUI.cs.meta +++ b/ColourMeOKGame/Assets/Scripts/AccountUI.cs.meta @@ -4,7 +4,7 @@ MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] - executionOrder: 0 + executionOrder: -10 icon: {instanceID: 0} userData: assetBundleName: diff --git a/ColourMeOKGame/Assets/Scripts/Backend.cs b/ColourMeOKGame/Assets/Scripts/Backend.cs index da7166e..12fc26c 100644 --- a/ColourMeOKGame/Assets/Scripts/Backend.cs +++ b/ColourMeOKGame/Assets/Scripts/Backend.cs @@ -60,12 +60,18 @@ public enum UserAccountDetailTargetEnum /// /// callback functions to be invoked when the user signs in /// - private readonly List> _onSignInCallback = new(); + private readonly List> _onSignInCallbacks = new(); /// /// callback functions to be invoked when the user signs out /// - private readonly List _onSignOutCallback = new(); + private readonly List _onSignOutCallbacks = new(); + + /// + /// callback functions to be invoked when the user signs in + /// + /// + private readonly List> _onConnectionStatusChangedCallbacks = new (); /// /// the firebase authentication object @@ -100,9 +106,9 @@ public enum UserAccountDetailTargetEnum /// /// variable initialisation function /// - public void Initialise() + public void Initialise(Action callback) { - FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => + FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => { // cher is this robust enough switch (task.Result) @@ -112,6 +118,7 @@ public void Initialise() _auth.StateChanged += AuthStateChanged; _db = FirebaseDatabase.DefaultInstance.RootReference; Status = FirebaseConnectionStatus.Connected; + callback(Status); break; case DependencyStatus.UnavailableDisabled: @@ -119,21 +126,25 @@ public void Initialise() case DependencyStatus.UnavilableMissing: case DependencyStatus.UnavailablePermission: Status = FirebaseConnectionStatus.ExternalError; + callback(Status); break; case DependencyStatus.UnavailableUpdating: Status = FirebaseConnectionStatus.Updating; - RetryInitialiseAfterDelay(); + callback(Status); + RetryInitialiseAfterDelay(callback); break; case DependencyStatus.UnavailableUpdaterequired: Status = FirebaseConnectionStatus.UpdateRequired; + callback(Status); break; case DependencyStatus.UnavailableOther: default: Status = FirebaseConnectionStatus.InternalError; Debug.LogError("firebase ??? blew up or something," + task.Result); + callback(Status); break; } @@ -146,8 +157,8 @@ public void Initialise() /// private void FireOnSignInCallbacks() { - Debug.Log($"firing on sign in callbacks ({_onSignInCallback.Count})"); - foreach (var callback in _onSignInCallback) + Debug.Log($"firing OnSignInCallbacks ({_onSignInCallbacks.Count})"); + foreach (var callback in _onSignInCallbacks) { try { @@ -155,18 +166,18 @@ private void FireOnSignInCallbacks() } catch (Exception e) { - Debug.LogError(e); + Debug.LogError($"error invoking OnSignInCallback: {e.Message}"); } } } /// - /// function to fire all on sign out callbacks + /// function to fire all on sign-out callbacks /// private void FireOnSignOutCallbacks() { - Debug.Log($"firing on sign out callbacks ({_onSignOutCallback.Count})"); - foreach (var callback in _onSignOutCallback) + Debug.Log($"firing OnSignOutCallbacks ({_onSignOutCallbacks.Count})"); + foreach (var callback in _onSignOutCallbacks) { try { @@ -174,7 +185,7 @@ private void FireOnSignOutCallbacks() } catch (Exception e) { - Debug.LogError(e); + Debug.LogError($"error invoking OnSignOutCallback: {e.Message}"); } } } @@ -182,10 +193,10 @@ private void FireOnSignOutCallbacks() /// /// async function to retry initialisation after a delay /// - private async void RetryInitialiseAfterDelay() + private async void RetryInitialiseAfterDelay(Action callback) { await Task.Delay(TimeSpan.FromSeconds(10)); - Initialise(); + Initialise(callback); } /// @@ -235,25 +246,24 @@ private void AuthStateChanged(object sender, EventArgs eventArgs) /// callback function that takes in a FirebaseUser object public void RegisterOnSignInCallback(Action callback) { - Debug.Log("registering on sign in callback"); - _onSignInCallback.Add(callback); + _onSignInCallbacks.Add(callback); } - // /// - // /// function to register a callback for when the user signs out - // /// - // /// callback function - // public void RegisterOnSignOutCallback(Action callback) - // { - // _onSignOutCallback.Add(callback); - // } + /// + /// function to register a callback for when the user signs out + /// + /// callback function + public void RegisterOnSignOutCallback(Action callback) + { + _onSignOutCallbacks.Add(callback); + } /// /// abstraction function to authenticate the user /// /// email string /// user raw password string - /// callback function that takes in an AuthenticationResult argument + /// callback function that takes in an AuthenticationResult enum /// whether to treat authentication as registration /// username string if registering public void AuthenticateUser( @@ -472,8 +482,7 @@ public void ForgotPassword(string email, Action callback) /// abstraction function to get the user's recent scores from the database /// /// - /// callback function that takes in a DatabaseTransactionResult and List of LocalPlayerData.Score - /// argument + /// callback function that takes in a DatabaseTransactionResult enum and a List<LocalPlayerData.Score> /// public void GetRecentScores(Action> callback) { @@ -485,7 +494,7 @@ public void GetRecentScores(Action /// score - /// callback function that takes in one DatabaseTransactionResult argument + /// callback function that takes in a DatabaseTransactionResult enum public void SubmitScore( LocalPlayerData.Score score, Action callback) @@ -497,7 +506,7 @@ public void GetRecentScores(Action - /// callback function that takes in a DatabaseTransactionResult and float (user rating) argument + /// callback function that takes in a DatabaseTransactionResult enum and a user rating float public void CalculateUserRating( Action callback) { @@ -508,7 +517,7 @@ public void GetRecentScores(Action /// new user rating value as a float - /// callback function that takes in one DatabaseTransactionResult argument + /// callback function that takes in a DatabaseTransactionResult enum public void UpdateUserRating( float newRating, Action callback) @@ -520,7 +529,7 @@ public void GetRecentScores(Action /// - /// callback function that takes in a DatabaseTransactionResult and LeaderboardEntry[] argument + /// callback function that takes in a DatabaseTransactionResult enum and a List<LeaderboardEntry> /// public void GetLeaderboard( Action callback) @@ -533,7 +542,7 @@ public void GetRecentScores(Action /// the target account detail to update /// the new value for the target account detail - /// callback function that takes in one DatabaseTransactionResult argument + /// callback function that takes in a DatabaseTransactionResult enum /// thrown when the target is not a valid UserAccountDetailTargetEnum public void UpdateUserAccountDetail( UserAccountDetailTargetEnum target, diff --git a/ColourMeOKGame/Assets/Scripts/GameManager.cs b/ColourMeOKGame/Assets/Scripts/GameManager.cs index ec2b3a3..44e2a6a 100644 --- a/ColourMeOKGame/Assets/Scripts/GameManager.cs +++ b/ColourMeOKGame/Assets/Scripts/GameManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; @@ -20,7 +21,17 @@ public class GameManager : MonoBehaviour /// /// the local player data object for storing player data /// - private LocalPlayerData _localPlayerData; + private LocalPlayerData _data; + + /// + /// read-only property for accessing the local player data outside of this class + /// + public LocalPlayerData Data => _data; + + /// + /// list of callbacks to call when the local player data changes + /// + private readonly List> _onLocalPlayerDataChangeCallbacks = new List>(); /// /// 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(); - }); - } - /// /// called when the game object is enabled, initialises variables /// private void OnEnable() { - Backend = new Backend(); - Backend.Initialise(); 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