Unity client guide

This client is built on the .NET client with extensions for Unity Engine. To work with our Unity client you'll need to install and setup Unity engine.

The client is available on the Unity Asset Store and also on GitHub releases. You can download "Nakama.unitypackage" which contains all source code and DLL dependencies required in the client code.

It requires the .NET4.6 scripting runtime version to be set in the editor. Navigate to Edit -> Project Settings -> Player -> Configuration (subheading) to apply it.

For upgrades you can see changes and enhancements in the CHANGELOG before you update to newer versions.

Contribute

The Unity client is open source on GitHub. Report issues and contribute code to help us improve it.

Setup

When you've downloaded the "Nakama.unitypackage" file you should drag or import it into your Unity editor project to install it. In the editor create a new C# script via the Assets menu with "Assets > Create > C# Script" and create a client object.

The client object is used to interact with the server.

using System.Collections;
using Nakama;
using UnityEngine;

public class YourGameObject : MonoBehaviour
{
  void Start()
  {
    var client = new Client("defaultkey", "127.0.0.1", 7350, false);
  }
}

Unity uses an entity component system (ECS) which makes it possible to share the client across game objects. Have a read of Controlling GameObjects Using Components for examples on how to share a C# object across your game objects.

Authenticate

With a client object you can authenticate against the server. You can register or login a user with one of the authenticate options.

To authenticate you should follow our recommended pattern in your client code:

   1. Build an instance of the client.

var client = new Client("defaultkey", "127.0.0.1", 7350, false);

   2. Authenticate a user. By default the server will create a user if it doesn't exist.

const string email = "hello@example.com";
const string password = "somesupersecretpassword";
var session = await client.AuthenticateEmailAsync(email, password);
Debug.LogFormat("Authenticated session: {0}", session);

In the code above we use AuthenticateEmailAsync but for other authentication options have a look at the code examples. This full example covers all our recommended steps.

Sessions

When authenticated the server responds with an auth token (JWT) which contains useful properties and gets deserialized into a Session object.

Debug.Log(session.AuthToken); // raw JWT token
Debug.LogFormat("User id '{0}'", session.UserId);
Debug.LogFormat("User username '{0}'", session.Username);
Debug.LogFormat("Session has expired: {0}", session.IsExpired);
Debug.LogFormat("Session expires at: {0}", session.ExpireTime); // in seconds.

It is recommended to store the auth token from the session and check at startup if it has expired. If the token has expired you must reauthenticate. The expiry time of the token can be changed as a setting in the server.

var prefKeyName = "nakama.session";
var authtoken = PlayerPrefs.GetString(prefKeyName);
if (string.IsNullOrEmpty(authtoken) || Session.Restore(authtoken).IsExpired)
{
  Debug.Log("Session has expired. Must reauthenticate!");
}
else
{
  var session = Session.Restore(authtoken);
  Debug.Log(session);
}

Send requests

The client includes lots of builtin APIs for various features of the game server. These are accessed with async methods. It can also call custom logic through RPC functions on the server.

All requests are sent with a session object which authorizes the client.

var account = await client.GetAccountAsync(session);
Debug.LogFormat("User id '{0}'", account.User.Id);
Debug.LogFormat("User username '{0}'", account.User.Username);
Debug.LogFormat("Account virtual wallet '{0}'", account.Wallet);

Methods which end with "Async" can use C# Tasks to asynchronously wait for the response. This can be done with the await keyword. For more advice on async/await features in C# have look at the official documentation.

The other sections of the documentation include more code examples on the client.

Socket messages

The client can create one or more sockets with the server. Each socket can have it's own event listeners registered for responses received from the server.

var socket = client.CreateWebSocket();
socket.OnConnect += (sender, args) =>
{
  Debug.Log("Socket connected.");
};
socket.OnDisconnect += (sender, args) =>
{
  Debug.Log("Socket disconnected.");
};
await socket.ConnectAsync(session);

You can connect to the server over a realtime socket connection to send and receive chat messages, get notifications, and matchmake into a multiplayer match. You can also execute remote code on the server via RPC.

To join a chat channel and receive messages:

const string RoomName = "Heroes";
socket.OnChannelMessage += (sender, message) =>
{
  Debug.LogFormat("Received a message on channel '{0}'", message.channelId);
  Debug.LogFormat("Message content: '{0}'", message.content);
};
var channel = await socket.JoinChatAsync(RoomName, ChannelType.Room);
// using Nakama.TinyJson;
var content = new Dictionary<string, string> {{"hello", "world"}}.ToJson();
var sendAck = await socket.WriteChatMessageAsync(channel, content);

There are more examples for chat channels here.

Handle events

A socket object has event handlers which are called on various messages received from the server.

socket.OnStatusPresence += (_, presence) =>
{
  foreach (var join in presence.Joins)
  {
    Debug.LogFormat("User '{0}' joined.", join.Username);
  }
  foreach (var leave in presence.Leaves)
  {
    Debug.LogFormat("User '{0}' left.", leave.Username);
  }
};

Event handlers only need to be implemented for the features you want to use.

Callbacks Description
OnConnect Receive an event when the socket connects.
OnDisconnect Handles an event for when the client is disconnected from the server.
OnError Receives events about server errors.
OnNotification Receives live in-app notifications sent from the server.
OnChannelMessage Receives realtime chat messages sent by other users.
OnChannelPresence It handles join and leave events within chat.
OnMatchState Receives realtime multiplayer match data.
OnMatchPresence It handles join and leave events within realtime multiplayer.
OnMatchmakerMatched Received when the matchmaker has found a suitable match.
OnStatusPresence It handles status updates when subscribed to a user status feed.
OnStreamPresence Receives stream join and leave event.
OnStreamState Receives stream data sent by the server.

Logs and errors

The server and the client can generate logs which are helpful to debug code. To log all messages sent by the client you can enable "Trace" when you build a client and attach a logger.

var client = new Client("defaultkey", "127.0.0.1", 7350, false)
{
#if UNITY_EDITOR
  Logger = new UnityLogger(),
  Trace = true
#endif
};

The #if preprocessor directives is used so trace is only enabled in Unity editor builds. For more complex directives with debug vs release builds have a look at Platform dependent compilation.

Full example

A small example on how to manage a session object with Unity engine and the client.

using System.Collections;
using System.Collections.Generic;
using Nakama;
using UnityEngine;

public class SessionWithPlayerPrefs : MonoBehaviour
{
    private const string PrefKeyName = "nakama.session";

    private IClient _client = new Client("defaultkey", "127.0.0.1", 7350, false);
    private ISession _session;

    private async void Awake()
    {
        var authtoken = PlayerPrefs.GetString(PrefKeyName);
        if (!string.IsNullOrEmpty(authtoken))
        {
            var session = Session.Restore(authtoken);
            if (!session.IsExpired)
            {
                _session = session;
                Debug.Log(_session);
                return;
            }
        }
        var deviceid = SystemInfo.deviceUniqueIdentifier;
        _session = await _client.AuthenticateDeviceAsync(deviceid);
        PlayerPrefs.SetString(PrefKeyName, _session.AuthToken);
        Debug.Log(_session);
    }
}

A collection of other code examples is available here.