-
Notifications
You must be signed in to change notification settings - Fork 35
Syncing
Delta will support syncing data between all your devices, so you will be able to resume any progress made on another device completely seamlessly.
This page is divided into two main sections, user-facing features and the actual implementation, read whichever parts you are most interested in.
Whenever you save your game or add/delete save states or cheats, the data will by synced to your other devices in the background. The goal is for this process to be fully automatic, but allow for some control when necessary.
GBA4iOS used Dropbox for all of its syncing functionality. While this made sense at the time, Dropbox has become increasingly less popular, and on the other hand, almost everyone has a Google account. As a result, Delta will fully support both Dropbox and Google Drive. This allows users to choose the option that makes the most sense for them.
Why, however, is the most obvious syncing back-end used by practically every other iOS app excluded: iCloud? Unfortunately, it’s because Delta is not just a normal app. iCloud is officially only supported for apps that are distributed through the App Store, and while there are ways around this, ultimately Apple has the power to disable iCloud support for any app they want very easily.
Maybe Apple will relax their policies on iCloud usage in the future, but for now this cloud service is far too risky, especially since we’re dealing with game data that would be disastrous to lose.
In GBA4iOS, it would sync all game data except the ROMs themselves. This was because Dropbox’s free tier was rather small at 2GB, and it couldn't risk filling up users’ storage quota with ROMs that could just be downloaded individually onto each device.
Unfortunately, in practice this was rather confusing. People wondered why after enabling syncing on one device their games didn’t sync to their other devices, and no matter how many times the question was answered, it was clear it just wasn’t intuitive why this was the case. Additionally, Google Drive comes with 15GB for the free tier, which is far more than enough for the added storage taken up by ROMs.
Delta we will be syncing the ROMs themselves as a default, there will likely be no way to turn off the ROM syncing in v1.0 but may be added in a later date.
A feature that was cut from GBA4iOS was the ability to view versions of synced data (such as game saves), since it was possible to access this information from the Dropbox website directly if people wanted to.
However, as people used Dropbox Sync, it was used more and more as a backup system for their data rather than just for syncing, which is great! But, any backup system should be able to show users past versions of their files, especially if they resolved a conflict by accidentally selecting the wrong version of the file.
Since this functionality is already built into Dropbox and Google Drive, Delta will hook into their implementations directly from the app. Most importantly, this should bring more users peace about their save data, since they know they can always restore a previous save file if they mess something up themselves.
Just like with GBA4iOS, data integrity is the #1 priority for syncing. As a result, Delta will defer as much as possible to the user for decisions when it is not 100% sure what the right answer is. While this means there may be more “Resolve Conflict” screens than similar syncing approaches, this is essential to ensure no data is lost.
The syncing functionality of GBA4iOS was always tied directly to Dropbox, and as a result the syncing code itself is tightly coupled with the Dropbox SDK. This made sense due to the time constraints and limited expertise of syncing logic in general, but it now means that practically none of the same code can be reused to build the syncing functionality for Delta.
Rather than follow the same approach and closely tying the logic with Dropbox and Google Drive directly, Delta will instead separate the logic into it’s own framework named Harmony, with support for arbitrary back-ends. This results in much more modular (and testable!) code, which can be used in any future projects without having to rework any of the syncing logic again.
Delta uses Core Data to store its information locally, and it has been incredible; it cannot be expressed how wonderful and powerful Core Data is. So, when designing Harmony, it made sense to make sure it integrated well with Core Data, so Delta and any other Core Data-based apps could easily adopt it.
Additionally, Core Data provides practically everything necessary for a syncing framework. It’s easy to know when anything is added/deleted/modified, and since apps using Core Data typically react to these updates automatically (using NSFetchedResultsController, for example), there really is almost no additional work for a Core Data app to support syncing via Harmony.
Harmony itself will have it’s own Core Data stack that will keep track of the status of both local and remote data. Additionally, it will have access to the app’s own Core Data stack, will is used to retrieve and update local data. This is important, because this means the app can be blissfully unaware of Harmony, and continue to work as if it wasn’t there.
While most apps that use Core Data typically store all information in the local database file itself, Delta is slightly different. Almost everything synced between devices is actually one (or more) files on disk, and Core Data is used to store metadata about that file. For example, when you create a save state, Delta saves a thumbnail and a save state generated by the emulation core to disk, and then creates a SaveState (custom NSManagedObject subclass) with relevant metadata such as the name, creation date, and whether the save state is “locked” or not.
Most syncing solutions based on database persistence treat the database entries as the only data necessary to sync, but since for Delta the entries are only the metadata of the files, Harmony allows you to associate a Record with any number of File objects, and will ensure they are synced together as one “unit” to ensure data integrity.
As mentioned before, Core Data apps typically use a reactive approach to display data; that is, rather than manually updating the UI, they instead listen for notifications sent out by the Core Data framework, and update the UI whenever they receive these notifications.
As it turns out, Harmony is able to use these very same notifications to determine when local data has been changed. Whenever an NSManagedObject is inserted, updated, or deleted, Harmony will receive a notification and update it’s private database with this information. When Harmony performs its next sync, it can easily query the state of all local objects and compare them with the state of remote objects to determine what operations are necessary to get everything in sync.
Additionally, when Harmony updates the app’s own database, it makes sure that the appropriate notifications are sent out. This way, when data is downloaded from the server, the app will react the same way as if it had saved the data itself, with 0 additional code changes. Magic!
Harmony was designed to be flexible and support any potential backend. To accomplish this, as much syncing logic as possible is kept separate from the notion of backends; Harmony knows how to serialize Core Data entities to and from syncable representations, determine exactly what operations are necessary to keep datasets in sync, and handle any conflicts as they arise.
Ultimately, it does need to connect to specific backends, so there is a very simple Service protocol that backend-implementations can conform to. This protocol is limited to very primitive functionality, such as authentication, uploading/download files, and fetching all changed remote files. For now, there are two concrete implementations of this Service protocol, DropboxService and DriveService, which handle the backend-specific logic for Dropbox and Google Drive, respectively.
This format for syncing will allow future cloud services to be implemented and makes it even easier for Harmony to be used in any other projects!