Skip to content

Game Host Adapter

The GameHostAdapter library is a utility library used to help bootstrap dedicated server allocations across multiple vendors. It is a required part of the integration in order to utilize our server allocation scheme.

The library is publicly available on Github at https://github.com/RallyHereInteractive/game-host-adapter, with the most recent release being at https://github.com/RallyHereInteractive/game-host-adapter/releases/latest.

NOTE: A version of the library comes pre-integrated into the Unreal Integration plugins. We suggest referencing it as an example integration.

C/C++ Library

To integrate the library, you will need the files from the include/game-host-adapter folder in the Github release, plus the library binaries. Note that the Windows binaries package has some additional libraries required to run, that are also included.

The adapter is provided as a dynamic library to be loaded. A static wrapping library may be provided in future releases or for specific platforms.

Library API

When including the library, you should only need to include c_api.h, which should include the other files. This file defines a set of C functions that can be looked up and bound after the library is loaded.

Note that most calls in the library provide a RallyHereStatusCode enum value in their responses. Generally, you can check this with rallyhere_is_error(<code>) to determine if it is an error. Additionally, you can get a printable version of the error using rallyhere_status_text(<code>).

Loading the Library

The dynamic library can be loaded through standard means. However, if your program includes OpenSSL and is running on Linux, we recommend using the (RTLD_LAZY | RTLD_DEEPBIND) flags when loading it to prevent conflicts.

Once the library is loaded and functions bound, it must be initialized by calling rallyhere_global_init(). Before unloading the library, you must call rallyhere_global_cleanup().

Note that for fleet maintainance and extensibility reasons, we require that the library path be able to be overridden by -gamehostadapterlibpath=<path> on the commandline. This allows us to deploy updates to the library without needing to know your program’s folder structure.

Creating an Adapter Context

To utilize the library, you will need to create an adapter context object once the library is loaded and initialized. This can be done by calling one of the following functions:

/// Create a new adapter using a single string to represent the command line arguments it will use for initialization.
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT RallyHereStatusCode rallyhere_create_game_instance_adapter(RallyHereGameInstanceAdapterPtr* adapter, const char* arguments);
/// Create a new adapter using a C-style array to represent the command line arguments it will use for initialization.
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT RallyHereStatusCode rallyhere_create_game_instance_adaptern(RallyHereGameInstanceAdapterPtr* adapter,
const char* arguments,
unsigned int arguments_length);
/// Create a new adapter using a single string to represent the command line arguments it will use for
/// initialization and a custom logging function to be used from the moment it is created.
/// @sa rallyhere_set_log_callback
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT RallyHereStatusCode rallyhere_create_game_instance_adapter_with_logger(RallyHereGameInstanceAdapterPtr* adapter,
const char* arguments,
RallyHereLogCallback callback,
void* user_data);
/// Create a new adapter using a C-style array to represent the command line arguments it will use for
/// initialization and a custom logging function to be used from the moment it is created.
/// @sa rallyhere_set_log_callback
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT RallyHereStatusCode rallyhere_create_game_instance_adaptern_with_logger(RallyHereGameInstanceAdapterPtr* adapter,
const char* arguments,
unsigned int arguments_length,
RallyHereLogCallback callback,
void* user_data);

The adapter passed in is an out pointer to the resulting adapter. It is valid if the RallyHereStatusCode returned passes a rallyhere_is_error(<return_code>) check.

The arguments passed in must contain the commandline arguments string (though additional argments can be added as needed). The n variants of the function allows for an arguments_length to be specified.

The callback passed in is a function pointer that will be called when the library needs to log something. The user_data passed in will be passed back to the callback function.

Required Adapter Functions

To utilize the adapter, you will need to implement calls to the following functions, and relevant callbacks.

///@name Soft Stop
/// There are times when the game hosting system would like your instance to shut down, but it does not need to
/// happen immediately. In these situations a soft-stop will be requested so that your instance can finish any
/// currently running games and then stop gracefully. Currently only used by SIC and i3D.
///@{
/// @brief The callback to trigger when the game host wants to stop the game instance.
///
/// In SIC this is expected to come from the SIGTERM handler.
/// In i3D this is expected to come from the Arcus commands
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT void rallyhere_on_soft_stop_callback(RallyHereGameInstanceAdapterPtr adapter,
void (*callback)(const RallyHereStatusCode& code, void* user_data),
void* user_data);

The rallyhere_on_soft_stop_callback registers a callback that is triggered when a soft stop is requested by the hosting provider. This does not mean an exit must happen immediately, but does hint that the server should shutdown as soon as possible.

/// @brief Tick that's expected to be called every frame.
///
/// This is used to check for any messages from the game host. All deferred message processing and callbacks will be
/// handled during this tick.
/// @return RH_STATUS_OK if this adapter can still be used, otherwise an error code.
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT RallyHereStatusCode rallyhere_tick(RallyHereGameInstanceAdapterPtr adapter);

The rallyhere_tick function must be called routinely (generally every frame), as it is used to process any pending requests from the library and to do health checks. Most callbacks generated are dispatched during this function call on the thread making the call. Some callbacks may be called during the initial function call which used them, or when rallyhere_destroy_game_instance_adapter is called.

/// @brief Mark the adapter as healthy.
///
/// This is used to tell the game host that this adapter is still alive and well. Should be called at a regular
/// interval. Every 5 seconds is a good rule of thumb. Currently only used by Agones.
/// SIC relies on an open metrics endpoint created by this SDK.
/// i3D relies on the Arcus socket connection.
/// Multiplay reliies on the A2S socket connection.
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT RallyHereStatusCode rallyhere_healthy(RallyHereGameInstanceAdapterPtr adapter);

The rallyhere_healthy function must be called routinely (every frame is fine, but at least once every few seconds), as it informs the adapter layer that the server is still in a healthy state.

/// @brief Set the base stats for the game instance.
///
/// Provide a callback to be notified when the stats have been set
/// These will be exported as labels on the "instance_info" gauge.
/// These will be exported as part of the A2S_INFO query.
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT RallyHereStatusCode rallyhere_stats_base(RallyHereGameInstanceAdapterPtr adapter,
const RallyHereStatsBase* stats,
const RallyHereStatsBaseProvided *provided,
void (*callback)(const RallyHereStatusCode& code, void* user_data),
void* user_data);

The rallyhere_stats_base is used to set some of the basic stats provided by the game. The callback is triggered when the hosting provider accepts these basic stats about the server. In the case of an error there was something wrong with the format of the stats or the hosting provider rejected them. Once the callback is successful all external systems which monitor for these stats should see the newly set values.

Additional stats can be provided using the rallyhere_set_additional_info, rallyhere_stats_gauge, and rallyhere_stats_gauge_with_labels functions.

Destroying an Adapter Context

To destroy an adapter context, call the following function:

/// @brief Destroys the adapter.
///
/// Before any memory is freed every registered callback is called with the status RH_STATUS_CANCELLED so that
/// any memory associated with the callback's user data can be freed.
/// @public @memberof RallyHereGameInstanceAdapter
RH_EXPORT void rallyhere_destroy_game_instance_adapter(RallyHereGameInstanceAdapterPtr adapter);
///@}

Requested Allocation Flow

This flow supports servers that are fielded via requests to the allocation service, such as via matchmaking. These servers spin up and then wait for allocation data from the hosting provider.

The Requested Allocation Flow utilizes the following functions in the following order. These functions are all asynchronous, and upon completion will call the provided callback function. The status code should be checked with rallyhere_is_error(<code>) before using the results and calling the next function, except as noted below

  1. rallyhere_connect -> (callback as passed in)
  2. rallyhere_on_allocated_callback to register callback for allocation complete
  3. rallyhere_ready -> (callback as passed in)
  4. callback from rallyhere_on_allocated_callback as registered above

The callback response from rallyhere_on_allocated_callback has some additional recommended checks from the status code:

  • rallyhere_is_cancelled(<code>) - this is a special code indicating that any resources associated with this callback should be freed and that the callback won’t be used again. This is usually called during rallyhere_destory_game_instance_adapter to give the user a chance to free any user_data.
  • rallyhere_is_error(<code>) - as normal, this is an error.

If the result is not an error, then the allocation_info is a string map containing the following keys:

  • allocation_id - the allocation id from the hosting provider
  • public_host - the public hostname or ip that the hosting provider will use for clients to connect to this server
  • public_port - the public port the hosting provider will use for clients to connect to this server

These can be retrieved from the map with the rallyhere_string_map_get function, which takes the map pointer, the key, and has an out pointer to the resulting value (a UTF8 character array) and the length of the value.

Note that the callback should destroy the allocation_info object with rallyhere_string_map_destroy once complete, or memory will be leaked.

Self-Hosted Allocation Flow With No Fallback

This flow supports servers that are designed to self-allocate, such as for fixed-capacity open world servers, or third party hosted servers. These servers will mark themselves as allocated, and provide functionality immediately upon spinning up rather than waiting on a request.

The Self-Hosted Allocation Flow With No Fallback utilizes the following functions in the following order. These functions are all asynchronous, and upon completion will call the provided callback function. The status code should be checked with rallyhere_is_error(<code>) before using the results and calling the next function, except as noted below

  1. rallyhere_connect -> (callback as passed in)
  2. rallyhere_reserve_unconditional -> (callback as passed in)
  3. Server completes its self initialization and enters its running state
  4. rallyhere_allocate -> (callback as passed in)

The callback response from rallyhere_allocate has some additional recommended checks from the status code:

  • rallyhere_is_cancelled(<code>) - this is a special code indicating that any resources associated with this callback should be freed and that the callback won’t be used again. This is usually called during rallyhere_destory_game_instance_adapter to give the user a chance to free any user_data.
  • rallyhere_is_error(<code>) - as normal, this is an error.

If you have registered a callback via rallyhere_on_allocated_callback, it will also be called as a result of the rallyhere_allocate call. In this situation the allocation_info map will be nullptr, as the server is assumed to provide it itself.

Self-Hosted Allocation Flow With Fallback Timeout

This flow supports servers that are designed to self-allocate, such as for fixed-capacity open world servers, or third party hosted servers. These servers will mark themselves as allocated, and provide functionality immediately upon spinning up rather than waiting on a request. A timeout is provided so that if this doesn’t happen within a certain amount of time the requested allocation flow will be used instead. This can be a way to handle the situation where third parties are able to launch instances, but need to return to the normal flow if no players connect after a certain amount of time.

The Self-Hosted Allocation Flow With Fallback utilizes the following functions in the following order. These functions are all asynchronous, and upon completion will call the provided callback function. The status code should be checked with rallyhere_is_error(<code>) before using the results and calling the next function, except as noted below

  1. rallyhere_connect -> (callback as passed in)
  2. rallyhere_on_allocated_callback to register callback for allocation complete
  3. rallyhere_reserve -> pass in a timeout, a callback for when the reservation is accepted, and a callback to use if the requested allocation flow is used
  4. Server completes its self initialization and enters its running state
  5. rallyhere_allocate -> (callback as passed in)

The callback response from rallyhere_allocate has some additional recommended checks from the status code:

  • rallyhere_is_cancelled(<code>) - this is a special code indicating that any resources associated with this callback should be freed and that the callback won’t be used again. This is usually called during rallyhere_destory_game_instance_adapter to give the user a chance to free any user_data.
  • rallyhere_is_error(<code>) - as normal, this is an error.

If you have registered a callback via rallyhere_on_allocated_callback, it will also be called as a result of the rallyhere_allocate call. In this situation the allocation_info map will be nullptr, as the server is assumed to provide it itself.

In the case where an amount of seconds greater than the timeout happens between rallyhere_reserve and rallyhere_allocate, then the ready callback will be called. Once this happens you may no longer call rallyhere_allocate and instead must wait for the callback provided to rallyhere_on_allocated_callback to be triggered. See the Requested Allocation Flow for handling that case.

Testing

To begin, you will need a credential file. This can be provided via your RallyHere developer contact.

All tests require the following command line arguments:

  • -rallyhereurl=<url_to_rallyhere_api> - This provides the URL to the RallyHere API
  • -rhcredentialsfile=<path_to_credentials_file> - the path to the credentials file mentioned above.
  • -rhpublichost=<hostname_or_ip_for_connection> - the hostname or IP to use for connecting to the server

Note for the Unreal Integration, the -rallyhereurl argument is not required, as it is provided by the integration based on the detected baseurl and sandbox.

Running SIC Servers

This method is used to test the Self-Hosted Allocation Flow With No Fallback

You will need a SIC profile id for the sandbox you are trying to host in. This can be provided via your RallyHere developer contact.

To run in SIC mode server using the library, you will need to provide the following command line arguments (note - deployed servers will receive additional commandline arguments that the library will process):

  • -rhbootstrapmode=SIC - this informs the library that it will be running in SIC mode
  • -rhsicprofileid=<sic_profile_id>_<region_id> - this is used by the SIC system to identify the server and register it. The <region_id> field suffix is the region the server will provide service for.

Most developer environments have regions 100-200 preconfigured as developer regions.

Running in AutoCreate mode

This method is used to test the Self-Hosted Allocation Flow With Fallback Timeout

To run in this mode, use the following

  • -rhbootstrapmode=AutoCreate - this informs the library that it will be running in AutoCreate mode

Using the Unreal Integration

Information on utilizing the pre-integrated implementation of Game Host Adapter in the Unreal Integration can be found at the Unreal Integration Dedicated Server Bootstrapping documentation