Integrate your dedicated server to AMS using the AGS SDK
Overview
This article walks you through the lifecycle of a dedicated server (DS) in AccelByte Multiplayer Servers (AMS) and how to integrate a dedicated server with the AccelByte Gaming Services (AGS) Game SDK.
The SDK used to develop both the Server-side and the game client-side is the same SDK.
Prerequisites
Before you begin this guide, you must have:
Installed and configured the AGS Game SDK for your project. The AGS Game SDK is available on both Unreal Engine and Unity. See the SDK setup guides to learn how to install the SDKs.
Prepared a dedicated server executable, built using the Linux architecture.
注記AMS only supports dedicated servers that are built for the Linux architecture.
The lifecycle of a dedicated server under AMS
The local watchdog uses states to keep track of the lifecycle of a dedicated server. The states are:
- Creating: the dedicated server has been launched by the watchdog, and is loading any necessary resources to serve a game session.
- Ready: the server is ready to serve a game session.
- In Session: the server is serving a game session.
- Unresponsive: the server has failed to send a heartbeat to the watchdog in the expected timeframe.
- Draining: the server is not in session and has been sent the drain command.
The change of states are best described by the following diagram:
The dedicated server is required to notify the watchdog when it is ready to handle a game session by using the SendReadyMessage()
API. This is because the dedicated server sometimes requires loading its own assets (such as meshes for a game level) in order to serve a game session. The time required to load such assets vary significantly from game to game. The SendReadyMessage()
API is used so that the dedicated server has time to do this, and can then notify the watchdog that it is ready to serve a game session. The watchdog will then change the dedicated server state from Creating to Ready.
The SDK APIs will not block your dedicated server from running on its own, even if it fails to connect to a local watchdog or an AMS simulator. This ensures that you can continue working on your dedicated server locally, independent of AMS requirements.
When you are ready to start testing your integration with AMS, you can do so locally by using the AMS Simulator. This is a much faster way to test your AMS integration code than uploading your dedicated server to AMS. Learn more in the Run the AMS Simulator section.
Listening to the correct ports
AMS runs multiple of your dedicated servers on each VM. In order to avoid port conflicts, your dedicated server will be assigned arbitrary port numbers determined by the local watchdog.
When your dedicated server starts, it will receive these port numbers in the form of command line arguments. The exact flags used to specify the port numbers are defined by you using the command line template, which is a part of the fleet configuration.
To learn more about configuring the command line argument, see Construct your dedicated server command.
Integrate a dedicated server with AMS
To integrate a dedicated server with AMS, follow these steps:
Set up your server configuration
- Unreal OSS
- Unity
Add the following configuration into your DefaultEngine.ini
file.
[OnlineSubsystemAccelByte]
bManualRegisterServer=True
[/Script/AccelByteUe4Sdk.AccelByteSettings]
bServerUseAMS=True
Mixing AB Unreal SDK and AB Unreal OSS usage is not fully supported and, in most cases, will not function. We recommend to integrate using only the AB OSS as it is more streamlined than only using the AB SDK.
To register your dedicated server with AMS, the SDK requires a dedicated server ID (DS ID) on Unity startup. The DS ID is passed on the command line using the --dsid
parameter. When running in AMS, the DS ID will have the form ds_<uuid>
- Editor
- Linux Server
Set the arguments of your project from Unity Hub before starting the project, for example
-dsId ds_65cb53ac-d2bf-11ef-a6d6-00155d7b207c
Set the DS ID as a command-line argument before executing the server binary.
[YourBinaryName].x86_64 -dsId ds_65cb53ac-d2bf-11ef-a6d6-00155d7b207c
If you are using AGS for matchmaking and want to be matched into servers in the region with the best latency for each game client, open the SDK editor on the menu toolbar AccelByte > Edit Client Settings, enable the checkbox on Service Url Configs > Use AMS QoS Server Url, and click Save.
Register your dedicated server
When your dedicated server is created by a local watchdog, it will transition into the "Creating" state. During the "Creating" state, the server will start to initialize and load all the necessary assets that it requires to serve a game session. During this time, the server is subjected to the creation timeout, which will automatically remove the server if the timeout is exceeded.
Once your server has finished loading, and is ready to serve a game session, your server must notify AMS by calling the respective API:
- Unreal
- Unreal OSS
- Unity
FRegistry::ServerAMS.SendReadyMessage();
const FOnRegisterServerComplete OnServerReady = FOnRegisterServerComplete::CreateUObject(this, &YourClass::OnServerReady);
SessionInterface->SendServerReady(TEXT(""), OnServerReady);
// The `sessionName` parameter, which is the first argument of SendServerReady(), is not utilized in AMS. You can simply pass TEXT("") as its value.
- Editor
- Linux Server
In the Unity Editor, the game needs to wait for the SDK to be connected with AMS.
void SignalReadyForGameSession()
{
ams = AccelByteSDK.GetServerRegistry().GetAMS();
if (ams == null)
{
return;
}
if (ams.IsConnected)
{
ams.SendReadyMessage();
}
else
{
Action signalReady = null;
signalReady = () =>
{
ams.SendReadyMessage();
ams.OnOpen -= signalReady;
};
ams.OnOpen += SignalReady;
}
}
AccelByteSDK.GetServerRegistry().GetAMS().SendReadyMessage();
Make sure your DS has done everything it needs to do to be ready to serve a game session before calling SendReadyMessage()
. If your game is using AGS, this should include finishing server login as the DS will not be ready to interact with AGS until login is complete.
Listening to the drain signal
The drain signal tells a dedicated server that the VM it is running on is slated to be removed. Unless the dedicated server is serving a game session, it will be set to the Draining state and be subject to the drain idle timeout; upon reaching the drain idle timeout, the watchdog will automatically terminate the dedicated server. Dedicated servers in the In Session state will remain subject to the session timeout after being sent a drain signal; upon reaching the session timeout the watchdog will automatically terminate the dedicated server. When your DS receives the drain signal it should finish any essential work (which may include finishing out an active game session as normal) and then exit. Unless your game has unique reasons for behaving differently, the usual expected behavior for a DS that receives the drain signal is:
- if the DS is serving an active game session, finish the session as usual and then exit
- if the DS is not serving a session (e.g., is in the "Ready" state), exit cleanly as soon as possible
There are several reasons why your dedicated servers might receive a drain signal:
- The fleet is deactivated.
- The fleet is scaling in as demand for dedicated servers decreases.
- The nodes hosting the dedicated servers need to be taken down for maintenance.
To register a handler to listen to the drain signal, use:
- Unreal
- Unreal OSS
- Unity
// Please create this instance ONCE if you haven't create it yet.
// If the instance has been created previously, please use the existing one.
auto AccelByteInstance = IAccelByteUe4SdkModuleInterface::Get().CreateAccelByteInstance();
if (!AccelByteInstance.IsValid()) { return false; }
auto ServerApiClient = AccelByteInstance->GetServerApiClient();
if (!ServerApiClient.IsValid()) { return false; }
ServerApiClient->ServerOauth2.LoginWithClientCredentials(LoginHandler, ErrorHandler);
...
ServerApiClient->ServerDSM.RegisterLocalServerToDSM(GAME_PORT, GAME_SESSION_NAME.ToString(), RegisterHandler, ErrorHandler);
...
// Listener
auto AmsDrainDelegate = ServerApiClient->ServerAMS.AddOnAMSDrainReceivedMulticastDelegate(AccelByte::GameServerApi::ServerAMS::FOnAMSDrainReceived::CreateLambda([&]() {
bDrainReceived = true;
}));
ServerApiClient->ServerAMS.SendReadyMessage();
//AmsDrainDelegate can be used to Reset
AmsDrainDelegate.Reset();
return bDrainReceived;
FOnAMSDrainReceivedDelegate OnAMSDrainReceivedDelegate = FOnAMSDrainReceivedDelegate::CreateUObject(this, &ClassName::OnAMSDrain);
OnAMSDrainReceivedHandle = SessionInterface->AddOnAMSDrainReceivedDelegate_Handle(OnAMSDrainReceivedDelegate);
AccelByteSDK.GetServerRegistry().GetAMS().OnDrainReceived += () =>
{
// The application should exit unless there is an active game session
if (!IsSessionActive)
{
ams.Disconnect();
#if UNITY_EDITOR
UnityEditor.EditorApplication.ExitPlaymode();
#else
Application.Quit();
#endif
}
};
For a full code example, see Complete code example using AGS sessions.
Now that you have completed your dedicated server integration code and configuration, you are ready to test it out using the AMS Simulator.
Run the AMS Simulator
The AMS Simulator emulates how the watchdog interacts with the dedicated server. It is a great tool to verify your dedicated server interactions with the watchdog so that you can be confident that your dedicated server will work on the AMS environment before uploading a dedicated server build. You can download the AMS Simulator on the Download Resource page on the Admin Portal. For more information, see Download AMS CLI tools from the Admin Portal.
This section is about running AMS Simulator in Standalone mode, which means it doesn’t register your local DS with your AMS cloud environment for matchmaking. In this mode, AMS Simulator doesn't connect to your cloud environment at all. Standalone mode is sufficient to test your server's integration with AMS. If you're looking to register your local server to your (live) environment so that you can test end to end with Matchmaking, see Register local dedicated servers with AMS.
To run the AMS Simulator, use this command:
> amssim run
Generate a config.json file
The first time when you call the run command, a config.json
file will be automatically generated for you. config.json
is located in the directory from which you run the amssim
executable and it contains settings that are essential to run your dedicated servers. Feel free to change any of these values to match how you would want your dedicated server to run.
Here's an example of a config.json
file:
{
"WatchdogPort": 5555,
"AGSEnvironmentURL": "",
"AGSNamespace": "",
"IAM": {
"ClientID": "",
"ClientSecret": ""
},
"LocalDSHost": "",
"LocalDSPort": 0,
"ClaimKeys": [],
"ServerName": "my-computer-name"
}
Note that leaving AGSEnvironmentURL
empty makes AMS Simulator run in standalone mode (which is what you want in this example).
Alternatively, you can use the following command to generate or replace your config.json
with default values.
> amssim generate-config
Generate a session
Every time you start the amssim
, a unique amssim session will be created. You can review your session information by using the info command:
amssim> info
AMS simulator url ws://0.0.0.0:5555/watchdog
AMS simulator session id: 01hcnefg15exp386j9rx901saa.
AMS simulator session log path: session\01hcnefg15exp386j9rx901saa.log
no connected dedicated server
Launch a dedicated server
When you have integrated your dedicated server with the AccelByte SDK, you can launch your dedicated server directly from your IDE, after configuring the required arguments. Provide the -dsid
argument to your dedicated server with a valid ID, like the example command line shown in the output of AMS Simulator (but any DS ID is valid as long as it follows the ds_<uuid>
format), and provide the -port
argument to override the default port that your dedicated server listens on. If you have not changed WatchdogPort
in config.json
, the AccelByte SDK will automatically connect to the AMS SIM instance at ws://localhost:5555/watchdog
. Otherwise, make sure that the dedicated server is connecting to AMS Simulator at the correct port by using the -watchdog_url
command line argument for Unreal or -watchdogUrl
for Unity. Later when you run the dedicated server in a live fleet, these values will be provided by the watchdog according your fleet configuration. (Read more on argument substitution in Construct your dedicated server command.)
If the connection is successful, you will see that the ds
state is Creating or Ready, depending on whether your dedicated server has called the Ready API.
When running in AMS, a server in the Creating state will be subjected to the creation timeout and will be terminated by the watchdog if it does not signal that it is ready before that timeout expires. Because amssim
does not launch the DS process, it does not manage the DS process lifetime or enforce any timeouts.
At any point if you want to check your dedicated server state, use this status command:
amssim> ds status
Set dedicated servers to the Ready state without calling the Ready API
The Ready command allows you to set your dedicated server state from any other state to Ready. This isn't particularly useful or interesting in standalone mode, but can be used to repeatedly claim the same DS without restarting the DS process when using the Local DS capabilities.
To set your dedicated server to the Ready state, use this command:
amssim> ds ready
Send drain signal to the server
The drain signal tells a dedicated server it should exit when it can safely do so without interrupting an active game session. When running in AMS, any server that is not In Session and has received the drain signal is subject to the drain idle timeout.
When the drain signal is sent to the dedicated server, the signal will trigger the OnDrainReceived()
handler. Your dedicated server can then override the handler to execute a code path to handle the drain signal.
Your dedicated server should respond to the drain signal by exiting cleanly as soon as it is not in session and has completed whatever work it needs to do.
To send a drain signal to your dedicated server, use this command:
amssim> ds drain
Complete code example using AGS sessions
- Unity
using AccelByte.Core;
using AccelByte.Models;
using AccelByte.Server;
using System.Collections;
using UnityEngine;
public class AmsDsConnection : MonoBehaviour
{
bool isAmsReady = false;
DedicatedServer ds;
ServerDSHub dsHub;
ServerAMS ams;
IEnumerator Start()
{
#if !UNITY_EDITOR && !(UNITY_STANDALONE_LINUX && UNITY_SERVER)
// This feature only available for Linux Server and Unity Editor.
yield break;
#endif
// Ensure the dedicated server is logged in and ready.
ds = AccelByteSDK.GetServerRegistry().GetApi().GetDedicatedServer();
Result loginResult = null;
ds.LoginWithClientCredentials(result =>
{
if (result.IsError)
{
// Do something if LoginWithClientCredentials fails.
Debug.Log($"Error LoginWithClientCredentials, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
loginResult = result;
// Your additional logic when the dedicated server successfully logs in.
});
yield return new WaitUntil(() => loginResult != null);
// Connect AMS (when not on server build) and set AMS as ready.
ams = AccelByteSDK.GetServerRegistry().GetAMS();
if (ams == null)
{
Debug.LogError("Failed to connect to AMS, please see SDK warning log");
yield break;
}
#if UNITY_STANDALONE_LINUX && UNITY_SERVER
ams.SendReadyMessage();
isAmsReady = true;
#else
// This code is intentionally for editor only.
ams.OnOpen += OnAmsConnected;
#endif
yield return new WaitUntil(() => isAmsReady);
string myServerId = AccelByteSDK.GetServerRegistry().Config.DsId;
// Connect DS Hub and your logic to its events.
DS Hub = AccelByteSDK.GetServerRegistry().GetApi().GetDsHub();
dsHub.Connect(myServerId);
dsHub.OnConnected += OnDsHubConnected;
dsHub.OnDisconnected += OnDsHubDisconnected;
dsHub.MatchmakingV2ServerClaimed += OnDsHubServerClaimed;
// DS Hub has many more events that you can listen to for your custom game logic.
}
void OnAmsConnected()
{
Debug.Log("AMS connected");
ams.SendReadyMessage();
isAmsReady = true;
ams.OnOpen -= OnAmsConnected;
}
void OnDsHubConnected()
{
Debug.Log("Ds Hub connected");
// Your logic when DS Hub successfully connects.
}
void OnDsHubDisconnected(WsCloseCode closeCode)
{
Debug.Log("Ds Hub disconnected");
// Your logic when DS Hub has disconnected.
}
void OnDsHubServerClaimed(Result<ServerClaimedNotification> claimedNotificationResult)
{
ServerClaimedNotification claimedNotification = claimedNotificationResult.Value;
// Your logic when this instance is claimed for a game session
}
}
What's next
Now that you have your dedicated server integrated and verified using AMS Simulator, you are ready to upload a dedicated server build using the AMS CLI.
You can also register a local dedicated server with AMS to test your integration and claim flow before you upload your dedicated server build and deploy dedicated servers with an AMS fleet.