34. Server management part 3: Server packaging

34.1. Flavors: Identifying servers according to their role

In some cases, you may need to set up servers differently depending on their role. You can set server flavors for this purpose in iFun Engine.

34.1.1. What is a flavor?

Flavors are server types that share source code but handle different roles. For example, a lobby server type and game server type may differ even if they use the same source code and can be identified as the lobby flavor and game flavor in iFun Engine.

34.1.2. Setting up flavors

If you want to differentiate between a lobby type game server and game type game server, set flavors as follows in the top-level CMakeLists.txt.

1
2
3
4
...
set(APP_FLAVORS lobby game)
...
include(Funapi)

34.1.3. Automatically created files for each flavor

When you set up and build this way, iFun Engine automatically creates the following files.

34.1.3.1. MANIFEST.json

Copy src/MANIFEST.json, included by default, to create src/MANIFEST.lobby.json and src/MANIFEST.game.json in the source directory. You can now change the MANIFEST.json for each flavor as necessary.

34.1.3.2. Launcher script

A launcher script is created for each flavor in the build directory. In the example above, scripts ending with .lobby-local, .lobby-launcher, .game-local, and game-launcher are created.

34.1.3.3. Daemon script

If set(WANT_SYSTEMD true) or set(WANT_UPSTART true) is set in CMakeLists.txt, script files are also created to run the game server using a daemon. Files included by default are copied to create files for flavor use, just as with MANIFEST.json.

For *set(WANT_SYSTEMD true):

  • Files are created in the etc/systemd/ directory in the source directory in formats like .chat.service and .lobby.service.

For *set(WANT_UPSTART true):

  • Files like .chat and .lobby are created in the etc/upstart/default/ directory in the source directory.
  • Files like .chat.conf and .lobby.conf are created in the etc/upstart/init/ directory in the source directory.

Note

Files created in this way are included and installed or distributed during make install or make package.

34.1.4. Learning the current flavor from code

To handle server actions differently for each flavor, you need to know the current server flavor from the code. Use a Google flag called app_flavor for this. The following is an example of use.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 DECLARE_string(app_flavor)

 class MyGameServer : public Component {
  public:
   static bool Install(const ArgumentMap &arguments) {
     if (FLAGS_app_flavor == "lobby") {
       // Configure as a lobby server.
     } else if (FLAGS_app_flavor == "game") {
       // Configure as a game server.
     }
   }
 }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Server
{
  public static void Install(ArgumentMap arguments)
  {
    if (Flags.GetString ("app_flavor") == "lobby")
    {
      // Configure as a lobby server.
    }
    else if (Flags.GetString ("app_flavor") == "game")
    {
      // Configure as a game server.
    }
  }
}

Tip

When you use a flavor, that flavor’s name is automatically included in its server’s RPC tag. Using this, you can easily import a list of servers with the same flavor. For more details, please see Distribution tagging.

34.2. Game server packaging to move to a production server

iFun Engine provides an easy packaging feature for developed game servers. You can use this feature to avoid the unstable process of copying all sources to copy the game server to the production server.

34.2.1. Available packaging types

You can create package files in the following three forms and set the variables below in the project’s top-level CMakeLists.txt file.

  • TGZ: tar file bundled with gzip. Created when set as set(WANT_TGZ_PACKAGE true). This is useful when you want the game server installed in a particular user’s home directory rather than in the usual OS path of /usr/bin.
  • DEB: Debian package file. Created when set as set(WANT_DEB_PACKAGE true). This is only available in Ubuntu. An execution file is installed according to Ubuntu conventions and a daemon script is also included.
  • RPM: Redhat package file. Created when set as set(WANT_RPM_PACKAGE true). This is only available in CentOS. An execution file is installed according to CentOs conventions and a daemon script is also included.

34.2.2. Adding version numbers to packages

The package file name is created in the format “{{project}}_{{version}}_install.tgz”, and version strings comprise major version strings and code revision IDs extracted from the source repository, as explained below.

34.2.2.1. Major version strings

To update a server package version, modify the contents of the VERSION file specified in Source directory structure and create a package. The server package version is then automatically upgraded.

34.2.2.2. Minor version strings (code revision IDs)

If you want to automatically add the GIT commit ID or SVN revision number as a build number to the version text string in versions other than those that must be updated manually, set the following variables in CMakeLists.txt.

  • GIT: Set set(PACKAGE_WITH_BUILD_NUMBER_FROM_GIT true)` to set the GIT commit ID as a minor version string.

    Tip

    If the source tree is dirty, add the text string ~dirty after the commit ID. This way, it is recognized as having been built in a source tree with uncommitted data.

  • SVN: Set set(PACKAGE_WITH_BUILD_NUMBER_FROM_SVN true)` to set the revision ID extracted from svn info as a minor version string.

    Warning

    If the update command is not run after committing for SVN, svn info returns the revision number before commitment. Run svn update before creating the package to prevent this problem.

34.2.3. Generating packages

34.2.3.1. In a command line

Enter make package in the terminal to create a package file.

34.2.3.2. In CLion

Go to the right target submenu and find the target called package. Double-click it to create the package file.

34.2.3.3. In Visual Studio

Package creation in Visual Studio will be supported later. You need to connect to the Linux server through Putty, etc. to create the package as explained in In a command line above.

34.2.4. Checking package data

34.2.4.1. TGZ

You can check package data as follows with tar ztvf.

$ tar ztvf example_0.0.1_install.tar.gz
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 etc/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 etc/default/
-rw-r--r-- dkmoon/dkmoon    72 2017-05-18 14:23 etc/default/example
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 etc/init/
-rw-r--r-- dkmoon/dkmoon  1304 2017-05-18 14:23 etc/init/example.conf
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/lib/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/lib/example/
drwxrwxr-x dkmoon/dkmoon     0 2017-05-18 14:24 usr/lib/example/default/
-rw-r--r-- dkmoon/dkmoon 5723064 2017-05-18 14:23 usr/lib/example/default/libexample.so
...
-rwxr-xr-x dkmoon/dkmoon    3288 2017-05-18 14:23 usr/bin/example-launcher

34.2.4.2. DEB

You can check package data as follows with the dpkg-deb --contents command.

$ dpkg-deb --contents example_0.0.1_install.deb
drwxrwxr-x root/root         0 2017-05-18 14:24 ./etc/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./etc/default/
-rw-r--r-- root/root        72 2017-05-18 14:23 ./etc/default/example
drwxrwxr-x root/root         0 2017-05-18 14:24 ./etc/init/
-rw-r--r-- root/root      1304 2017-05-18 14:23 ./etc/init/example.conf
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/bin/
-rwxr-xr-x root/root      3288 2017-05-18 14:23 ./usr/bin/example-launcher
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/lib/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/lib/example/
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/lib/example/default/
-rw-r--r-- root/root   5723064 2017-05-18 14:23 ./usr/lib/example/default/libexample.so
drwxrwxr-x root/root         0 2017-05-18 14:24 ./usr/share/
...

34.2.4.3. RPM

You can check package data as follows with the rpm --qpl command.

 $ rpm -qpl example_0.0.1_install.rpm
 /lib/systemd/system/example.service
 /usr/bin/example-launcher
 /usr/lib/example/default/libexample.so
 /usr/share/example/default/DEBIAN
 /usr/share/example/default/LICENSE
 /usr/share/example/default/README
 /usr/share/example/default/VERSION
 /usr/share/example/default/app.yaml
 /usr/share/example/default/manifests/MANIFEST.json
 /usr/share/example/default/resources/.stamp
 /usr/share/example/default/resources/client_data/.stamp
 /usr/share/example/default/resources/client_data/README
 /usr/share/example/default/resources/game_data/.stamp
 /usr/share/example/default/resources/game_data/README
 /usr/share/example/default/resources/json_protocols/.stamp
 /usr/share/example/default/resources/json_protocols/README
 /usr/share/example/default/symbols/libexample.so/62BD5D7D261EC43AFCBABB208919AD480/libexample.so.sym

34.2.5. Including the iFun Engine license file in a package

As explained in Using a license file, when installing account.ilf, it is better to also include it in packages.

When you save account.ilf as etc/ifunfactory/account.ilf in the source directory to create the package file as a DEB or RPM file, account.ilf is also installed.

34.2.6. Including game resource files in a package

As with Content support part 4: Game design data, you may have resource files to reference in order to implement server-side logic.

All resource files must be accessible by the game server during development and live service. Resource files are often copied to a set location and used for this purpose, but this creates problems such as requiring the same user ID or requiring separate resource updates when the game server is updated.

iFun Engine allows game developers to specify particular directories as resource directories to solve these problems. These specified directories are included in game server packages and can be accessed consistently by the game server.

34.2.6.1. Specifying a resource directory

Resource directories are listed in a variable called RESOURCE_DIRS in CMakeLists.txt of the top-level directory.

1
2
3
4
5
...
set(RESOURCE_DIRS game_data)
...

include(Funapi)

34.2.6.2. Accessing resource files in code

Resource files are located in the current source directory during server development and are installed in particular locations depending on the package during service. For this reason, GetResRoot() results must be used as a prefix in source code to access resource files. This feature guarantees access to the same resource files during both development and live service.

For example, in the previous example in which a directory called game_data was set as a resource, it was used as follows to access the file called game_data/my_file1.

1
string path = GetResRoot() + "/game_data/my_file1";

34.3. Distributing on the production server

Please read Server management part 4: Deployment for package distribution and deployment.