UE4のDedicated ServerをAmazon GameLiftにデプロイしてみる

Dedicated Serverをホストする環境としてAmazon GameLiftを試してみたので内容をメモしておきます。
GameLiftについては[Black Beltの資料](https://aws.amazon.com/jp/blogs/news/webinar-bb-amazon-gamelift-2019/)がわかりやすかったです。

# 試した環境

* UE4.24.3 Win64ビルド
* GameLift_09_03_2019
 * GameLift-Cpp-ServerSDK-3.4.0
 * GameLift-Unreal-plugin-3.3.0
* [UE4でDedicated Serverを試す - Qiita](https://qiita.com/mechamogera/items/0b8719184bd088a165d0)で作成したThirdPersonのDedicated Serverを利用

# GameLift Server SDKをプロジェクトに組み込む

基本的には[Amazon GameLift を Unreal Engine ゲームサーバープロジェクトに追加 - Amazon GameLift](https://docs.aws.amazon.com/ja_jp/gamelift/latest/developerguide/integration-engines-setup-unreal.html)の手順に従ってServer SDKをプロジェクトに組み込む。
大まかな手順はこちら。

1. GameLift Server SDKをダウンロード
2. C++サーバーSDKライブラリ for Unrealをビルド
3. ビルドしたバイナリをGameLiftプラグインファイルに追加
4. GameLiftプラグインファイルを4.24.3用に修正
5. GameLift プラグインをプロジェクトにインポート

## GameLift-Unreal-plugin-3.3.0のUE4.21.1をUE4.24.3用に修正

GameLiftのUnreal Pluginは以下のように修正する必要があった。

```cpp:Plugins/GameLiftServerSDK/Source/GameLiftServerSDK/Private/GameLiftServerSDK.cpp
@@ -13,8 +13,8 @@
 */
 #include "GameLiftServerSDKPrivatePCH.h"
 #include "Core.h"
-#include "ModuleManager.h"
-#include "IPluginManager.h"
+#include "Modules/ModuleManager.h"
+#include "Interfaces/IPluginManager.h"

 #define LOCTEXT_NAMESPACE "FGameLiftServerSDKModule"
```

```cpp:Plugins/GameLiftServerSDK/Source/GameLiftServerSDK/Public/GameLiftServerSDK.h
@@ -14,11 +14,11 @@
 #pragma once


-#include "ModuleManager.h"
-#include "DelegateCombinations.h"
+#include "Modules/ModuleManager.h"
+#include "Delegates/DelegateCombinations.h"

 #if PLATFORM_WINDOWS
-#include "AllowWindowsPlatformTypes.h"
+#include "Windows/AllowWindowsPlatformTypes.h"
 #endif

 #include "aws/gamelift/common/Outcome.h"
@@ -27,7 +27,7 @@
 #include <map>

 #if PLATFORM_WINDOWS
-#include "HideWindowsPlatformTypes.h"
+#include "Windows/HideWindowsPlatformTypes.h"
 #endif

 DECLARE_DELEGATE_OneParam(FOnStartGameSession, Aws::GameLift::Server::Model::GameSession);
```

## Unreal Engine ゲームサーバーを初期化での設定

以下のGameModeでの設定はWebSocketNetworkPluginで指定したポートを設定

```cpp
    params->port = 7777;
```

## ToDo

* サーバー側でGameLift Server SDKを通して以下の場合に関数を呼び出すのが必要そう([BlackBeltスライド23ページ](https://www.slideshare.net/AmazonWebServicesJapan/20191002-aws-black-belt-online-seminar-amazon-gamelift/23)、[BlackBeltスライド24ページ](https://www.slideshare.net/AmazonWebServicesJapan/20191002-aws-black-belt-online-seminar-amazon-gamelift/24)参照)。
 * プレイヤー参加時：AcceptPlayerSession
 * プレイヤー離脱時:RemovePlayerSession
 * セッション終了時：TerminateGameSession
 * サーバープロセス終了時：ProcessEnding
* クライアント側ではAWS SDKを利用してのセッションの処理が必要そう([ゲームエンジンと Amazon GameLift - Amazon GameLift](https://docs.aws.amazon.com/ja_jp/gamelift/latest/developerguide/integration-engines.html)あたり参照)。

# Dedicated ServerをGameLiftで起動する

## アップロードのための前準備

### UE4の依存パッケージインストール用のバッチファイル設置

素のWindowsでUE4プロジェクトのビルド結果を動かそうとするとC++ runtimeやDirectXが入っていないため以下のエラーが発生して起動できない。

```
The program can't start because XINPUT1_3.dll is missing from your computer. Try reinstalling the program to fix this problem.
```

このため以下の参照リンク先のようにC++ runtimeやDirect Xをインストールする必要がある。
[Fleet can't start UE4 Dedicated Server - Amazon GameLift / Amazon GameLift Discussion - Amazon Lumberyard Game Dev Community](https://forums.awsgametech.com/t/fleet-cant-start-ue4-dedicated-server/2843/2)

1. [リンク先](https://www.microsoft.com/en-us/download/details.aspx?id=35)からdxwebsetup.exeを取得する。
2. [リンク先](https://www.microsoft.com/en-us/download/details.aspx?id=48145)からvc_redist.x64.exeを取得する。
3. 上記のexeをビルド結果のWindowsNoEditor直下に配置する。
4. 以下のようなinstall.batをビルド結果のWindowsNoEditor直下に配置する。

```
vc_redist.x64.exe /q
dxwebsetup.exe /q
```

### GameLiftServer SDKのdllを配置する

GameLiftServerSDK.Build.csではTarget.Type == TargetRules.TargetType.Serverの場合のみPublicDelayLoadDLLsやRuntimeDependenciesの設定を行っている。
このため[UE4でDedicated Serverを試す - Qiita](https://qiita.com/mechamogera/items/0b8719184bd088a165d0)のようにEditorでビルドしてVSでサーバー用のBinaryをビルド配置しているとGameLiftServer用のdllをビルドしたパッケージに含まれず以下のようなエラーとなる。

```text
[2020.05.12-04.37.36:718][  0]LogWindows: Failed to load '../../../WebSocketTest/Plugins/GameLiftServerSDK/ThirdParty/GameLiftServerSDK/Win64/aws-cpp-sdk-gameli
ft-server.dll' (GetLastError=126)
[2020.05.12-04.37.36:719][  0]LogWindows: File '../../../WebSocketTest/Plugins/GameLiftServerSDK/ThirdParty/GameLiftServerSDK/Win64/aws-cpp-sdk-gamelift-server.
dll' does not exist
```

このため、ビルド結果のWindowsNoEditor\\[プロジェクト名]\Plugins\GameLiftServerSDK\ThirdParty\GameLiftServerSDK\Win64にaws-cpp-sdk-gamelift-server.dllを配置する。
（無理やり配置したけどどうするのが正解？）

## GameLiftへのアップロードと接続確認

### アップロードしてビルド作成

以下のような感じでアップロードしてビルド作成

```
aws gamelift upload-build --name WebSocketTestServer --build-version 0.01 --build-root ./WindowsNoEditor --operating-system WINDOWS_2012 --region ap-northeast-1
```

### ビルドからフリート作成

AWSのマネージメントコンソールからアップロードしたビルドを確認してフリートを作成

プロセス管理では以下のように設定

起動パス：[プロジェクト名]\Binaries\Win64\[プロジェクト名]Server.exe
※ [UE4でDedicated Serverを試す - Qiita](https://qiita.com/mechamogera/items/0b8719184bd088a165d0)のスタンドアロン実行参照
起動パラメータ：-log

EC2ポート設定では以下のように設定

ポート範囲：[WebSocketNetworkPluginで指定したポート番号]
プロトコル：TCP
IPアドレス範囲：0.0.0.0/0
※ [UE4でDedicated Serverを試す - Qiita](https://qiita.com/mechamogera/items/0b8719184bd088a165d0)参照

フリートを作成したらアクティベートされるのを待つ。

### 接続してみる

以下のようにするとフリートに配置されたインスタンスのIPがとれるので[UE4でDedicated Serverを試す - Qiita](https://qiita.com/mechamogera/items/0b8719184bd088a165d0)のクライアントを起動してIPを指定して接続するとマルチプレイできた。
（本来はGameLiftのセッションと連携する必要があるがひとまず接続確認）

```bash
$ aws gamelift list-fleets
$ aws gamelift describe-instances --fleet-id [fleetid]
```

## Todo

ちゃんと運用するならエイリアスかキュー作ったりオートスケーリングのやり方を決めたりと構成を考える必要がある。