45. Dedicated server support

This documentation explains how to build a game service using the client engine’s dedicated server features. You can use dedicated server features of UnrealEngine 4 and Unity with iFun Engine.

iFun Engine's dedicated server architecture

A physical or virtual machine that launches dedicated servers is called a dedicated server host. These make it possible for users to undergo a series of processes to access iFun Engine as a dedicated server.

  1. (Server) iFun Engine spawns a dedicated server with additional data.

  2. iFun Engine collects users to send to a single dedicated server along with additional data.

  3. Selects dedicated server host and begins dedicated server process.

  4. Running dedicated servers

    • Begins the dedicated server process
    • Sends command line argument to the client plugin to perform the required initialization
    • Invokes particular plugin functions and finishes preparations when the dedicated server is ready
  5. Invokes startup complete callback on the iFun Engine server side and sends access data to the client.

  6. (Client) Receives plugin callback to access the dedicated server and play the game.

  7. (Dedicated server) Sends game results from the dedicated server when the game ends.

45.1. Changing server settings

Add the following to MANIFEST.json to use dedicated server features.

"DedicatedServerManager": {
}

45.2. Dedicated server manager

45.2.1. Installing the dedicated server manager

The same Linux environments as iFun Engine are supported along with MS Windows.

45.2.1.1. Installing in Linux

Ubuntu Linux

$ sudo apt-get install -y funapi1-dedicated-server-host

CentOS

$ sudo yum install -y funapi1-dedicated-server-host

45.2.1.2. Installing in MS Windows

Tests have been run in Windows 10 (x64) 64-bit Python 2.7.14.

  1. First, download and install Python for MS Windows. (Please select latest release of Python 2.7.)

  2. Assuming Python is installed by default in c:\Python27, enter the following commands into a command line to install the required package.

    C:\> C:\Python2.7\Script\pip.exe install flask gevent netifaces ^
        python-gflags requests redis six
    

    Note

    ^ is the line continuation character for MS-DOS batch files. Enter on one line.

  3. Download the dedicated server manager, install where you want it, and unzip it.

45.2.2. Configuring the dedicated server manager

Set up the configuration file as follows.

  • Set your dedicated server engine type (ue4 or unity)
  • Set network interface to receive game client connections
  • Set network interface to receive iFun Engine game server commands
  • Redis server address. The redis server must be shared with iFun Engine.
  • Dedicated server executable location

In Linux, the configuration file is in /etc/funapi-dedicated-server-host/funapi-dedicated-server-host.flag. You can confirm the directory to unzip the file in MS Windows.

Linux example

# Lines that begins with the '#' are ignored.
# You should update binary_path to your dedicated server executable's location.
--binary_path=/var/lib/your/dedicated-server/binary

# Engine type. Possible values are 'ue4' (UnrealEngine4) and 'unity' (Unity).
--engine_type=ue4

# Also, you should update redis_host, redis_port to match the redis address.
--redis_host=127.0.0.1
--redis_port=6379

# If you want to bind the specific NIC for clients, update the following lines.
# And you may choose another NIC for inter-server communication.
# eg) You may use eno1 for games, and eno2 for inter-server communication.
# Depends on your OS, NIC name can be varying - eg) eth0, eno1, ens1, enp2s0.
--game_interface=eth0
--restful_interface=eth1

Dedicated server binary is an executable file called /var/lib/your/dedicated-server/binary, and the Redis server is a configuration file hosted at 127.0.0.1:6379. The game client communicates with eth0, and if it communicates with the iFun Engine game server with eth1, you can set it up as above.

MS Windows example

MS Windows uses the game_ip and restful_ip parameters. (It does not use the interface parameter.) These values must be set in order to connect properly.

# Lines that begins with the '#' are ignored.
# You should update binary_path to your dedicated server executable's location.
--binary_path=D:\ShooterGame\ShooterGame.exe

# Engine type. Possible values are 'ue4' (UnrealEngine4) and 'unity' (Unity).
--engine_type=ue4

# Also, you should update redis_host, redis_port to match the redis address.
--redis_host=127.0.0.1
--redis_port=6379

# For Microsoft Windows, you must use following flags, instead of
# game_interface or restful_interface.
# IP addresses used by game clients and game servers respectively.
--game_ip=10.0.0.7
--restful_ip=10.10.1.7

Tip

If you want to pass additional arguments to the dedicated server, specify the script file (.sh or .bat depending on OS) instead of the --binary_path executable location and add arguments from that file.

You can also use the UE4 editor to set up launch without packaging during development. Here is an example: (Using a .bat file in MS Windows)

REM exmple batch file, which utilizes UE4 editor to launch dedicated server

"C:\Program Files\Epic Games\4.14\Engine\Binaries\Win64\UE4Editor.exe" ^
  "C:\Work\apps-ue4-dedi-server-example\ShooterGame\ShooterGame.uproject" ^
  HighRise -skipcompile -server -log ^
  %*

Use the UE4 editor to launch the dedicated server and add HighRise to be sent as the map name.

When sending values that need to be changed for each game, like map name and game mode, use the DedicatedServerManager::SendUsers() function’s server_args as in the next section.

45.2.3. Running the dedicated server manager

Running in Ubuntu 16.04/CentOS 7

First, activate the service with the following command:

$ sudo systemctl daemon-reload
$ sudo systemctl enable funapi-dedicated-server-host

Then start the service.

$ sudo systemctl start funapi-dedicated-server-host

Running in Ubuntu 14.04

Execute the service as follows:

$ sudo start funapi-dedicated-server-host

Running in MS Windows

Configure the data in funapi-dedicated-server-host.flag, then run the command below in the directory with the funapi_dedicated_server folder.

This assumes unzipping in the D:\DedicatedServerHost directory.

D:\DedicatedServerHost> C:\Python2.7\python.exe -m funapi_dedicated_server ^
    --flagfile=funapi-dedicated-server-host.flag

Note

^ is the line continuation character for MS-DOS batch files. Enter on one line.

45.3. Starting games

Invoke the following function on the game server:

#include <funapi/service/dedicated_server_manager.h>

void start_callback(const fun::Uuid &match_id,
                    const std::vector<std::string> &accounts,
                    bool success) {
  // Do anything after dedicated game server started.
  // You may handle the failed spawning of dedicated game server here.
}


DedicatedServerManager::Spawn(
    match_id,
    game_data,
    server_args,
    accounts,
    user_data,
    start_callback);

Parameters have the following meanings:

  • fun::Uuid match_id: The unique ID for each dedicated server instance. This ID is also used when receiving results after the game is played.
  • fun::Json game_data: JSON data received and used from the dedicated server. Put data needed to start the game here.
  • std::vector<std::string> server_args: Set arguments to be sent to the dedicated server executable file. For example, if a map must be selected, pass it as map=blahblah?opt1=1&opt2=2.
  • std::vector<std::string> accounts: Send user account IDs managed by AccountManager. iFun Engine will automatically notify dedicated server address to clients.
  • std::vector<fun::Json> user_data: Per-user data. The ``user_data.size()`` should be equal to ``accounts.size()``.
  • start_callback: Callback function invoked upon game success/failure to start.

If the host launching the dedicated server executes successfully, access data (address, token, etc.) is sent to individual clients after the callback function is invoked. The individual client can access the dedicated server to play the game.

45.3.1. Sending users to already started game

You may send user(s) to ongoing game by using DedicatedServerManager::SendUsers API.

static void SendUsers(const fun::Uuid &match_id,
                      const fun::Json &match_data,
                      const std::vector<std::string> &accounts,
                      const std::vector<fun::Json> &user_data,
                      const SendCallback &callback);

You may call DedicatedServerManager::SendUsers() with the same arguments as Spawn() – except game_data argument.

45.4. Handling dedicated servers (Unreal Engine 4)

You can find Unreal Engine 4 example at GitHub. Also, you can find Unity Eample at GitHub .

Required elements to communicate with the iFun Engine server are gathered and provided as fun::FunapiDedicatedServer class member functions.

45.4.1. Handling command line arguments

Invoke the code below to read command line arguments. The code below needs to be invoked to read data sent from the game server or game results sent to the game server. The applicable function is as follows:

bool ParseConsoleCommand(const TCHAR* cmd,
                         const FString &match_id_field,
                         const FString &manager_server_field);

If not all required parameters can be obtained, false is returned. If executed as follows, the required arguments are automatically analyzed.

fun::FunapiDedicatedServer::ParseConsoleCommand(FCommandLine::Get());

If you want to use command line arguments for the dedicated server other than the default values, invoke them as follows:

fun::FunapiDedicatedServer::ParseConsoleCommand(
    FCommandLine::Get(),
    "FunapiMatchID",        // Argument for match id.
    "FunapiManagerServer",  // Server address for dedicated server manager.
  );

45.4.2. Fetching required data

You can invoke the following function to fetch data sent from the game server to the dedicated server. After fetching this data, you can perform the required reset inside the callback function.

void GetGameInfo(
    const TFunction<void(FHttpResponsePtr response)> &completion_handler);

For example, set up and invoke the callback function as follows:

// After fetching the data, this callback function will be called.
void OnDataReceived(FHttpResponsePtr response) {
  // Response has data in JSON format, which was sent by the game server.
}

// Fetches the data.
fun::FunapiDedicatedServer::GetGameInfo(OnDataReceived);

45.4.3. Sending notification when the dedicated server is ready

Once the dedicated server has been initialized, invoke the following function to notify the dedicated server manager so the client can access it.

fun::FunapiDedicatedServer::PostReady();

45.4.4. Handling user authentication

This function is only valid after GetGameInfo() is called.

A function to authenticate users is provided at UE4’s PreLogin stage. Invoke the following function to handle authentication after client access. Use FunapiUID and FunapiToken as user ID and authentication token field names. If you need to use other values, use a second function.

// Authenticates user. Returns whether authentication is successful.
bool AuthUser(const FString& options,  // Argument passed in PreLogin step.
              FString &error_message);  // Error message for failed auth.

// If you changed the field name for user id and token, use this function.
bool AuthUser(const FString& options,  //  Argument passed in PreLogin step.
              const FString& uid_field,  // Field name for an uid
              const FString& token_field,  // Field name for a token
              FString &error_message);  // Error message for failed auth.

For example, invoke as follows:

// If you are using the default fields.
if (!fun::FunapiDedicatedServer::AuthUser(Options, ErrorMessage)) {
  // Handle authentication failure.
}

// If you use non-default fields.
if (!fun::FunapiDedicatedServer::AuthUser(Options,
                                          "FunapiUID",
                                          "FunapiToken",
                                          ErrorMessage)) {
  // Handle authentication failure.
}

45.4.5. Reporting game results

When the game ends, data is created and sent to the game server in JSON format. Use the following function.

void PostResult(const FString &json_string, const bool use_exit);

If use_exit is true, the dedicated server shuts down after results are reported.

For example, invoke as follows to report game results:

fun::FunapiDedicatedServer::PostResult(
    FString("{ \"foo\":\"bar\"}"), false);

Game results sent here are handled in server code as explained in Handling game results.

45.5. Handling dedicated servers (Unity)

Unity example can be found at GitHub. There is a FunapiDedicatedServer class, which provides required functionality to enable Unity dedicated server to communicate with iFunEngine.

45.5.1. Handling command line arguments

bool FunapiDedicatedServer.Init();

The code above parses and processes command line argument passed to a dedicated server. If the command line arguments are malformed or missing required argument, it would return false.

45.5.2. Starting dedicated server

FunapiDedicatedServer.Start();

After calling the Start() method, dedicated server related functionality will be started. A dedicated server would receive data after calling this method.

45.5.3. Fetching required data

You can invoke the following functions to fetch data set from the game server.

// Get user data
string GetUserDataJsonString(string uid);

// Get match data
string GetMatchDataJsonString();

45.5.4. Sending notification when the dedicated server is ready

Once the dedicated server has been initialized, invoke the following function to notify the dedicated server manager so the client can access it.

FunapiDedicatedServer.Ready();

45.5.5. Handling user authentication

You can validate the user authentication using the following API.

FunapiDedicatedServer.AuthUser(string uid, string token);

45.5.6. Notifying user join / leave

void SendJoined(string uid);

void SendLeft(string uid);

If you want to notify the game server for newly joined/left users, use the above APIs.

45.5.7. Reporting game results

When the game ends, data is created and sent to the game server in JSON format. Use the following function.

void SendResult(string json_string);

45.6. Handling game results

As discussed previously in Reporting game results, results sent to the game server can be handled by the relevant callback function once it is preregistered.

#include <funapi/service/dedicated_server_manager.h>


// 게임 결과를 처리하는 콜백 함수입니다.
void result_callback(const fun::Uuid &match_id,
                     const fun::Json &match_data,
                     bool success) {
    // 게임 결과 처리를 수행합니다.
}

// 콜백을 등록합니다.
DedicatedServerManager::RegisterMatchResultCallback(result_callback);

If the callback function is preregistered in the game server’s Start() function, results can be received and processed after the game ends. JSON data sent by the dedicated server is in match_data. Use the relevant values and match ID to perform tasks like saving game results in a database.