Hosting with Gameye
この機能はPhoton Bolt Proバージョンで利用できます。
Gameye は、不可知論的なインフラストラクチャを使用してゲームサーバーを世界中に展開するホスティングサービスです。
Photon Boltは Gameye上の実行に対応しています。このチュートリアルでは、数分でゲームサーバーを開始してデプロイを行います。
Gameyeサービスについて
GameyeサービスはDocker Containersを使用した仮想化を中心に構築されており、各コンテナーはプレイヤーをリッスンするゲームサーバーです。
REST APIを使用してこれらのゲームサーバーを簡単に作成、削除、一覧表示できるため、サーバーのオーケストレーションと自動化を行うのに最適です。
サービス自体の詳細については、公式ウェブサイトhttps://gameye.com/ とドキュメントページhttps://docs.gameye.com/をご覧ください。
ワークフロー
このチュートリアルでは、専用のゲームサーバーを実行し、Photon Bolt Proを使用して直接接続できるようにする方法に焦点を当てます。
次の手順に従います。
- ヘッドレスゲームサーバーを構成します。
Gameyeサービスにサーバーコンテナーをデプロイし、専用サーバーを起動します。- リモートサーバーを検索して接続できるゲームクライアントを構築します。
これらの各ステップには、いくつかのサブステップがあります。次のセクションで説明します。
このスキームを構築するために必要なファイルはすべてオープンソースプロジェクトとして利用できます。
構築するパーツの概要画像:
前提条件
必要なすべてのパーツの作成を始める前に以下のことを確認してください。
- Photon Bolt Proを保持していること。このサンプルは、Proバージョンの直接接続機能で使用することを前提としています。
- 独自の
Application Tokenを受け取り、サービスにアクセスするために、Gameyeのスタッフにお問い合わせください。通話の認証に使用されます。 - DockerとDockerHubがどのように機能するかについての基本的な知識が必要です。
dockerイメージとdockerコンテナーを構成、ビルド、実行、アップロードする方法も理解する必要があります。また、以下を保持している必要があります:DockerHubアカウント(まだお持ちでない場合)。- サーバーイメージをアップロードするリポジトリ。
- 基本的なBoltチュートリアル(
Getting StartedおよびAdvanced Tutorial)を完了してください。 - Unityエディターに
Linux Target Platformをインストールしてください。
ヘッドレスゲームサーバーを構築する
Gameyeで専用サーバーを実行するには、次のソリューションが必要です。(i)ヘッドレスサーバーを実行して接続をリッスンするUnityプロジェクト、(ii)サーバーバイナリをdockerイメージにカプセル化する 。後でアプリケーションをコンテナ化するために使用されます。
Unityプロジェクト
受け取ったSDKパッケージ内に、 samples_proというフォルダーがあります。このフォルダーには、他のサンプルプロジェクトと GameyeIntegrationというフォルダーが含まれています。
ヘッドレスサーバーを実行するために必要なすべてのファイルが含まれています。
次に、ゲームサーバーで使用されるいくつかのコードについて説明します。
Scenesフォルダーには、このサンプルで使用する3つのメインシーン、(i) GameyeHeadlessServer、(ii) GameyeInGame、および(iii) GameyeClientがあります。
ゲームサーバーでは、最初の2つのシーンを使用します。
GameyeHeadlessServerシーンから開始し、 GameyeServerスクリプト(ゲームサーバーを制御するためのメインのエントリポイント)を実行する1つの単純な Game Objectのみを使用します。
このスクリプトはとてもシンプルです。
スクリプトは、BoltLauncher.StartServer(serverPort)を呼び出して GameyeInGameシーンを読み込むことにより、Boltサーバーを起動します。
ただし、注意が必要ないくつかの重要な側面があります。
Startでは、command-line argumentsを解析して、ロードするマップなどの情報を読み込みますが、最も重要なのは、どのポートをバインドするかです。
このような専用サーバーを実行する場合、2つのメインポートを使用します。(i)新しいプレイヤー接続をリッスンするサーバーポート、および(ii)A2Sクエリプロトコルを使用してサーバーからリアルタイム情報を取得するために使用されるクエリポート。
Gameyeでサーバーをホストする場合、Igniter(github)というツールを使用します。
このツールは、ゲームサーバーの現在の状態を追跡し、サービスマネージャーに報告します。
Igniterと通信するには、いくつかの特定の文字列をstdoutストリームに出力する必要があります(次のセクションでこれらのメッセージについて詳しく説明します)。そのために、それらのキー文字列を記録するGameyeIgniterApiを作成しました。
たとえば、 starting、playing、または exitingなどの状態を公開するために、GameyeServerスクリプトによって使用されます。
GameyeServerスクリプトのもう1つの重要な側面は、A2SManagerクラスの使用です。
このマネージャーは、サーバーに関する内部メタデータを更新します。
この情報は、後でクライアントがサーバー構成をチェックするために使用します。
また、例として、このスクリプトは、セッションに接続しているプレーヤーがいない場合にゲームサーバーを自動的にシャットダウンします。
そのため、ゲームサーバーを起動し、プレイヤーが参加するのを待って、必要なだけプレイできるようにします。最後のプレイヤーが切断すると、自動的にシャットダウンします。
そのため、ゲームサーバーを起動し、プレイヤーが参加するのを待って、必要なだけプレイできるようにします。最後のプレイヤーが切断すると、自動的にシャットダウンします。
GameyeInGameシーンについては、現時点では単なるプレースホルダーであり、実際のコンテンツやゲームプレイはありません。サーバーとクライアントが別のシーンをプレイできるようにするためだけに使用します。
サーバーで発生することへの説明は以上です。ビルドしてみましょう。
Build Settingsウィンドウを開き、インデックス0にGameyeHeadlessServerを、インデックス1にGameyeInGameシーンを含めます。- Bolt(
Bolt / Compile Assembly)を再コンパイルして、シーンの構成を認識できるようにしてください。 Architecture``x86を使用して、Target PlatformをLinuxに変更します。- ゲームをビルドします。ここではこの名前を使用するため、バイナリには
game.x86という名前を付けることをお勧めします。
ゲームサーバーのDockerイメージを構築する
Gameyeサービスの主な特徴の1つは、ゲームの実行可能ファイルの構築方法に依存しないことです。 Docker Imageへの参照が必要なだけで、必要な数のサーバーをスピンできます。
ただし、この imageにはいくつかの設定が必要であり、前述したIgniterツールを使用する必要があります。
Igniterはゲームを実行(点火)し、実行可能ファイルを制御します。
これをできるだけスムーズにするために、わずか数ステップでDocker Imageを構築するために使用できるテンプレートを構築しました。
https://github.com/BoltEngine/gameye_bolt_server_imageにあるプロジェクトのクローンを作成してください。
リポジトリにはすでにイメージの構築方法の説明が含まれていますが、ここで要約します。
- リポジトリをマシンにダウンロードします。
- Game Serverバイナリをビルドします(これは最後のステップで行いました)。
- サーバーファイルを
buildフォルダー、実行可能ファイル、データフォルダーにコピーします。 実行可能ファイルの名前はgame.x86に設定しました。 Makefileファイルを開き、変数DOCKER_USERNAME(DockerHubユーザー名)とGAME_IMAGE_NAME(DockerHubリポジトリ名)を変更します。- フォルダーで
makeを実行してイメージをビルドします。
これで、アップロード用のDocker Imageが設定されました。
この画像と Gameyeサービスを使用するときに注意する必要がある設定について説明します。
Docker側から始めます。ルートフォルダーに Dockerfileがあります。
この構成ファイルは、イメージの構築方法を説明しています。主な点は次のとおりです。
- 画像は
ubuntu:latestに基づいています。そのため、UnityプロジェクトをLinux実行可能ファイルとしてビルドしました。 これは、Gameyeでゲームを実行するための推奨OSです。 - それはいくつかの環境変数を定義します。それらはビルド中に特定のフォルダーにいくつかのファイルを割り当てるために使用されます。たとえば、ゲームのバイナリを
GE_DIRGAMEに入れます。README.mdファイルはそれらすべての変数を記述します。 - 最後に、画像が
docker-entrypoint.shをENTRYPOINTとして実行する必要があることをDockerに通知します。このファイルは特定のパラメーターを指定して、Igniter-shell(Igniterツールから実行可能)を実行するだけです。使用方法については、公式ページをご覧ください。
では、 Gameye関連のファイルについて説明します。
サービスドキュメントで説明した通り、2つの構成ファイル、(i) args.yamlおよび(ii)config.yamlが必要です。
ゲームサーバーがオーケストレーションシステムと連携するためには、これらのファイルにいくつかの詳細な値が必要です。
今回のケースでは、args.yamlファイルはarg/main.yamlにあり、外部と通信するためにサーバーに開く必要があるすべての必要なポートを登録します。
ご覧のとおり、(i) server(ゲームサーバーポート)、(ii)query( A2Sクエリ用)、(iii)すべてのPhoton関連ポート(マッチメイキングとしてPhotonを使用する予定の場合)。
このファイルを、以前に連絡した のGameyeアカウントマネージャーに送信して設定してもらいます。
同様に、 config/main.yamlファイルにあるconfig.yamlファイルがあります。
argsファイルとconfigファイルは同じ名前(この場合は main.yaml)を使用する必要があるため、これらは独自のディレクトリにあります。
設定ファイルはもう少し広範です:
cmd:ここでは、サーバーに送信されるコマンドライン引数について説明します。 したがって、ヘッドレスモードでゲームを開始し(-batchmode -nographics -logFile)、必要なポート情報を引数として渡します(-port ${port.server} -query ${port.query})。Igniterは、動的な値を適切な値に置き換えます。script:このセクションでは、ゲームサーバーが実行できるすべての状態と遷移について説明します。前に説明したキー文字列を構成します。ご覧のように、Igniterはplaying状態に変更するときにGAMEYE STATE CHANGE PLAYなどのいくつかの値を期待します。すべてのパラメータはGameyeページに文書化されています。defaults:最後に、引数にいくつかのデフォルト値を設定します。
テンプレートの動作の基本は以上です。必要な変更を加える準備が整いました。
Docker Imageをアップロードする前に、Dockerリポジトリへの Gameyeアクセスをセットアップし、プッシュWebhookを設定して、バイナリの新しいバージョンをいつアップロードするかをサービスが認識できるようにする必要があります。
詳細は、 Gameye ドキュメントページで説明しています。Sending a build notificationおよび Image Permissionsセクションを探してください。
Gameyeアカウントマネージャーが手助けをしてくれます。
準備がすべて整ったので、 make uploadコマンドを実行して画像をDockerHubにアップロードするか、 docker push username/image_name:versionを使用して手動で実行します。
ほんの数分で、使用できるようになります。
サーバーの展開を確認する
デプロイが成功したことを確認する簡単な方法の1つは、 Gameye REST APIを使用して新しいサーバーをリクエストし、そこにあるかどうかを確認することです。
REST APIに関するドキュメントは、このリンクにあります。
次に、 Gameye Application Tokenを使用します。この情報は、Gameyeスタッフから送信されました。
すべての{key}を「トークン」の文字列に置き換えます。
最初に、次のコマンドを実行して、既に実行されているサーバー(存在するべきではありません)があるかどうかを確認する必要があります。
bash
curl --request GET \
--url https://api.gameye.com/fetch/match \
--header 'authorization: Bearer {key}'
実行中のサーバーがないことを示す、以下のような応答が得られます。
JSON
{
"match": {}
}
ゲームサーバーをリクエストするために、次のように、別のAPIエンドポイントを使用します。
bash
curl --request POST \
--url https://api.gameye.com/action/start-match \
--header 'authorization: Bearer {key}' \
--header 'content-type: application/json' \
--data '{"locationKeys":["{locationKeys}"],"matchKey":"{name}","gameKey":"{gameKey}","templateKey":"{templateKey}","endCallbackUrl":"{endCallbackUrl}"}'
この呼び出しに関する備考:
locationKeys: 利用可能なリージョンのリストはこちらです。matchKey: 新しいリクエストを行うたびに一意のIDである必要があります。 重複したキーを使用すると、サーバーが存在しなくてもエラーが発生します。gameKey: このキーは起動するサーバーを表し、Gameyeのスタッフによって修正および設計されています。 また、使用するキーも通知されます。templateKey: テンプレートの値は、args.yamlとconfig.yamlに使用したファイルの名前と一致している必要があります。 このサンプルでは、これらのファイルの名前としてmain.yamlを使用しているため、この引数に文字列"main"を渡す必要があります。endCallbackUrl:これはマッチが終了したときに呼び出されるWebhookです。 サーバーからいくつかの統計を取得するのに役立ちます。
適切なパラメータでリクエストを行うと、次のような結果が得られます。
JSON
{
"id": "bfc5890f-9ba2-46ef-bb69-31ac5cf6a092",
"image": "boltgameimage",
"location": "washington_dc",
"host": "123.456.789.000",
"created": 1590002692454,
"port": {
"server": 53723,
"query": 51642,
"masterServer1": 55488,
"masterServer2": 49784,
"gameServer1": 62047,
"gameServer2": 50203,
"nameServer1": 57337,
"nameServer2": 61128
}
}
新しいゲームサーバーが正常に展開され、一部のプレイヤーの準備が整ったことを示しています。
ご覧のとおり、 args.yamlファイルで尋ねたように、パブリックIPとリスニングポートに関する情報があります。
これでこのサーバーをシャットダウンできます。
次の呼び出しを使用して、 Gameyeにセッションの停止を要求します。
bash
curl --request POST \
--url https://api.gameye.com/action/stop-match \
--header 'authorization: Bearer {key}' \
--header 'content-type: application/json' \
--data '{"matchKey":"example-match"}'
ご覧のとおり、どのセッションが強制終了されるかを通知するためには matchKeyのみを使用します。
このリクエストに対する返信はありません。
ゲームクライアントの詳細
サーバーが機能するようになったので、サーバーに接続するクライアントが必要です。
このセクションでは、私たちが構築したクライアントサンプルについて説明します。そこから始めて、ニーズに合わせて拡張できます。
前に述べたように、 samples_pro内の GameyeIntegrationフォルダーを再度確認すると、 GameyeClientシーンが見つかります。
これがプレイヤーの出発点になります。
要約すると、プレイヤーは単純化されたロビーシーンを利用します。ロビーシーンでは、利用可能なすべてのゲームサーバーを表示できますが、REST APIを使用して行ったように、サーバーが見つからない場合は新しいサーバーをリクエストできます。
プレイヤーのUIは非常にシンプルで、2つの主要な部分で構成されています。(i)Request New ServerボタンのあるNo Server Foundパネルと、(ii)サーバーのリストを表示するロビーリストです。
これは、 GameyeUIManagerクラスによって管理され、イベントを使用してサーバーリクエストをトリガーし(クラスのrequestServerEvtアクションを参照)、サービスから取得したデータをサーバーのリストに入力します(詳細は次を参照)。
また、 GameyeUIServerInfoManagerクラスがあります。これはサーバーリストのアイテムを表し、UIコンテンツを取り込み、Joinボタンのクリックに応答します。
ゲームクライアントのコアセクションは次のクラスです。
GameyeApi
ここでは、 Gameyeのドキュメントに記載されているREST APIに基づいたシンプルなHTTPクライアントを実装しました。
APIを使用する場合は両方のタイプが必要なので、GETとPOSTリクエストを実行できます。
このサンプルでは、次のメソッドで表される2種類のリクエストのみを使用します。
RequestServer: この関数を呼び出すことにより、Gameyeにいくつかの事前定義された値で新しいゲームサーバーを起動するように要求します。この操作の結果は、引数として渡されたアクションコールバックで受信されます。GetSessionList: このメソッドは、有効なゲームサーバーの現在のリストを要求し、それらの情報をマネージ形式に解析します。これのクラス定義は、GameyeData.csファイルにあります。
GameyeClientManager
これは、プレイヤー管理の中心的なクラスであり、すでに説明されている他のすべてのパーツを統合し、それらを連携させる役割を果たします。
このクラスは、次のタスクを実行できます。
- APIを使用して
Gameyeサービスから情報をリクエストし、処理されたデータをUIに入力して、有効なサーバーのリストを更新します。これは、refreshInterval値(UpdateSessionsメソッド)に基づいて定期的に発生します。 - UI入力に基づいて新しいゲームサーバーの作成をリクエストします(
RequestServerメソッド)。 - Boltクライアントを起動し、リモートゲームサーバーに接続します(
JoinSessionメソッド)。
すべてのメソッドの詳細はドキュメント化されています。
ゲームクライアントを実行する
可動部分がどのように連携するかについての理解が深まったところで、専用サーバーに接続するようにクライアントを構成してみましょう。
Unityクライアントは、サーバーと同様、2つのシーンで構成されています。(i) GameyeClientは前のセクションで説明したメニューシーンです (ii) GameyeInGameは同じゲーム内シーンであり、単なるプレースホルダーです。
次の手順に従ってゲームクライアントを実行します。
GameyeClientシーンを開きます。 シーンにGameyeClientという名前のゲームオブジェクトが表示されます。インスペクターで開きます。 これにはGameyeClientManagerコンポーネントがあり、Gameye Application Tokenを設定する必要があります。プレハブの変更を適用してシーンを保存できます。Build Settingsウィンドウを開き、インデックス0のGameyeClientとインデックス1のGameyeInGameでシーンリストを設定します。- Bolt(
Bolt/Compile Assembly)を再コンパイルして、シーンの構成を認識できるようにしてください。 - これからは、エディターでクライアントを実行するか、スタンドアロンバージョンをビルドできます。
クライアントが実行されている状態で、Request New Serverボタンがデフォルトで30 secs無効になっていることがわかります。
これは、新しいサーバーをリクエストする前に、実行中のサーバーがないことを確認するためです。
サーバーのリストはデフォルトで20 secsごとに更新されます。"Refresh Interval"スライダーを動かすことでこれを変更できます。
Gameyeには1分あたりのAPIリクエストの制限があるため、妥当な値にしておくことをお勧めします。
サーバーが利用できない場合は、リクエストボタンをクリックするだけで、非同期リクエストが実行されます。
すべてが順調に進んでいると、コンソールログにJSON応答が表示され、数秒以内に(別の更新更新後)、セッションがロビーリストにポップアップ表示されます。
サーバー名、現在読み込まれているマップ、プレイヤーの数/プレイヤーの最大数、作成時間などの一部のサーバー情報が表示されます。
すべての追加情報は、 A2Sサーバークエリ APIを通じて利用できます。
このサーバーに接続するには、Joinボタンをクリックするだけです。
クライアントが接続し、ゲーム内シーンを読み込みます。
そこから、サンプルコードの基本的な機能を拡張して、セッションをフィルタリングしたり、サーバーに関する詳細情報を表示したり、特定のゲームサーバータイプを要求したりすることができます(これは、名前や値が異なる複数の config.yamlファイルを使用して行われます。 また、サーザーを要求する際に正しい templateKeyを使用します)。