Unreal Engine 5 dedicated server development with Amazon GameLift Anywhere

Building dedicated servers is challenging, and developers need the ability to quickly test and iterate on their games. The recently updated Amazon GameLift Server SDK from Amazon Web Services (AWS) provides an Unreal Engine plugin that is compatible with both Unreal Engine 4 and Unreal Engine 5.

The plugin makes it easy for Unreal Engine developers to use an Amazon GameLift Anywhere fleet to test their game server on a local workstation without the need to upload a build to Amazon GameLift. Amazon GameLift Anywhere fleets also integrate with Amazon GameLift FlexMatch and Queues, allowing end-to-end testing.

This post describes how to integrate the Amazon GameLift Server SDK 5.0 plugin into Unreal Engine 5, create an Anywhere fleet, and register your local workstation as a compute resource. You will then create a game session running on your local workstation, saving time and shortening the game development feedback loop.

Solution overview

Unreal Engine 5 offers a free sample game project called Lyra that provides online multiplayer support. This project is a great starting point for building a dedicated server, and in this walkthrough, we integrate the Amazon GameLift plugin into Lyra and describe how to use Amazon GameLift Anywhere to test and iterate on your game server.

Unreal Engine 5 Lyra Starter Game

Walkthrough

This walkthrough takes you through the following steps:

  • Build Unreal Engine from source
  • Build the Lyra Starter Game
  • Set up the Amazon GameLift plugin
  • Configure the Lyra Starter Game to use the plugin
  • Set up an Amazon GameLift Anywhere fleet
  • Create a game session

Prerequisites

For this walkthrough, you should have the following:

  •  An AWS account
  • A GitHub account
  • An Epic Games account
  • Visual Studio 2022
  • OpenSSL and cmake installed
  • Prior experience with Unreal Engine and C++

Build Unreal Engine from source

In order to build a dedicated server, you need to compile Unreal Engine from source. This is required so that you can specify a Server Target for the build. Unreal Engine 5.1.0 is used throughout this blog post.

To build your desired version of Unreal Engine

  1. Follow these steps to link your GitHub account to your Epic Games account.
  2. Clone your desired version of the Unreal GitHub repo by running:

git clone -b 5.1.0-release --single-branch https://github.com/EpicGames/UnrealEngine.git

  1. If you plan to cross-compile for Linux, you will need to install the cross-compile toolchain.
  2. Follow the Unreal Engine documentation to build the engine from source.

Build the Lyra Starter Game

To download Lyra

  1. Open the Epic Games Launcher
  2. Click on the Marketplace tab and search for “Lyra”
  3. Click “Create Project”
  4. Select your Unreal Engine version and click “Create”

To build Lyra

  1. Right-click on the LyraStarterGame project file and select “Switch Unreal Engine version…”. Select your Unreal source build.

Image showing right-click menu and “Generate Visual Studio project files” highlighted

  1. Right-click on the LyraStarterGame project file and select “Generate Visual Studio project files”.
  2. Open Lyra project in the Unreal Editor.
  3. Follow the dedicated server tutorial in the Unreal documentation to configure Lyra and build, package, and test both a server and a client.

Set up the Amazon GameLift plugin

The Amazon GameLift plugin supports building both Windows and Linux servers. In both cases, the Managed Servers C++ SDK must be compiled, and the library files copied into the plugin folder.

Download the Amazon Gamelift plugin

  1. Download the latest version of the Amazon GameLift Managed Servers C++ SDK.
  2. Unzip the archive.

To prepare the plugin for Windows servers

  1. Open the Visual Studio 2022 Developer Command Prompt.
  2. Change directory to the C++ SDK folder.
  3. Build the Windows library by running:
mkdir out
cd out 
cmake -G "Visual Studio 17 2022" -DBUILD_FOR_UNREAL=1 .. 
msbuild ALL_BUILD.vcxproj /p:Configuration=Release

  1. This creates 2 library files in the outgamelift-server-sdkRelease folder:

aws-cpp-sdk-gamelift-server.lib

aws-cpp-sdk-gamelift-server.dll

  1. Copy these files into the Amazon GameLift Unreal plugin package in ThirdPartyGameLiftServerSDKWin64

Prepare the plugin for Linux servers

Optionally, you can build and integrate the Linux version of the library, so that the plugin also supports Linux servers.

  1. Change directory to the C++ SDK folder.
  2. Use a machine or a docker container running Amazon Linux 2 to build the Linux version of the library by running:
mkdir out
cd out 
cmake -DBUILD_FOR_UNREAL=1 .. 
make

  1. This creates a library file libaws-cpp-sdk-gamelift-server.so in the out/gamelift-server-sdk folder
  2. Copy this file into the Amazon GameLift Unreal plugin package in: ThirdPartyGameLiftServerSDKLinuxx86_64-unknown-linux-gnu

Configure the Lyra Starter Game to use the plugin

With the plugin ready to use:

  • Enable the plugin in the Lyra Starter Game project
  • Add code to use the Amazon GameLift SDK

Enabling the plugin

  1. Copy the top-level GameLiftServerSDK folder into the LyraStarterGamePlugins folder. The folder structure should look like the following:

Image showing Unreal folder tree with PluginsGameLiftServerSDK folder highlighted

  1. Enable the plugin by editing the LyraStarterGame.uproject file and adding the GameLiftServerSDK plugin to the bottom of the list of plugins:

Image showing GameLiftServerSDK plugin node in the LyraStarterGame.uproject file

  1. Edit the SourceLyraGameLyraGame.Build.cs file and add “GameLiftServerSDK” to the list of public module dependencies:

Image showing GameLift ServerSDK added to public module dependencies list

  1. Open the LyraStarterGame project in Unreal Editor and allow it to rebuild the plugin on startup.

Using the Amazon GameLift Server SDK

When you call InitSDK() to initialize the Amazon GameLift Server SDK, you need to provide a FServerParameters object, containing values for how the SDK should be initialized.

With managed Amazon EC2 instances, these server parameter values can be left empty.

However, when setting up an Amazon GameLift Anywhere fleet, you need to specify server parameters to send to Amazon GameLift:

  • The Host ID/Compute Name of the Amazon GameLift Anywhere instance
  • The Anywhere Fleet ID
  • The WebSocket URL
  • The Process ID of the running process
  • The compute authorization token

When you want to test your server as part of an Amazon GameLift Anywhere fleet, you can provide these parameters via the command line.  When you deploy to a managed Amazon EC2 fleet, you can simply omit these parameters.

You will add code to:

  • Initialize the Amazon GameLift Server SDK via the InitSDK action, using our command line parameters, if provided.
  • Inform the Amazon GameLift service that our process is ready to host players via the ProcessReady action, implementing callback functions to handle requests from the Amazon GameLift service to check the process health, activate a new game session, and terminate a running game session.
  1. Open SourceLyraGameLyraGameMode.h and add a private function definition for InitGameLift(). Add a definition to override the BeginPlay() protected function:
    Image showing function definitions added to LyraGameMode.h
  1. Open SourceLyraGameLyraGameMode.cpp and include the Amazon GameLift Server SDK header file at the top of the file:

#include “GameLiftServerSDK.h”

Image showing GameLiftServerSDK.h included at the top of the file

  1. Add the code for the BeginPlay and InitGameLift functions at the bottom of the file:
void ALyraGameMode::BeginPlay()
{
	// Code enclosed with the WITH_GAMELIFT=1 flag is only processed if the following are true:
	// The plugin found the Amazon GameLift server SDK binary files.
	// The build is a game server : Target.Type == TargetRules.TargetType.Server

#if WITH_GAMELIFT
	InitGameLift();
#endif
}

void ALyraGameMode::InitGameLift()
{
	FString AuthToken;
	FString HostId;
	FString FleetId;
	FString WSSUrl;

	FServerParameters serverParameters;

	UE_LOG(LogLyra, Log, TEXT("Running on port %d"), GetWorld()->URL.Port);

	FParse::Value(FCommandLine::Get(), TEXT("-authtoken="), serverParameters.m_authToken);

	if (FParse::Value(FCommandLine::Get(), TEXT("-hostid="), serverParameters.m_hostId))
	{
		UE_LOG(LogLyra, Log, TEXT("HOST_ID: %s"), *serverParameters.m_hostId)
	}

	if (FParse::Value(FCommandLine::Get(), TEXT("-fleetid="), serverParameters.m_fleetId))
	{
		UE_LOG(LogLyra, Log, TEXT("FLEET_ID: %s"), *serverParameters.m_fleetId)
	}

	if (FParse::Value(FCommandLine::Get(), TEXT("-websocketurl="), serverParameters.m_webSocketUrl))
	{
		UE_LOG(LogLyra, Log, TEXT("WEBSOCKET_URL: %s"), *serverParameters.m_webSocketUrl)
	}

	serverParameters.m_processId = FString::Printf(TEXT("%d"), GetCurrentProcessId());
	UE_LOG(LogLyra, Log, TEXT("PID: %s"), *serverParameters.m_processId);

	UE_LOG(LogLyra, Log, TEXT("Initializing the GameLift Server"));

	//Getting the module first.
	FGameLiftServerSDKModule* gameLiftSdkModule = &FModuleManager::
		LoadModuleChecked(FName("GameLiftServerSDK"));

	//InitSDK will establish a local connection with GameLift's agent to enable further communication.
	FGameLiftGenericOutcome initSdkOutcome = gameLiftSdkModule->InitSDK(serverParameters);
	if (initSdkOutcome.IsSuccess())
	{
		UE_LOG(LogLyra, Log, TEXT("GameLift InitSDK succeeded"));
	}
	else
	{
		UE_LOG(LogLyra, Log, TEXT("ERROR: InitSDK failed"));
		FGameLiftError gameLiftError = initSdkOutcome.GetError();
		UE_LOG(LogLyra, Log, TEXT("ERROR: %s"), *gameLiftError.m_errorMessage);
		return;
	}

	//When a game session is created, GameLift sends an activation request to the game server and passes along the game session object containing game properties and other settings.
	//Here is where a game server should take action based on the game session object.
	//Once the game server is ready to receive incoming player connections, it should invoke GameLiftServerAPI.ActivateGameSession()
	auto onGameSession = [=](Aws::GameLift::Server::Model::GameSession gameSession)
	{
		FString gameSessionId = FString(gameSession.GetGameSessionId());
		UE_LOG(LogLyra, Log, TEXT("GameSession Initializing: %s"), *gameSessionId);
		gameLiftSdkModule->ActivateGameSession();
	};
	FProcessParameters* params = new FProcessParameters();
	params->OnStartGameSession.BindLambda(onGameSession);

	//OnProcessTerminate callback. GameLift will invoke this callback before shutting down an instance hosting this game server.
	//It gives this game server a chance to save its state, communicate with services, etc., before being shut down.
	//In this case, we simply tell GameLift we are indeed going to shutdown.
	params->OnTerminate.BindLambda([=]() {
		UE_LOG(LogLyra, Log, TEXT("Game Server Process is terminating"));
		gameLiftSdkModule->ProcessEnding();
		});

	//This is the HealthCheck callback.
	//GameLift will invoke this callback every 60 seconds or so.
	//Here, a game server might want to check the health of dependencies and such.
	//Simply return true if healthy, false otherwise.
	//The game server has 60 seconds to respond with its health status. GameLift will default to 'false' if the game server doesn't respond in time.
	//In this case, we're always healthy!
	params->OnHealthCheck.BindLambda([]() {
		UE_LOG(LogLyra, Log, TEXT("Performing Health Check"));
		return true;
		});

	//The game server takes the port from the Unreal world.
	params->port = GetWorld()->URL.Port;

	//Here, the game server tells GameLift what set of files to upload when the game session ends.
	//GameLift will upload everything specified here for the developers to fetch later.

	TArray logfiles;
	logfiles.Add(TEXT("LyraStarterGame/Saved/Logs/LyraStarterGame"));
	params->logParameters = logfiles;
	//Calling ProcessReady tells GameLift this game server is ready to receive incoming game sessions!
	UE_LOG(LogLyra, Log, TEXT("Calling Process Ready"));
	FGameLiftGenericOutcome processReadyOutcome = gameLiftSdkModule->ProcessReady(*params);
	if (processReadyOutcome.IsSuccess())
	{
		UE_LOG(LogLyra, Log, TEXT("Process Ready Succeded"));
	}
	else
	{
		UE_LOG(LogLyra, Log, TEXT("ERROR: Process Ready Failed"));
		FGameLiftError processReadyError = processReadyOutcome.GetError();
		UE_LOG(LogLyra, Log, TEXT("ERROR: %s"), *processReadyError.m_errorMessage);
	}
	UE_LOG(LogLyra, Log, TEXT("Init GameLift complete"));
}
        

  1. Build with a Development Server Solution Configuration in Visual Studio 2022.

Image showing Development Server solution configuration highlighted

  1. Package the server in the Unreal Editor.

Set up an Amazon GameLift Anywhere fleet

Now that you have your dedicated server ready, the next step is to create an Amazon GameLift Anywhere fleet that allows you to place game sessions on  your local workstation.

Create an Amazon GameLift Anywhere fleet

  1. Create a custom location and specify a location name. Custom location names must begin with “custom-“ and must be a minimum of 8 characters in length:

aws gamelift create-location --location-name custom-

  1. Create a fleet using the newly created location, specifying the compute type as ANYWHERE:

aws gamelift create-fleet --name --compute-type ANYWHERE --locations "Location="

  1. You will be returned some attributes of the fleet – you will need the FleetId for the next step.

Register your workstation and start the server

  1. Register your local workstation as a compute resource in the fleet:

aws gamelift register-compute --compute-name --fleet-id --ip-address --location

You will be returned a JSON object with the compute attributes. Make a note of the GameLiftServiceSdkEndpoint – you will need to pass this in to your game server.

  1. Obtain a compute authorization token for your local workstation:

aws gamelift get-compute-auth-token --fleet-id --compute-name

You will be returned a JSON object with an AuthToken which is required to authorize the server with Amazon GameLift when you initialize the Amazon GameLift Server SDK.

NOTE – the AuthToken expires 15 minutes after creation. Once the token expires, you will need to retrieve a new AuthToken for a different process.

  1. Start the Lyra game server, passing in the compute name, the GameLiftServiceSdkEndpoint, the AuthToken and the FleetId:

LyraServer.exe -log -fleetid= -hostid= -websocketurl= -authtoken=

  1. You should see logs indicating that the call to InitSDK has succeeded and ProcessReady has been successfully called:

Image showing logs to indicating that the InitSDK call was successful

If the call to InitSDK fails, check the command line parameters and make sure you have provided the correct details, and the AuthToken has not expired.

Create a game session

The final step is to create a game session running on your fleet.

In production, it is always recommended to use game session queues and use game session placement events to track the progress of your queue placement.

In development, you can do this via the create-game-session console command:

aws gamelift create-game-session --fleet-id --maximum-player-session-count 2 --location

You will be returned a JSON object with a Status that will be ACTIVATING if everything worked correctly.

You should also see an entry appear in your game server logs showing that the game server is activating:

Image showing log of game session activating.

You can now run the Lyra Starter game client to connect in to your server:

LyraClient.exe -log

Conclusion

You have now learned to integrate the Amazon GameLift Server SDK into Unreal Engine 5 to start game sessions and carry out local testing via Amazon GameLift Anywhere.

To learn more, please visit these additional resources:

AWS Marketplace | Unreal Engine 5

Amazon GameLift adds support for Unreal Engine 5

Introducing Amazon GameLift Anywhere

Amazon GameLift Anywhere Documentation

Deploying an Anywhere Fleet on Amazon GameLift Tutorial Video

Setting Up Dedicated Servers | Unreal Documentation

Unreal Engine 5 Lyra Starter Game | Unreal Documentation

Multiplayer Programming | Unreal Documentation

https://aws.amazon.com/blogs/gametech/unreal-engine-5-dedicated-server-development-with-amazon-gamelift-anywhere/

Related Posts