Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Storage API + Metrics API #113

Merged

Conversation

sp4ce-cowboy
Copy link
Contributor

@sp4ce-cowboy sp4ce-cowboy commented Apr 13, 2024

Summary

This PR adds the entire Metrics API + Storage API. Added both together given the close link between them (i.e. Storage is needed to see if the Metrics work properly).

MetricsAPI

  • Statistics sub-API: Gathers information using an event-driven architecture, and liaises with Storage.
  • Inference sub-API: Custom contexts to make sense of statistics gathered above.
    • Achievements: Permanent achievements completed throughout the lifetime of the app
    • Missions: Objectives completed within a given game sequence only
    • Ranking: Experience points and rank can be determined from Statistics (architecturally scalable to be used for level-based player matching or level-based perks)

StorageAPI

  • Local & Remote: All storage is stored both locally and remotely in firebase, regardless of whether user is logged in by using one-time instantiated UUID that is stored separately and used to distinguish between different devices that ping firebase.
  • Metadata: The above mentioned one-time instantiation is stored within a Metadata file identifies the user and simultaneously keeps track of latest update date signature. Metadata is also stored locally and remotely.
  • Data collision resolution: 2 types of data collision resolution implemented (Merge both or keep latest only) using the above metadata and some manual merging.
  • Data synchronization: Above-mentioned collision also takes into account cases where a user is playing locally, and then decides to log in. All progress can be merged, and kept in sync.

Pending & Concerns

  • Singleton pattern eliminated, but given the nature of Firebase/local storage, only utility classes with static methods are used. This prevents data from existing in two places at once (i.e. inside game memory and local storage) but it's a bit too close to singleton pattern, might need to double confirm.
  • Achievements, Missions need a UI so that the user can view them. (Ideally can move to a new PR)
  • Data sync and remote storage could use some more testing to make sure they work with user login.

PR Status

Ready for review. UIView for Achievements and missions to be move to another PR. Some commented code is retained just in case the newer StatisticsUpdateActors fail and we need to revert back (which we can only tell after some more testing)

Closes #52

@sp4ce-cowboy sp4ce-cowboy added the feature list Adding features label Apr 13, 2024
@sp4ce-cowboy sp4ce-cowboy self-assigned this Apr 13, 2024
zheng-ze
zheng-ze previously approved these changes Apr 14, 2024
Copy link
Contributor

@zheng-ze zheng-ze left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think generally this looks ok.


import Foundation

extension Double {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file should be in the extensions folder

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locally, it is in the Extensions folder. I think this is a glitch with GitHub.
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it like that in the Finder aka local machine not in xcode as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nice thanks for letting me know, that seems to be the issue. It's fixed now.

TowerForge/TowerForge/Metrics/Statistics/Statistic.swift Outdated Show resolved Hide resolved
@sp4ce-cowboy sp4ce-cowboy changed the title [Feature] Remote-Local Storage Sync + Achievements Engine [Feature] Storage API + Metrics API Apr 15, 2024
@sp4ce-cowboy sp4ce-cowboy marked this pull request as ready for review April 15, 2024 22:03
zheng-ze
zheng-ze previously approved these changes Apr 16, 2024
Copy link
Contributor

@zheng-ze zheng-ze left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine but I feel that the retrieval of stats from events is a bit hardcoded and there is some commented code that needs to be cleaned up.

Comment on lines 28 to 34

if let statsSystem = target.system(ofType: StatisticSystem.self) {
if player != .ownPlayer {
statsSystem.notify(for: self)
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to somehow register the stats system notifier as a handler in the EventManager? So that we select which stats we want to get notified for via the StatsEngine rather than being controlled via the event? I believe this Prof will feel that this current method is kind of hard coding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for noticing this, I forgot to remove the player check here. I've implemented something similar which removes the hard coding:

        let eventUpdateClosure: (Statistic, DamageEvent?) -> Void = { statistic, event in
            guard let event = event, event.player != .ownPlayer else {
                return
            }
            statistic.updateCurrentValue(by: Double(event.damage))
            Logger.log("Updating statistic with event detail: \(String(describing: event))", self)
        }

This code snippet is from the TotalDamageDealtStatistic, the StatisticUpdateActor (i.e. eventUpdateClosure) related to this Statistic now takes in an Event as opposed to just EventType from the prior implementation (which had the check inside the event itself) and the parsing is done by the StatsEngine when it calls to execute the above closure.

Comment on lines 29 to 36
/*func getStatisticUpdateLinks() -> StatisticUpdateLinkDatabase {
let eventType = TFEventTypeWrapper(type: DamageEvent.self)
let updateActor: StatisticUpdateActor = { statistic in statistic.updateCurrentValue(by: ) }
let eventUpdateDictionary = [eventType: updateActor]
let statsLink = StatisticUpdateLinkDatabase(statisticUpdateLinks: eventUpdateDictionary)

return statsLink
}*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidental commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks.

@sp4ce-cowboy sp4ce-cowboy requested a review from zheng-ze April 16, 2024 14:09
@sp4ce-cowboy sp4ce-cowboy merged commit 602f44f into cs3217-2324:main Apr 16, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature list Adding features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missions and Achievements
3 participants