using System; using System.Threading.Tasks; using Firebase; using Firebase.Auth; using Firebase.Database; using UnityEngine; /// /// the general managing class for handling communication with the firebase backend /// (to be initialised by GameManager) /// public class Backend : MonoBehaviour { /// /// whether the backend is connected to the firebase backend /// public bool connected; /// /// the firebase authentication object /// private FirebaseAuth _auth; /// /// the firebase database reference /// private DatabaseReference _db; /// /// callback function to be invoked when the user signs in /// private Action _onSignInCallback = user => { Debug.Log("signed in as" + user.UserId); }; /// /// callback function to be invoked when the user signs out /// private Action _onSignOutCallback = user => { Debug.Log("signed out" + user.UserId); }; /// /// the current user object, if authenticated /// private FirebaseUser _user; /// /// script load function /// private void Awake() { Debug.Log("firing firebase Initialise() invocation"); Initialise(); } /// /// deferred cleanup function /// private void OnDestroy() { SignOutUser(); } /// /// variable initialisation function /// private void Initialise() { FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => { switch (task.Result) { case DependencyStatus.Available: var app = FirebaseApp.DefaultInstance; _auth = FirebaseAuth.GetAuth(app); _auth.StateChanged += AuthStateChanged; _db = FirebaseDatabase.DefaultInstance.RootReference; connected = true; Debug.Log("firebase initialised"); break; case DependencyStatus.UnavailableDisabled: case DependencyStatus.UnavailableInvalid: case DependencyStatus.UnavilableMissing: case DependencyStatus.UnavailablePermission: Debug.LogError("firebase error outside of our control"); break; case DependencyStatus.UnavailableUpdaterequired: case DependencyStatus.UnavailableUpdating: Debug.LogError("firebase is updating"); RetryInitialiseAfterDelay(); break; case DependencyStatus.UnavailableOther: default: Debug.LogError("firebase ??? blew up or something," + task.Result); break; } }); } /// /// function to handle the authentication state change event /// /// the object that triggered the event /// the event arguments private void AuthStateChanged(object sender, EventArgs eventArgs) { if (_auth.CurrentUser == _user) return; var signedIn = _user != _auth.CurrentUser && _auth.CurrentUser != null; switch (signedIn) { case false when _user != null: _onSignOutCallback(_user); break; case true: _onSignInCallback(_auth.CurrentUser); break; } } /// /// function to register a callback for when the user signs in /// /// callback function that takes in a FirebaseUser argument private void RegisterOnSignInCallback(Action callback) { _onSignInCallback = callback; } /// /// function to register a callback for when the user signs out /// /// callback function that takes in a FirebaseUser argument private void RegisterOnSignOutCallback(Action callback) { _onSignOutCallback = callback; } /// /// async function to retry initialisation after a delay /// private async void RetryInitialiseAfterDelay() { await Task.Delay(TimeSpan.FromSeconds(10)); Initialise(); } /// /// abstraction function to authenticate the user /// /// user name string /// user raw password string /// callback function that takes in an AuthenticationResult argument /// whether to treat authentication as registration private void AuthenticateUser( string username, string password, Action callback, bool registerUser = false) { throw new NotImplementedException(); } /// /// abstraction function to retrieve the user /// /// the firebase user object private FirebaseUser GetUser() { return _user; } /// /// abstraction function to sign out the user /// private void SignOutUser() { _auth.SignOut(); } /// /// abstraction function to submit a play to the database /// /// the float percentage (0-100) of how accurate the user was when colour matching /// callback function that takes in one DatabaseTransactionResult argument private void SubmitPlay( float averageMatchAccuracy, Action callback) { throw new NotImplementedException(); } /// /// 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 /// /// callback function that takes in a DatabaseTransactionResult and float (user rating) argument private void CalculateUserRating( Action callback) { throw new NotImplementedException(); } /// /// abstraction function to update the user's rating in the database /// /// new user rating value as a float /// callback function that takes in one DatabaseTransactionResult argument private void UpdateUserRating( float newRating, Action callback) { throw new NotImplementedException(); } /// /// abstraction function to get the leaderboard from the database /// /// /// private void GetLeaderboard( Action callback) { throw new NotImplementedException(); } /// /// struct for a leaderboard entry /// // ReSharper disable once MemberCanBePrivate.Global public struct LeaderboardEntry { public string Username; public float Rating; public int PlayCount; } /// /// enum for the result of the authentication process /// // ReSharper disable once MemberCanBePrivate.Global public enum AuthenticationResult { Ok, AlreadyAuthenticated, NonExistentUser, AlreadyExistingUser, InvalidCredentials, GenericError } /// /// generic enum for the result of a database transaction /// // ReSharper disable once MemberCanBePrivate.Global public enum DatabaseTransactionResult { Ok, Unauthenticated, Error } }