Front-End Web & Mobile

Using Amazon Cognito to sync data in Unity games

With the release of the Developer Preview for the AWS SDK for Unity you can now start using Amazon Cognito in your Unity games to synchronize player profiles and game state with the cloud. To demonstrate how to use this new SDK, we have created a simple Unity Scene that uses the Cognito Sync Service to save data, such as character experience and level, and access it from other devices. It also demonstrates how Cognito can be used for both guest users as well as authenticated users via Facebook. This post guides you through setting up Amazon Cognito for use by your app and using the AWS SDK for Unity. Finally, it also shows you how to build the sample project for Android.

Sample screenshot

 

Prerequisites

Follow these steps to run this sample with your own Cognito account:

1. Create an Identity Pool within Cognito

  1. Access the AWS Cognito console using your AWS account.
  2. Select New Identity Pool.
  3. Set up the identity pool:
    • Specify a name for your identity pool.
    • If you already have a Facebook App to log in your users, specify the app id in this page. If you don’t, you will be able to add this later.
    • Check the “Enable Access to Unauthenticated Identities” check box to allow users to play without logging-in.
    • Click Create Pool, and then Update Roles on the next screen.
  4. Copy or download the “Starter Code” from the last step, you will need it to set up the Unity Scene.

2. Download the AWS Unity SDK Samples and open the Cognito Sync Demo Project in Unity. This sample project is compatible with Unity 4.x, and does not require Unity Pro.

3. Download the AWS Unity SDK, uncompress it and import the Cognito Sync Unity Package into the sample project.

4. Set up your own Cognito credentials:

  1. In the editor, open the scene DemoScene/SyncCharactersSelection/CharactersSelection.unity.
  2. Open the source file DemoScene/SyncCharactersSelection/SaveManager.cs
  3. Copy the Identity Pool ID and Region from the starter code into the two public variables for them.
  4. You can now run the scene in the editor.

5. Integrate Facebook login in the demo scene –By offering login, your users are able to access their game data, saved with Cognito Sync, from all of the devices they log in to with the same credentials. Cognito supports multiple different authentication providers, such as Login with Amazon, Facebook, Google, any OIDC compliant provider, and also your own custom implemented provider. For the sake of the sample, follow these steps to implement authentication with Facebook:

  1. Navigate to https://developers.facebook.com/.
  2. Select Apps -> Add a New App. Select a platform to start with. For the purpose of this demo, we’ll use Android.
  3. For Package Name introduce “com.amazonaws.cognito.sync.demo” and for Default Activity Class Name use “com.facebook.unity.FBUnityDeepLinkingActivity“. This last one is common for every Unity project.
  4. Follow the Facebook instructions to add the keys you sign your apps with. Facebook only allows applications signed with the keys you add here to authenticate against your Facebook app.
  5. Once your Facebook app is configured, you can paste the App Id into the edit identity pool page in the Cognito console.
  6. Now you have to configure the Facebook SDK in Unity to use your Facebook app. Because the Facebook SDK is bundled in this sample app you should see a Facebook menu in the Unity editor.
  7. From the Facebook menu, select Edit Settings and paste the App Id you created on Facebook.
  8. When you run the demo app, you now see a Facebook login button. The button opens your browser and asks you to manually copy your “User token” back into Unity. This is only for in-editor testing, and in a build for Android or iOS, it will trigger the regular login procedure.

6. You are now ready to build the game for Android.

Note: The Facebook SDK only supports iOS and Android, so you won’t be able to use the Facebook login if you compile for other platforms. If you run the app inside the Unity Editor instead, the Facebook SDK provides a way to authenticate for debugging purposes.

  1. The Android SDK has to be installed in your system and your Android phone needs to be in developer mode.
  2. Unity needs to know the SDK path. You can set it from Preferences -> External Tools -> Android SDK Location.
  3. Now you can go to File -> Build Settings, select Android and click on Switch platform.
  4. Press Build to generate an APK that you can install in an Android phone.

7. You can now run the sample on your phone. When you start the sample you are asked to log in. Then, you can use the New Character button to add characters to the scene. Clicking on a character will increase its experience. The characters and their experience are saved to the cloud, and can be loaded later from another device using the same Facebook login.

Authentication screen

 

How it works

Now that you have the project up and running, we can take a closer look at the source code.

We focus primarily on the AWSPrefab and the SceneController. The first GameObject defines the connection parameters and needs to be available to use any AWS service from a Unity scene. The second is specific to this sample, and has three components:

CharacterList: Keeps track of the characters in the scene and allows you to serialize/deserialize them to be saved/restored by the SaveManager.

LoginController: Handles the login of Facebook users or unauthenticated identities, and then activates and initializes the SaveManager component. This is the only class that interacts with the Facebook SDK.

SaveManager: Contains all the code that communicates with AWS and Cognito. Some functions are accessible by the user through the interface and others are callbacks from the SDK. Here’s a list of the user-facing functions to help understand this class:

  • InitWithFacebook/InitWithoutFacebook: These are the entry points called from LoginController. When the SaveManager is initialized it makes the first call to LoadFromDataset() using the Cognito sync SDK. To call InitWithFacebook you need to provide an access token. In our case, we get this from the LoginController.
  • LoadFromDataset: Restores the saved state of the scene and sends it to the CharacterList. The load takes place in two steps: First RefreshDatasetMetadataAsync and then the Synchronize function in the Cognito Dataset, which will trigger the HandleSyncSuccess callback (see the list of callbacks below).
  • SaveToDataset: This method gets the scene state from CharacterList into a Cognito Dataset and synchronizes it to the cloud.

Most of the interaction with the SDK is done through callbacks. Some of them are passed directly to the function that will invoke them, but others are set at initialization time. The most important are:

  • HandleSyncSuccess: This callback indicates that the sync operation of a Dataset is completed. A sync operation then reads the latest updates from the cloud and pushes the local changes to the sync store. In our example, we synchronize the dataset that contains the user data. Once the sync operation is completed, the data is ready for us to read. This callback is executed on a separate thread and therefore cannot access Unity Components. In this example, instead of that, we copy the data to the variable characterStrings, which will be read by the main thread in the Update function.
  • HandleSyncConflict: This function is called when a conflict occurs during a sync operation. This can happen when a second device changes the data in the cloud before the first device had a chance to synchronize its changes. The SDK’s default behavior for conflict resolution is last writer wins. In in our demo scene we have an implementation that simply overrides our local data with the remote data:
    bool HandleSyncConflict(Dataset dataset, List<SyncConflict> conflicts)
    {
        List<Record> resolvedRecords = new List<Record>();
        foreach (SyncConflict conflictRecord in conflicts)
        {
            resolvedRecords.Add(conflictRecord.ResolveWithRemoteRecord());
        }
        // resolves the conflicts in local storage
        dataset.Resolve(resolvedRecords);
        // returning true allows the synchronize operation to continue
        // returning false cancels the synchronize operation
        return true;
    }
  • HandleSyncFailure: When something goes wrong during a sync operation, this callback is fired to notify the application.
  • HandleDatasetMerged: This callback is fired when a user already has data stored on Cognito, for example with an authenticated identity, and the user then logs in with a Facebook account that already had data associated to it. This callback gives you a chance to merge the data of the two profiles and decide which version to keep, for example the latest one, or the one with the highest score or latest level in your game. After you have merged the data, you have to delete the merged datasets. If we fail to do so, this function will keep being called until we resolve the merge.
  • HandleDatasetDeleted: This callback is called when a dataset we have in the local storage has been deleted remotely, so we can delete our copy in the local storage.

 

Summary

Amazon Cognito helps you synchronize data, such as game state and user profiles, with the cloud and other devices without writing any backend code. Amazon Cognito also simplifies the job of managing end users’ identities, including unauthenticated guests and their transition to logged-in users, without losing the data in their user profiles. We will follow up on this blog post with a detailed explanation of these features.

Further reading: