Social Infrastructure At Scale

Build scalable game backends with Nakama

Sean

Sean Packham

01 Nov 2021

Background

In this tutorial I am going to show you the Nakama specific parts to build some social and competitive features for a fictional Unity game inspired by the hit mobile game, Crossy Road. Nakama is a customizable and scalable open source game server with all the social, competitive, and economy features you need to build and scale online games.

Croaky Road gameplay mockup
A gameplay mockup for the Croaky Road game

Install Nakama server and game engine SDK

First thing, head over to the Nakama docs and follow our Docker or binary installation guide.

Next install the Nakama Unity SDK, and in your main scene connect your game to your Nakama server by creating a Nakama Client.

1
var client = new Nakama.Client("http", "127.0.0.1", 7350, "defaultKey");

Authentication, Sessions and Users

Now that your game is connected to the server, it’s time to authenticate players with Facebook, import their Facebook friends, create game sessions and manage user accounts.

Facebook authentication

Authenticating with Facebook is simple with Nakama:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void AuthenticateWithFacebook()
{
    FB.LogInWithReadPermissions(new[] { "public_profile", "email" }, async result =>
    {
        if (FB.IsLoggedIn)
        {
            try
            {
                var importFriends = true;
                Session = await client.AuthenticateFacebookAsync(AccessToken.CurrentAccessToken.TokenString, importFriends);
                Debug.Log("Authenticated with Facebook");
            }
            catch(ApiResponseException ex)
            {
                Debug.LogFormat("Error authenticating with Facebook: {0}", ex.Message);
            }
        }
    });
}

Your friends can easily be imported by passing a True value for importFriends. Nakama will then add them to your in-game friends list if they are also playing.

Sessions

Once authenticated, sessions can be restored or refreshed so that players don’t have to re-authenticate. The session auth and refresh tokens can be stored in Unity’s PlayerPrefs:

1
2
PlayerPrefs.SetString("nakama.authToken", Session.AuthToken);
PlayerPrefs.SetString("nakama.refreshToken", Session.RefreshToken);

Then accessed to restore sessions:

1
2
3
var authToken = PlayerPrefs.GetString("nakama.authToken", null);
var refreshToken = PlayerPrefs.GetString("nakama.refreshToken", null);
session = Nakama.Session.Restore(authToken, refreshToken);

Or refresh sessions before they expire:

1
2
3
4
5
6
7
8
9
10
11
12
if (session.IsExpired || session.HasExpired(DateTime.UtcNow.AddDays(1))) {
    try {
        // Attempt to refresh the existing session.
        session = await client.SessionRefreshAsync(session);
    } catch (ApiResponseException) {
        // Couldn't refresh the session so reauthenticate.
        session = await client.AuthenticateDeviceAsync(deviceId);
        PlayerPrefs.SetString("nakama.refreshToken", session.RefreshToken);
    }

    PlayerPrefs.SetString("nakama.authToken", session.AuthToken);
}

User accounts

Using the session we can get the current player’s user account, and access and update properties, visualized in your game’s profile screen:

Croaky Road player profile and friends list
Croaky Road player profile and friends list

Get the player’s account

1
2
3
var account = await client.GetAccountAsync(session);
var username = account.User.Username;
var avatarUrl = account.User.AvatarUrl;

Update the player’s account

1
2
3
4
5
6
7
var newUsername = "NotTheImp0ster";
var newDisplayName = "Innocent Dave";
var newAvatarUrl = "https://example.com/imposter.png";
var newLangTag = "en";
var newLocation = "Edinburgh";
var newTimezone = "BST";
await client.UpdateAccountAsync(session, newUsername, newDisplayName, newAvatarUrl, newLangTag, newLocation, newTimezone);

Get the player’s friends

1
2
3
4
5
var result = await client.ListFriendsAsync(session);
foreach (var f in result.Friends)
{
    Debug.LogFormat("Friend '{0}' state '{1}'", f.User.Username, f.State);
}

Nakama has many more easy-to-use APIs for working with friends, groups (clans), real-time parties, matches, leaderboards, chat and more.

Competing with your friends

Nakama makes it easy to add social and competitive features to singleplayer games or build complete real-time multiplayer experiences. Like Crossy Road, the core gameplay of Croaky Road happens on the client and players compete against each other on global or friend leaderboards.

Once players complete a round and receive a score we’ll show them where they ranked versus their friends.

Croaky Road game over screen and new score
Croaky Road game over screen and new score

Create a leaderboard

We first need to create a Leaderboard on the game server in one of Nakama’s supported server runtimes: Go, TypeScript/JavaScript or Lua. Here’s the Go server code to create a leaderboard:

1
2
3
4
5
6
7
8
id := "weekly_leaderboard"
authoritative := false
sort := "desc"
operator := "incr"
reset := "0 0 * * 1"
metadata := map[string]interface{}{}

nk.LeaderboardCreate(ctx, id, authoritative, sort, operator, reset, metadata)

Submit a score

Player scores can be submitted to the leaderboard and Nakama will take care of ranking and ordering players.

1
2
3
4
var score = 1;
var subscore = 0;
var metadata = new Dictionary<string, string> {{ "map", "jungle" }};
await client.WriteLeaderboardRecordAsync(session, "weekly_leaderboard", score, subscore, JsonWriter.ToJson(metadata));

Display a friends leaderboard

Nakama has powerful leaderboard listing functionality. We could display the top records on the leaderboard, records around the player, the player’s group (clan) and for this example just the player’s friends:

1
2
3
4
5
6
7
var friendsList = await client.ListFriendsAsync(session, 0, 100, cursor: null);
var userIds = friendsList.Friends.Select(f => f.User.Id);
var recordList = await client.ListLeaderboardRecordsAsync(session, "weekly_leaderboard", userIds, expiry: null, 100, cursor: null);
foreach (var record in recordList.Records)
{
    Debug.LogFormat("{0} scored {1}", record.Username, record.Score);
}
Croaky Road friend leaderboard
Croaky Road friend leaderboard

Monitoring your game’s success

Nakama comes with a developer console for monitoring your game server config, users, storage, matches, leaderboards and performance.

Nakama Developer Console
Nakama Developer Console

This is just a taste of how easy it is to add social and competitive features to your game. Nakama also has a wealth of realtime multiplayer features for matchmaking, networking game state and so much more.

Next steps

  1. Read our comprehensive Unity Client Guide.
  2. Run one of our open source sample games.
  3. Contact us to discuss effortlessly scaling your game on Heroic Cloud.