/nakama-unreal

Unreal client for Nakama server.

Primary LanguageC++Apache License 2.0Apache-2.0

Nakama Unreal

Nakama is an open-source server designed to power modern games and apps. Features include user accounts, chat, social, matchmaker, realtime multiplayer, and much more.

This client implements the full API and socket options with the server. It's written in C++ with minimal dependencies to support Unreal, unreal and other custom engines and frameworks.

If you experience any issues with the client, it can be useful to enable debug logs and open an issue.

Full documentation is online - https://heroiclabs.com/docs

General Information

This plugin can also be used for programmers who like C++ or Blueprints. All variables and functions are exposed to types used by Unreal Engine (UPROPERTIES, USTRUCT, UFUNCTIONS etc.)

The plugin is divided into three modules which can be pulled in depending on your needs.

  • NakamaUnreal The recommended C++ based module for using Nakama in UnrealEngine. This integrates with Unreal's native types and UObjects.
  • NakamaBlueprints For users who would prefer to use Blueprints in their project.
  • NakamaCore For users who are migrating from our old Unreal client and want to make minimal changes, or use our lower-level C++ API without Unreal types: (https://github.com/heroiclabs/nakama-cpp)

Clients are referred in this documentation as Realtime Client and Default Client in which the realtime client is the socket and the default client is using REST API to communicate with Nakama.

Getting Started

You'll need to setup the server and database before you can connect with the client. The simplest way is to use Docker but have a look at the server documentation for other options.

To get started using Nakama in Unreal you will need the following:

  1. Install and run the servers. Follow these instructions.
  2. A copy of the core Nakama Unreal plugin
  3. Unreal Engine 4.25 or greater (Unreal Engine 5 support is tentative).
  4. A compiler for the platform you are developing on, such as Visual Studio on Windows or XCode on OSX.

Also, please ensure your Unreal project is a C++ project. If it is Blueprint only, you can add a new C++ file to your project in Unreal Editor via "File -> New C++ Class". Set it private and name it whatever you like. Having this file in your project lets Unreal compile the plugin.

Installing the Plugin

To use Nakama in your Unreal project, you'll need to download our plugin from the Unreal Marketplace or copy the nakama-unreal files you downloaded into the appropriate place. To do the latter:

  1. Open your Unreal project folder (for example, C:\\MyUnrealProject\\) in Explorer or Finder.
  2. If one does not already exist, create a Plugins folder here.
  3. Copy the Nakama folder from nakama-unreal and put it in the Plugins folder

Optionally: you can put the plugins inside your Unreal Engine plugin folder (for example, C:\Program Files\Epic Games\UE_4.26\Engine\Plugins\Marketplace) to use the plugin on multiple projects.

At this point, you are done. Restart Unreal. After it compiles things, open Edit->Plugins and scroll to the bottom. If all went well, you should see HeroicLabs.Nakama listed as a plugin.

Clients

You have to decide where you want to create and keep record of these clients.

Sessions

Sessions are portable UObjects that contain a session pointer and a struct with the actual data in the session, like the tokens, user data, expiry information an so on. There are also some utility functions provided with the Session objects, like getting a specific variable or restoring the session.

Tick System

Normally you would have to handle ticking on a C++ basis, luckily this is done automatically under the hood in this plugin after you have created the client. When you create the Client you can define a Tick Interval, by default this is set to 0, which means it will tick every frame, if you want it to tick every 50ms you have to set it as 0.05, to make it tick every second this number would be 1.

Getting Started with NakamaUnreal (C++ with Unreal Types)

Below is a simple example of setting up a default client, authenticating, setting up a realtime client and joining a chat room. In the example we will put everything in a empty AActor class that is placed in the level.

Remember to add NakamaUnreal and NakamaCore to your Private Dependencies under your project Build.cs file. For example:

PrivateDependencyModuleNames.AddRange(new string[] { "NakamaUnreal", "NakamaCore" });

Starting with the headers public variables, we are using a blank actor that will be placed in the scene in this example.

UPROPERTY()
UNakamaClient* NakamaClient;

UPROPERTY()
UNakamaRealtimeClient* NakamaRealtimeClient;

UPROPERTY()
UNakamaSession* UserSession;

UFUNCTION()
void OnAuthenticationSuccess(UNakamaSession* LoginData);

UFUNCTION()
void OnAuthenticationError(const FNakamaError& Error);

UFUNCTION()
void OnRealtimeClientConnectSuccess();

UFUNCTION()
void OnRealtimeClientConnectError();

// Initialize client and authenticate here
virtual void BeginPlay() override;

Then inside the Begin Play we setup default client, authenticate and bind delegates.

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
	Super::BeginPlay();

	// Default Client Parameters
	FString ServerKey = FString(TEXT("defaultkey"));
	FString Host = FString(TEXT("localhost"));
	FString ClientName = FString(TEXT("Main"));

	// Setup Default Client
	NakamaClient = UNakamaClient::CreateDefaultClient(ServerKey, Host, 7350, false, true, ENakamaClientType::DEFAULT, 0.05f, ClientName);

	// Authentication Parameters
	FString Email = FString(TEXT("debug@mail.com"));
	FString Password = FString(TEXT("verysecretpassword"));
	FString Username = FString(TEXT("debug-user"));
	TMap<FString, FString> Variables;

	// Setup Delegates of same type and bind them to local functions
	FOnAuthUpdate AuthenticationSuccessDelegate;
	AuthenticationSuccessDelegate.AddDynamic(this, &AMyActor::OnAuthenticationSuccess);

	FOnError AuthenticationErrorDelegate;
	AuthenticationErrorDelegate.AddDynamic(this, &AMyActor::OnAuthenticationError);

	NakamaClient->AuthenticateEmail(Email, Password, Username, true, Variables, AuthenticationSuccessDelegate, AuthenticationErrorDelegate);
}

Then the response of the authentication callbacks

void AMyActor::OnAuthenticationSuccess(UNakamaSession* LoginData)
{
	if(GEngine) GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, FString::Printf(TEXT("Authenticated As %s"), *LoginData->SessionData.Username));

	UserSession = LoginData;

	// Setup Delegates of same type and bind them to local functions
	FOnRealtimeClientConnected ConnectionSuccessDelegate;
	ConnectionSuccessDelegate.AddDyanmic(this, &AMyActor::OnRealtimeClientConnectSuccess);

	FOnRealtimeClientError ConnectionErrorDelegate;
	ConnectionErrorDelegate.AddDyanmic(this, &AMyActor::OnRealtimeClientConnectError);

	// This is our realtime client (socket) ready to use
	NakamaRealtimeClient = NakamaClient->SetupRealtimeClient(UserSession, true, 7350, ENakamaRealtimeClientProtocol::Protobuf, 0.05f, "");

	// Remember to Connect
	NakamaRealtimeClient->Connect(ConnectionSuccessDelegate, ConnectionErrorDelegate);

}

void AMyActor::OnAuthenticationError(const FNakamaError& Error)
{
	if(GEngine) GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, FString::Printf(TEXT("Failed to Authenticate: %s"), *Error.Message));
}

And finally the overridden realtime client setup callback, you can now use the realtime client.

void AMyActor::OnRealtimeClientConnectSuccess()
{
	if(GEngine) GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, FString(TEXT("Socket Setup Success!")));

	// Example of Joining Chat without callbacks
	NakamaRealtimeClient->JoinChat("Heroes", ENakamaChannelType::ROOM, true, false, {}, {});

}

void AMyActor::OnRealtimeClientConnectError()
{
	if(GEngine) GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, FString(TEXT("Socket Setup Failed!")));
}

If you setup everything correctly, create a blueprint version of this actor and place it in the level you will see on-screen messages saying you authenticated, your username and then socket connected message.

Getting Started with NakamaBlueprints

In this section you will learn how to manually create and manage Nakama clients that are provided by this plugin, entirely in blueprints.

It is up to the you where to create and store references to the clients, this could be done in any actor, component, character, gamemode etc. A good place to put the clients is in the Player Controller or the Game Instance.

Start by adding the Create Default Client node which is a part fo the Nakama Library.

image createclient-1

It is good practice to promote the clients to variables so you can access them other places in your blueprint graphs.

image createclient-2

You are now ready to authenticate, using one of the many provided Nakama authentication types, in this example we will be authenticating with email and password, normally you would setup a Widget Blueprint and pass the input from the UI into the authentication node, and authenticate by pressing a login button.

image createclient-3

As you can see, this returns a session object that will be passed into other functions, make sure to promote the session object for later use. With this plugin you may have multiple sessions per unreal instance, it is up to you to keep record and decide how you want to use the sessions. The variables pin also needs to be connected, but you can leave the string map empty if you don't want to use custom variables.

image createclient-4

After you have created a default client you'll be able to setup one or more realtime clients (sockets) that interact with the server.

Drag out from the NakamaClient that you created earlier, and call the Setup Realtime Client function.

image createclient-4

Remember to provide the user session from the successful authentication earlier, then bind custom events to the success and error callbacks. The Realtime Client will be returned from this node, and is ready to be used to communicate with the Nakama server. You can now use features such as Chat and Matchmaker.

image createclient-5

Setting up Listeners and Binding to Events

Before you bind to event callbacks you need to setup the listener first, drag out from the realtime client and type Listener, you will be provided a list over different events you can listen to, there is also a Listen to All Callbacks which will open up all listeners.

image binding-1

After setting up your specific listeners you are ready to bind to the callbacks.

image binding-2

Create a custom event and give it a meaningful name.

image binding-3

In the example below, we setup a listener for notifications, then we bind to the event, loop over notifications and print them as debug strings on the screen.

image binding-4

In the next example we listen to matchmaker matched event then bind to it and handle the response by joining a match with the returned token which then returns a Match including the match id, presences, label and so on.

image binding-5

Session Management

As described earlier, when you authenticate with Nakama you'll receive a Session Object which you should store somewhere easily accessible in your Blueprints, since many of the nodes in this plugin require a session object as input to function.

The session object contains the actual session reference and also a structure with the data readable in blueprints. Drag out from the session and get the session data.

image sessions-1

Right click the structure to split or break the struct to see the values

image sessions-2

Here are all the values contained within the session

image sessions-3

There are also some additional session management methods like restoring the session and checking if the session has expired

image sessions-4

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.

Requests

The clients include lots of builtin APIs for various features of the game server. These can be accessed with the async methods, which returns Success and Error callbacks. They can also call custom logic as RPC functions on the server. All requests are sent with a session object which authorizes the clients.

image requests

The RPC node can be used to run specific functionality on the server, the payload should be in JSON format.

image rpc

Moving forward, you should be ready to use all functionality of Nakama to power your awesome Unreal Engine built game or app, done entirely in Blueprints. Please refer to the official documentation at https://heroiclabs.com/docs even though some of the documentation is described in C++ the same core functionality applies to the Blueprint implementation.

Cursors

Cursors are used to add paging functionality to certain nodes, like friends list and leaderboard records. When there is more data to be retrieved, a cursor string will be returned in the Success callback. You can store this cursor as a string and use it later, like when a person clicks a "more" button or use it immediately to fetch more data. Look at the example below.

image cursors

Additional Information

Some of the features of this plugin depend on JSON, such as sending chat messages and storing data using storage objects. It is therefore recommended that if you use purely blueprints that you find a plugin that can construct and parse Json strings such as VaRest.

When you are developing within the editor, you can run multiple unreal instances using PIE (Play In Editor) and are able to authenticate using separate accounts, which is very useful when testing functionalities that require multiple players, such as chat, realtime multiplayer, matchmaking and so on.

In the installation part of this documentation we add C++ to our project, this is only to be able to compile the plugin, you can still use only Blueprints.

Example Project

Provided with this plugin is an example project which is developed in pure Blueprints that showcases almost all of the Nakama core features.

image example-1

image example-2

image example-3

Contribute

The development roadmap is managed as GitHub issues and pull requests are welcome. If you're interested to enhance the code please open an issue to discuss the changes or drop in and discuss it in the community forum.

Source Builds

The Unreal module is based on General C++ SDK

Nakama Unreal Client guide

You can find Nakama Unreal Client guide here.

License

This project is licensed under the Apache-2 License.