35. 服务器管理Part 3: 服务器打包

35.1. Flavor: 按不同作用来区分服务器

根据情况的不同,有时须要按照不同的作用来设置服务器。 对于iFun引擎,可以这种目的来指定服务器的Flaver。

35.1.1. 什么是Flavor?

Flavor表示虽然共享source code,但却负责不同作用的服务器类型。 例如,即使使用同一source code,类型也有可能不同,如lobby服务器和game服务器。iFun引擎中将它们分成lobby flavor和game flavor。

35.1.2. 设置Flavor

如果想要区分lobby类型的游戏服务器和game type的游戏服务器,在最上级的CMakeLists.txt中,按如下所示指定flavor。

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

Note

flavor 지정 시, default 는 엔진 내부에서 예약어(reserved keyword)로 사용하기 때문에 default 이외의 다른 이름을 사용해야 합니다.

35.1.3. 各Flavor自动生成的文件

待这样设置并构建好之后,iFun引擎会自动生成如下所示文件。

35.1.3.1. MANIFEST.json

复制所包含的默认 src/MANIFEST.json ,在source directory上创建 src/MANIFEST.lobby.jsonsrc/MANIFEST.game.json 。现在适当修改各flavor的MANIFEST.json。

35.1.3.2. Launcher script

在Build directory中创建各flavor的launcher script。上述示例中创建了以 .lobby-local.lobby-launcher.game-localgame-launcher 结尾的脚本。

35.1.3.3. Daemon script

CMakeLists.txt 中通过 set(WANT_SYSTEMD true)set(WANT_UPSTART true) 设置时,也同时生成用于通过daemon运行游戏服务器的script文件。此时,各个flavor专用文件和在MANIFEST.json中一样,复制默认包含的文件,并进行创建。

  • set(WANT_SYSTEMD true)时:

    • 在source directory的etc/systemd/目录下,以 .chat.service.lobby.service 等形式生成文件。

  • set(WANT_UPSTART true)时:

    • 在source directory的etc/upstart/default/目录下,生成 .chat , .lobby 等文件。

    • 在source directory的etc/upstart/init/目录下,生成 .chat.conf , .lobby.conf 等文件。

Note

这样生成的文件在 make installmake package 时,会同时包含进去,从而进行安装或发布。

35.1.4. 在代码中查看当前flavor

为了对各flavor的服务器动作进行不同处理,须要在代码中查看当前服务器的flavor。 此时,使用名为 app_flavor 的Google flag。下面是使用示例。

 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

如果使用Flavor,那么相关服务器的RPC标签中会自动包含该flavor名称。据此可轻松调取同一flavor的服务器列表。具体内容请参考 用标签来区分分布式服务器

35.2. 用于发布到实际执行服务器中的游戏服务器packaging

iFun引擎提供了可轻松对已开发的游戏服务器进行打包的功能。使用该功能,可以避免为了将游戏服务器 复制到实际服务器而复制所有代码的不安全的行为。

35.2.1. 可创建的包类型

包文件可通过以下3种格式创建,分别在项目最上级的CMakeLists.txt文件中设置如下变量即可。

  • TGZ: 通过gzi打包的tar文件。设置为 set(WANT_TGZ_PACKAGE true) ,即可创建。在不将游戏服务器安装到/usr/bin等OS的常规路径下,而是安装到特定用户的home directory时所使用。

  • DEB: Debian package文件。设置为 set(WANT_DEB_PACKAGE true) ,即可创建。仅在Ubuntu中有效。根据Ubuntu的convention来安装执行文件,并同时包含daemon script。

  • RPM: Redhat package文件。设置为 set(WANT_RPM_PACKAGE true) ,即可创建。仅在CentOS中有效。按照CentOs的convention来安装执行文件,并同时还包含daemon script。

35.2.2. 为已创建的包赋予版本号

包的文件名以 “{{project}}_{{version}}_install.tgz” 的形式生成,version string则按如下所示说明,由在major version string和source储存库中提取的code revision ID组成。

35.2.2.1. Major版本号

为了提高服务器包的版本,可修改 Source 디렉터리 구조 中记述的 VERSION 文件内容并创建包,即可自动提高服务器包的版本。

35.2.2.2. Minor版本号(code revision ID)

如果除了须要手动更新的VERSION以外,还想要 自动 添加GIT的commit id或SVN的revision number到版本字符串中作为Build编号,只需在最上级的CMakeLists.txt文件中设置如下变量即可。

  • GIT: 设置成 set(PACKAGE_WITH_BUILD_NUMBER_FROM_GIT true)` ,即可将GIT commit ID设置为minor version string。

    Tip

    若source tree为dirty状态,在commit id后面添加 ~dirty 字符串。由此可知,是在有仍未commit的内容的source tree中所构建的。

  • SVN: 设置成 set(PACKAGE_WITH_BUILD_NUMBER_FROM_SVN true)` ,即可将 svn info 中提取的reversion ID设置为minor version string。

    Warning

    svn如在commit后未执行update命令, svn info 将返回commit之前的revision号。为了避免该问题,请在创建包之前执行 svn update

35.2.3. 包的创建方法

35.2.3.1. 在命令行中操作时

在终端内输入 make package ,即可创建包文件。

35.2.3.2. 通过CLion操作时

选择右侧 target 的子菜单,即可选择名为 package 的target。双击,即可创建包文件。

35.2.3.3. 通过Visual Studio操作时

在Visual Studio中创建包的功能计划后续提供。您须要通过Putty等软件访问Linux服务器,通过上面 在命令行中操作时 中介绍的方式创建。

35.2.4. 查看包的内容

35.2.4.1. TGZ

可通过 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

35.2.4.2. DEB

可通过 dpkg-deb --contents 命令查看包的内容,如下所示。

$ 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/
...

35.2.4.3. RPM

可通过 rpm --qpl 命令查看包的内容,如下所示。

 $ 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/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

35.2.5. 将iFun引擎许可证文件包含在package中

当已按照 应用许可证文件 中介绍的方法安装好 account.ilf 进行使用时,最好在package中也包含该文件。

如果已通过source directory中的 etc/ifunfactory/account.ilf 保存了 account.ilf ,那么在通过DEB或RPM 创建包时, account.ilf 也会被同时安装。

35.2.6. 将游戏资源文件包含在package中

内容支持Part4: 策划数据 这种情况,有时可能存在为了实现服务器端逻辑而需要参考的资源文件。

这种资源文件,须要在开发时及在实际服务运行时,可在游戏服务器中均能够被访问到。 为此,大多情况下会将资源文件复制到固定位置进行使用,但这会引起须要和用户ID保持一致,或在更新游戏服务器时须要单独更新资源等诸多问题。

iFun引擎为了解决这些问题,使游戏开发人员可以将特定目录指定为资源目录。 这样已指定好的目录在对游戏服务器进行打包时,会同时包含到包中,并在游戏服务器上也能通过一贯的方法访问文件。

35.2.6.1. 指定资源目录

在最上级目录的 CMakeLists.txtRESOURCE_DIRS 变量中列出资源目录。

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

include(Funapi)

35.2.6.2. 在代码中访问资源文件

资源文件在开发服务器时,会位于当前的源目录中,而在服务中时,则根据包的不同,将安装在特定位置。 因此,为了访问资源文件,源代码中须要将 GetResRoot() 函数的结果值作为prefix来使用。该函数确保了无论游戏服务器是处于开发中还是处于服务中,均能访问资源文件。

例如,上面的示例中,已将名为 game_data 目录指定为资源,而为了访问 game_data/my_file1 ,按如下所示进行使用。

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

35.3. 作为实际执行服务发布

与包的发布和安装有关的内容请参考 服务器管理Part 4: 发布服务器