65.9K Views
December 21, 23
スライド概要
EOS Deep Dive 2023 では、サンドロット様より地球防衛軍6における Epic Online Services の導入及び実装事例について紹介いただきました。
本ドキュメントは実際に講演で使用した資料を配布用に編集したものです。
Unreal Engineを開発・提供しているエピック ゲームズ ジャパンによる公式アカウントです。 勉強会や配信などで行った講演資料を公開しています。 公式サイトはこちら https://www.unrealengine.com/ja/
『地球防衛軍6』における EOS導入と実装事例 株式会社サンドロット 『地球防衛軍6』におけるEOS導入と実装事例をはじめさせていただきます 1
話者紹介 • 堀内 康寛 • 株式会社サンドロット • エンジニア • 話者 / 質疑応答 • 野口 俊雄 • 株式会社サンドロット • ディレクター・チーフエンジニア • 質疑応答 まず、簡単に自己紹介をさせていただきます、 私は株式会社サンドロットの堀内と申します 本作、地球防衛軍6では他の業務と兼業する形で オンライン機能の開発に従事しました 本日は私の上司で 地球防衛軍のディレクター兼チーフエンジニアを務めます 野口も登壇させていただいております 本日はよろしくお願いいたします 2
当セッションで得られる知見 • 独自フレームワークへのEOS導入コスト • どのような機能を利用して実装を行っているのか 本セッションは アンリアルエンジンなどをもちいない 独自フレームワーク環境へEOSを導入した事例となっております 導入で発生したコスト またEOSのどのような機能を利用して 仕様を実現しているのか といった内容を取り扱っております 当スライドは後日共有される予定となっております 3
ゲーム内容紹介 地球防衛軍6とは オンライン協力プレイ 本題に入る前にざっくりとですが、 地球防衛軍6とはどういったゲームなのかを紹介させて頂きます 4
地球防衛軍6とは • 2022年8月発売 • PS4 / PS5 • 2024年春頃発売予定 • Epic Games Store / Steam • ステージクリア型TPS • 累計販売本数39万 • オフライン2人画面分割プレイ • オンライン4人協力プレイ 地球防衛軍6は昨年夏に発売された ステージクリアタイプのサードパーソンシューティングゲームです 現時点で40万本弱、販売されており オンライン4人協力プレイに対応 PS4/PS5版でのクロスプレイもサポートしておりますが こちらはEOSによって実現されております。 5
オンライン協力プレイ • 多人数で協力して攻略するモード • プレイするには • 他ロビーに参加する • 自分でロビーを作成 • 自動マッチングは非対応 本作のオンライン協力プレイモードは シングルプレイモードと同等のステージを ネットワークを利用し複数人で協力して攻略していくモードとなっております オンラインモードをプレイするには ロビーを作成し参加者を集めるか ロビー画面から自分の参加したいロビーへ参加する必要があります 昨今では自動的にこれらを行う 自動マッチング形式のゲームも、多くなっておりますが ゲームの性質上プレイヤースキルキャラクターの育成度の影響が大きく 数値化を行いマッチングを自動的に行うだけでは プレイアビリティが損なわれるとの判断で どこへ参加するかの判断を明瞭に行える マニュアル方式のロビー実装となっております 6
本日の予定 • 利用した機能 • 導入した経緯、導入までの期間 • 実装について • まとめ 改めまして、本日の予定ですが こちらの内容となっております EOSのどの機能を利用しているのか どのような環境へ導入したのか 導入にはどの程度の期間がかかったのか そしてどのような機能として実装したのか 最後に使用してどのように感じたのか といったこともお伝えできればと考えております 7
利用した機能について 地球防衛軍6で利用したEOSの機能 最初の内容は本作で利用した、EOSの機能についてになります 8
EOSの機能 Achievements Interface KWS Interface ProgressionSnapshot Interface Leaderboards Interface Reports Interface AntiCheatClient Interface AntiCheatServer Interface RTC Interface Lobby Interface Auth Interface Sanctions Interface Metrics Interface Connect Interface Sessions Interface Mods Interface Stats Interface CustomInvites Interface P2P Interface TitleStorage Interface Ecom Interface PlayerDataStorage Interface UI Interface Presence Interface UserInfo Interface Friends Interface IntegratedPlatform Interface EOSには多種多様な機能が実装されています アンチチート、招待、情報収集、オンラインストレージ 他にもたくさんの機能が実装されています ドキュメントから抜粋し、リストにしてみたのですが スライドに載せてしまうと 字が小さくなりすぎて見えなくなるほど沢山あります 9
実際に利用したEOSの機能 Auth Interface Connect Interface Lobby Interface P2P Interface そんな中で、本作ではこちらの機能を利用させて頂いております 認証、接続、ロビー、ピアツーピア、こちらの機能になります 防衛軍と同様のものを作る場合 こちらの機能が利用可能ならば実装可能となっております PC版ですと招待処理なども利用するため もう少し必要になるのですが コンシューマ版ではこれら機能のみの利用となっております 10
講演で触れる機能 Auth Interface Connect Interface Lobby Interface P2P Interface 本日はこれら機能の中から ロビー機能の実装、ピアツーピアの状況についてお伝え出来ればと考えております 11
運用状況紹介 リリース時の同時接続者数 続きまして、運用状況について 同時接続数の情報となります 12
リリース直後の同時接続者数 • 発売直後の土曜夜がピーク • 10万弱の同時接続 • 発売週の販売本数30万 • 購入者3割程度の同接数 • トラブルなし スライドにあります、スクリーンショットは EOSの管理画面で利用できる機能で 本作の発売日直後の 同時接続数を 取り出したグラフになっております 発売後、接続数は急激に上昇し約6万強 その後、週末に向け上昇し ピーク値は10万弱程度まで届きました この接続数は開発の予測よりも かなり多かったのですが 余裕をもって捌いていただけたようで サーバー側でのトラブルなどは 特に発生しなかったようです フォートナイトを稼働させているサーバーと聞き及んでおりますが この程度ではビクともしない感じでしょうか 13
導入 どのような環境に導入したのか どのような経緯で導入されたのか どの程度で実装ができたのか 続きまして、導入についてになります 14
前作地球防衛軍5の環境 • 独自フレームワーク+ミドルウエア • • • • • PC/PS4環境 物理演算、AI、音声のミドルウエア プラットフォームネットワークライブラリ 通信は独自ReliableUDPを実装 多くは旧作から引き継ぎ利用 前作、地球防衛軍5は 独自フレームワークをPC/PS4上に構築し それに加え物理演算、AI、音声を扱うミドルウエアを追加した環境となっておりました オンライン開発は各種プラットフォームに用意された ネットワークライブラリをそのまま利用させていただくような実装を行っておりました 各プラットフォームのユーディーピー上に 独自のリライアブルユーディーピー通信環境を構築しております この独自通信部分を含めたプログラム群は 地球防衛軍4以前から補修と再利用を繰り返しているもので 10年を越えた現在ではかなりの骨董品となってきております 15
地球防衛軍6の開発開始 • まずはPS4版を そして、本作についての話になるのですが おおもとの予定ではPS4版を出しましょう という流れになっておりました オンラインモード用のプログラムは 地球防衛軍5から大半が流用される予定で 通信部分に限定すれば、かなり楽な作業になる予定です 16
問題発生 PS5が発売されるらしいね! 時代は縦マルチだよね! クロスマッチ対応 問題発生 そして、開発が進むにつれ PS5というものが発売されるらしい PS5が発売されたらしい ・・・といった流れから開発中盤頃に PS5をターゲットに含めるように、と方針転換がありました そうなりますと、クロスマッチは必要だよね となりましてPS4/PS5間でのクロスマッチが可能な ライブラリの調査を行ったのですが 実装予定の仕様とロビー機能がうまくマッチせずこのままだとまずい という問題が発生しました 17
解決 • 無料でオンラインゲーム開発 ~EOS を利用したゲーム開発~ https://youtu.be/zm1y6azGmSk そうした事情でプラットフォーマーさんへ相談を投げたり 移行候補ミドルウエアの調査といったことを行っていたのですが セデック2020でのEOS講演を見かけまして 個人で簡単に試用してみたところ あれ、これ全部必要な機能揃ってませんかね、え、これ使っていいの? となりまして、会社の方へ持ち帰り試験組み込みを開始しました なお、EOSの利用条件があまりに良すぎ 本作における利用条件が 達成できているのか確証が持てず この時期に、パブリッシャーさん経由で エピックゲームズジャパン様に利用可否の確認を行いました ミーティングまで開催していただき、その節は本当にありがとうございました 18
どの程度で実装ができたのか • ロビー機能移植、10日程度 • 4人で集まってロビー内でチャットが出来る程度 • ゲームパート含む全体で20日程度 • P2P通信でキャラクタ同期 • ステージ進行同期 • 招待等の実装 • トータルで1月程度で完了 • ほぼ見積もり通りで終わった • 素直な実装が多く、移植難易度は低い 組み込み開始から10日程度でロビー機能の大半が動作する状態へ持ち込めました ゲームパートを含む、それ以外の移植も20日程度で終わり、 他の業務も併走していたため正確ではないのですが、 移植は全体で1ヶ月弱程度で完了しました オーソドックスな実装が多く、 機能も必要なものは大概揃っており、 移植難易度は高くないように感じました 19
ロビーの実装 防衛軍にとってのロビー 実装例 ここからはロビーの実装についてになります 20
地球防衛軍にとってのロビーとは • ゲームへ参加するための導線提供 具体的な実装に触れる前に、 本作に実装されているロビー機能について、 ご説明させていただきます 本作でのロビー機能は、スムーズにゲームへ参加するため、の導線を提供する 重要な機能のひとつと考えております 21
ロビー - ゲーム内からの導線 • この画面でできること • ロビーの作成 • ロビーへの参加 • マッチングのために • 条件をロビー外部へ発信 • 発信された情報で選択 こちらの画面は、本作でロビー画面、 として提供しているメニュー画面になります、 現在有効なロビーが、複数並んだ画面構成になっており、 ここからロビーを作成、ロビーへ参加、オンラインモードにおける ホーム画面のような機能の画面になります マッチングを主催している側は自分が遊んでいる状態と、 どういった感じで遊びたいかを外部へ発信し、 参加する側はそれを検索や一覧から選び 取捨選択を行うことで、マッチングを成立させています 22
ロビー - SNSからの導線 • 名前検索 • テキストを完全一致で検索する • パスコード参加 • 参加時に特定のフレーズを入力する またSNS経由からの流入を想定し、 名前検索、パスコード参加といった機能を用意しています、 名前検索はロビーに名前をつけて、 特定フレーズで検索を使うことで、目的の参加先を探す機能、 パスコード参加は、特定のフレーズを知っている方なら、 誰でも参加できるロビーを用意する仕組みです こちらもロビー機能として実装されております 23
本日ご紹介する実装例 • ロビーを作る • ロビーの情報を表示する • 検索について • バージョン違いの除外 • 4人(最大人数)集まったら? 本日、紹介する実装例は、 本作で実装されているロビー機能の一部から、 こちらの内容を抜粋し、簡単に触れていきます 24
事前の注意点 省略点 注意点 内容に入る前に、いくつか注意点があります 25
実装例の前に - 省略している部分 • この部分省略してます • アプリケーション登録が必要 • ログイン、ユーザーID取得 • ユーザー作成 Webに登録している アプリケーション情報 EOSへログイン トークン取得 EOSへ接続 ユーザーID取得 EOS_ProductUserId EOSを利用する際、 はじめにサーバーにアプリケーション登録を行い、 アプリケーションはその登録情報を用いて、 認証を行い、自分自身をあらわす、 プロダクトユーザーIDを取得する必要がありますが、 本セッションでは省略しております 26
実装例の前に - 注意点 • スライド掲載のコードは概略となっています • • • • 関数呼び出しの流れを追うのが目的 エラーも未対処 正確な記述は公式のサンプル GitHubに参考資料(スライド終盤) • ハンドルなどメモリの管理 • スライドでは省略 • 解放処理が漏れやすいので注意(1敗) また、本スライドに掲載しているコードは、 スライドの可視性を重視し、 関数呼び出しの流れをある程度把握できる程度の 内容となっております、 実際の動作するコードに関しましては、 公式のサンプルを参照していただくか、 ギットハブのほうに ウインドウズプラットフォーム用のコードを 参考資料として作成してみましたので、 参照して頂いてければと思います そして、C++版のEOSでは メモリの開放管理を すべて自分で行う必要がありますので、 プログラム中で作成、取得した 27
ハンドル、メモリの解放漏れがないよう注意してください。 あとから見つけるのは非常に困難です
ロビーを作成する ロビーの登録 ロビーに参加する 注意点は以上になります、 最初にロビーを作成してみます 28
ロビーを作成する - 1 • プラットフォームハンドルを作成する • ハンドルからロビーインターフェイスを取得する EOS_Platform_Options opt; opt.ProductId = SampleConstants::ProductId; opt.SandboxId = SampleConstants::SandboxId; opt.DeploymentId = SampleConstants::DeploymentId; opt.ClientCredentials.ClientId = SampleConstants::ClientCredentialsId; EOS_Hplatform platform = EOS_Platform_Create(&opt); EOS_Hlobby lobby_handle = EOS_Platform_GetLobbyInterface(platform); まず、サーバーに登録したアプリケーション情報から プラットフォームインターフェイスを作成します こちらはロビーだけに限定されず、 EOSの各インターフェースの取得に必要となるハンドルとなっております このハンドルを作成する際に、 Webに登録しているアプリケーション情報を利用する必要があります 作成したプラットフォームインターフェイスから ロビーインターフェイスが取得できるようになっています 29
ロビーを作成する - 2 • ロビーインターフェイスからロビー作成を行う • 作成完了時に、ロビーIDが取得できる • ロビーIDからディテールハンドルを確保しておく EOS_HLobbyDetails details; EOS_LobbyId id; auto OnCreated = [&id](const EOS_Lobby_CreateLobbyCallbackInfo* data) { id = data->LobbyId; }; EOS_Lobby_CreateLobbyOptions options; EOS_Lobby_CreateLobby(EOS_Hlobby, options, OnCreated); // OnCreatedが処理されるまで待つ EOS_Lobby_CopyLobbyDetailsHandle(EOS_Hlobby, id, &details); 続いて先ほど取得した ロビーインターフェイスで ロビーを作成するように要求を行います、 こちらを行うことでサーバーに登録が行われ 作成したロビーとのインターフェイスになる ロビーIDが得られ、 ロビーIDからロビーディテールハンドルが得られます 30
ロビーに参加する
• 作成と同じくIDが取得できる
• ロビーIDからディテールハンドルを確保しておく
EOS_HLobbyDetails details;
EOS_LobbyId id;
auto OnJoined = [&id](const EOS_Lobby_JoinLobbyCallbackInfo* data){
id = data->LobbyId;
};
EOS_Lobby_JoinLobbyOptions options;
options.LobbyDetailsHandle = 参加先;
EOS_Lobby_JoinLobby(EOS_Hlobby,options,OnJoined);
// OnJoinedが処理されるまで待つ
EOS_Lobby_CopyLobbyDetailsHandle(EOS_Hlobby,id,&details);
参加する場合も同じく、
ロビーIDとロビーディテールハンドルが取得できます
31
ロビー作成まとめ • EOS_LobbyId、 EOS_HLobbyDetailsというものがある • 作成、参加するともらえる • EOS_LobbyId • 新たに変更、取得などを行う際に指定する • 文字列ポインタなので、保存する場合は実体を保存する • EOS_HLobbyDetails • 現時点でのロビー情報が格納されている • 属性(後述)、参加人数、参加者情報等 • 参加する際にも必要になる(後述) 作成についてのまとめです、 ロビー作成、参加時はロビーIDが取得でき、 そこからディテールハンドルが取得できます 必要に応じて保存しておきましょう 32
ロビーの情報を表示する 続きまして、 ロビーの情報を一覧として 表示するために必要な要素の 登録や取得について、です 33
ロビーに必要な情報 • ロビーに属性として情報を設定 • 属性は文字列で名前を付ける • 属性はUTF8、真偽値、倍精度小数、整数が保存できる • ロビー情報を取得、再構成して表示する 本作のロビーでの情報表示は、 各ロビーに登録されたアトリビュート、 属性と呼ばれるパラメータを取得し、 それらを再構成し、 表示することで実現しています、 先ほどのロビー画面に表示されていた 各ロビー情報のことですが、 ロビーひとつに限定し、拡大した図がスライドの画像になります、 属性は、キーとなる文字列と、データが ついとなった情報です、 データには、文字列、真偽値、小数点、整数が選択できます 本作では、ユーザーさんに見せないものを含め 20個弱程度の属性が設定されており、 これらを取得した結果を加工し、 34
ロビー画面へ提供しています
ロビーへ属性を登録する ということで、ロビーに情報を登録してみます 35
ロビーへ属性を登録する - 1 • 設定変更用のインターフェイスを作成する • ロビーIDとユーザーIDが必要 EOS_HLobbyModification modification = nullptr; EOS_Lobby_UpdateLobbyModificationOptions opt = {}; opt.ApiVersion = EOS_LOBBY_UPDATELOBBYMODIFICATION_API_LATEST; opt.LobbyId = EOS_LobbyId; opt.LocalUserId = EOS_ProductUserId; EOS_Lobby_UpdateLobbyModification(EOS_Hlobby, &opt, &modification); まず、操作用のインターフェイスを作成します、 ロビーモディフィケーションというインターフェイスです、 ロビーの設定をおこないたい場合は こちらのインターフェースを利用します 操作対象のロビーIDと、 プロダクトユーザーIDが必要となります 今回は属性を追加する目的で作成していますが、 最大参加人数、パーミッションなども取り扱いできます 36
ロビーへ属性を登録する - 2
• 登録する情報を設定する
• データ種はUTF8、真偽値、倍精度小数、整数
• 設定変更インターフェイスへ登録する
EOS_Lobby_AttributeData a;
a.ApiVersion = EOS_LOBBY_ATTRIBUTEDATA_API_LATEST;
a.Key = "NAME";
a.ValueType = EOS_ELobbyAttributeType::EOS_AT_STRING;
a.Value.AsUtf8 = u8"なまえ";
EOS_LobbyModification_AddAttributeOptions opt= {};
opt.ApiVersion = EOS_LOBBYMODIFICATION_ADDATTRIBUTE_API_LATEST;
opt.Attribute = &a;
opt.Visibility = EOS_ELobbyAttributeVisibility::EOS_LAT_PUBLIC;
EOS_LobbyModification_AddAttribute(EOS_HLobbyModification, &opt);
こちらはNAMEというキーで
文字列を設定する例となります
キーワードとデータ部分の文字列を設定し、
それをロビーモディフィケーションへ登録しています
属性用の構造体へ
登録したいデータと種類を設定します、
データ部分は共用体になっており、
種類により指定するメンバ名が変化します
登録する際、ビジビリティという項目がありますが、
こちらは自分以外から見ることが出来るか、のようなパラメータです
パブリック、プライベートと設定できまして
本作ではパブリックのみ利用しております
37
ロビーへ属性を登録する - 3 • 更新処理を呼び出してサーバーにロビーの属性を反映する EOS_Lobby_UpdateLobbyOptions opt = {}; opt.ApiVersion = EOS_LOBBY_UPDATELOBBY_API_LATEST; opt.LobbyModificationHandle = EOS_HLobbyModification; EOS_Lobby_UpdateLobby(EOS_Hlobby,&opt, OnUpdated); // OnUpdatedが呼び出されるまで待つ モディフィケーションに登録した情報を サーバーへ反映させる処理を呼び出し、 実際にサーバーへ反映させ、 登録操作は完了になります 38
ロビーの情報を取得する サーバーに登録されているロビーを取得する ロビーから属性を取得する 続きまして、設定した内容を取得する方法です 39
ロビーの情報を取得する - 1 • 情報を取得するには、検索する必要がある • 検索インターフェイスを作成する • インターフェイス作成時に最大取得数を指定 • 最大取得数には上限制約があるので注意する EOS_HLobbySearch search_handle; EOS_Lobby_CreateLobbySearchOptions opt; opt.ApiVersion = EOS_LOBBY_CREATELOBBYSEARCH_API_LATEST; opt.MaxResults = 20; EOS_Lobby_CreateLobbySearch(EOS_Hlobby, &opt, &search_handle); 外部からロビー情報を取得するためには、 検索を行う必要があります 検索インターフェイスを作成するのですが、 作成時に検索結果の最大取得数を 指定する必要があります 40
ロビーの情報を取得する - 2 • 検索処理を呼び出す • コールバックで結果を受け取ることが出来る • 自分のユーザーIDを指定 ※注意点 条件なしの検索は本来出来ないため注意 EOS_LobbySearch_FindOptions opt; opt.ApiVersion = EOS_LOBBYSEARCH_FIND_API_LATEST; opt.LocalUserId = EOS_ProductUserId; EOS_LobbySearch_Find(EOS_HLobbySearch , &opt, OnSearchFind); // OnSearchFindが呼び出されるまで待機する インターフェイスが作成できましたら検索を行い、 結果を取得できるまで待機します 41
ロビーの情報を取得する - 3 • 結果は検索インターフェイスに格納されている • 複数の結果があることが前提 • ロビーに参加する際に、EOS_HLobbyDetailsが必要 // 格納されている数を取得する EOS_LobbySearch_GetSearchResultCountOptions options; EOS_LobbySearch_GetSearchResultCount(EOS_HLobbySearch, &options); // 格納されているロビー情報をコピーする EOS_LobbySearch_CopySearchResultByIndexOptions options; options.LobbyIndex = 取得したいインデクス; EOS_HLobbyDetails details; EOS_LobbySearch_CopySearchResultByIndex(EOS_HLobbySearch, &options, &details); 検索完了後、 まず何件の検索結果が帰ってきたかを調べます。 件数がわかったあとは、 取り出したいインデクスを指定し ロビーディティールハンドルを取得します このディティールハンドルは、 作成、参加したときに得られるハンドルと同じものです、 参加時の説明では省きましたが、 ロビーに参加する際、 参加先を特定するために、 要求されるハンドルとなっております 42
ロビーの情報を取得する - 4
• 特定のロビーとなったので、ロビーの属性を取り出す
const auto count = EOS_LobbyDetails_GetAttributeCount(EOS_HLobbyDetails);
EOS_LobbyDetails_CopyAttributeByIndexOptions options;
options.ApiVersion = EOS_LOBBYDETAILS_COPYATTRIBUTEBYINDEX_API_LATEST;
for (auto i = 0; i < count; i++) {
options.AttrIndex = i;
EOS_Lobby_Attribute* a;
EOS_LobbyDetails_CopyAttributeByIndex(EOS_HLobbyDetails, &options, &a);
a->Data->Key;
a->Data->ValueType;
a->Data->AsUtf8;
a->Visibility;
}
ロビーディティールハンドルからは、
そのロビーに登録されている
属性の個数や属性を取り出すことが出来ます
インデクス形式でのアクセスする場合は、
まず、属性の登録数を取り出して、
その個数分、属性を取り出します、
こちらには書かれていませんが、
キー経由でのアクセスも可能となっています
どちらの方法でも、設定時に利用した
ロビー属性構造体の形式でデータが取得されます
ロビー属性の取得方法については、
このような形で行います
43
ロビーでの表示 - パラメータ • 黄色…整数(int64) • 赤色…文字列(UTF8) 本作で属性として利用している部分については、 図のような形で 個別の属性が設定されております 黄枠が整数、赤枠が文字列の属性です 文字列の場合はそのまま表記し、 数値の場合は、必要な加工を行い表示するようになっています 44
ロビーの情報まとめ • ロビーの属性はUTF8、INT64 、 DOUBLE 、 BOOL • 属性には名前(キー)が設定できる • EOS_HLobbyModification • 属性の登録、削除 • その他対象ロビーに関する変更処理が行える • EOS_HLobbySearch • 属性、ID、ユーザーで検索ができる • 結果の取得もこちらのインターフェイスから • EOS_HLobbyDetails • 対象ロビーの情報が取得できる • 属性、参加者数、参加者情報 ロビーの情報についてのまとめです ロビーの属性は文字列、整数、浮動小数、真偽値があり、 ロビーモディフィケーション経由で登録が行える、 ロビーサーチインターフェイス経由で、 ロビーディテールハンドルを取得することで 各ロビーの属性を取得することができます 45
検索 条件指定検索 結果のソート 設定した属性を利用してロビーを探すことも出来ます 46
ロビー情報を取得する時の条件 • EOS_LobbySearch_Findには条件が必要 • 属性と演算子 • ロビーID • ユーザーID • <講演内容の補足> 条件を何も設定せず検索を行うと EOS_LobbySearch_Findの結果が EOS_InvalidParametersになります 先ほどのロビー情報の取得ですが、 設定をなにも行っていないため、 実は動作できず、 エラーになってしまいます、 検索を正しく行うには、 条件を設定する必要があります 47
地球防衛軍6での検索 本作では、ステージ情報や、難易度など ユーザーが指定するものを中心に 属性と演算子により条件を作成し、 動作させています 48
検索する属性を指定する
• Findを行う前に検索パラメータを設定する
• 演算子 == ≠ > ≥ < ≤ any one contains
EOS_Lobby_AttributeData a;
a.Key = "NAME";
a.ValueType = EOS_ELobbyAttributeType::EOS_AT_STRING;
a.Value.AsUtf8 = u8"なまえ";
EOS_LobbySearch_SetParameterOptions opt = {};
opt.ComparisonOp = EOS_EComparisonOp::EOS_CO_EQUAL;
opt.Parameter = &a;
EOS_LobbySearch_SetParameter(EOS_HLobbySearch, &opt);
EOS_LobbySearch_FindOptions opt;
EOS_LobbySearch_Find(EOS_HLobbySearch, &opt, OnSearchFind);
// OnSearchFindが呼び出されるまで待つ
属性と演算子により検索を行う場合、
先ほどの検索インターフェイスに対して
属性と比較演算の種類を、設定します
指定する属性は、
さきほど、属性の設定時に利用した
構造体と同じものです
こちらを検索インターフェイスへ設定します、
比較演算の種類も同時に設定します
== ≠ > ≥ < ≤ any one containsなど色々な種類があります、
今回指定しているのは == になっています、
検索を実行した結果、
NAMEになまえと設定されているロビーが
取得できます
49
検索 - 順序の制御 次に、検索結果のソートについてです 50
地球防衛軍6でのロビーの並び • ロビーの順序はソート済み • 作成直後、クリア直後のものを優先 • 時間を格納する属性を用意 • 時間を基準にソート EOSにて検索結果のソートは サポートはされているのですが、 ある程度うまく仕込みをする必要があります 本作では、ロビーの一覧表示を行う際、 ロビーを作成した直後か ゲーム進行から戻ってきた直後のものが 先頭から順に並ぶようにしています、 これは、スムーズに参加できる可能性が高いと 想定しているからです こちらをどのように行っているか、 ということですが、 ロビーに時間の属性を設定し、 それを検索する際にサーバ側でソートして結果を取得しています 51
属性として更新時間を設定する • マッチングの管理者がロビーの属性に現在の時間を設定 EOS_Lobby_AttributeData a; a.Key = "CREATE_TIME"; a.ValueType = EOS_ELobbyAttributeType::EOS_AT_INT64; a.Value.AsInt64 = 現在の時間を整数へ変換した値; EOS_LobbyModification_AddAttribute(EOS_HLobbyModification,opt(a)); EOS_Lobby_UpdateLobby(EOS_Hlobby, opt(EOS_HLobbyModification), OnUpdated); // OnUpdatedが呼び出されるまで待つ 設定している項目は こちらのような内容で、 時間の属性を用意し、 ロビーを作成した際、 またゲーム進行から戻ってきた際、 それぞれに最新の時間になるよう 属性を更新しています 52
更新時間基準にソートして結果を取得
• サーバーの各ロビーの属性には新しい順に大きな値が入る
• 距離よる比較を行うことで一番近いロビー順に並べる
• EOS_CO_DISTANCEを使う
EOS_Lobby_AttributeData a;
a.Key = "CREATE_TIME";
a.ValueType = EOS_ELobbyAttributeType::EOS_AT_INT64;
a.Value.AsInt64 = std::numeric_limits<decltype(int64_t)>::max();
EOS_LobbySearch_SetParameterOptions opt = {};
opt.ComparisonOp = EOS_EComparisonOp::EOS_CO_DISTANCE;
opt.Parameter = &a;
EOS_LobbySearch_SetParameter(EOS_HLobbySearch, &opt);
EOS_LobbySearch_Find(EOS_HLobbySearch, OnSearchFind);
// OnSearchFindが呼び出されるまで待つ
サーバーからみると、
各ロビーの更新順に
大きな値が入ることとなります
そして、検索する際に
整数の最大値と
ディスタンスの演算子を指定することで、
サーバー側で
整数の最大値に近い順序に
なるよう並べかえた結果を
受け取ることができます
53
複数の検索で一貫した結果を得る • 検索後、現在の検索結果の続きを取得する また、本作では続きを取得する、 という機能を実装しております、 こちらは、最大取得数以上に サーバに同じ条件のものがある場合、 検索結果の続きを取得する という機能になっています、 こちらの機能も同じく、 時間属性を利用することで実現しております 54
ソートと小なりを同時に設定する
• EOS_CO_LESSTHANを利用する
• 比較は取得したロビー情報の一番若い時間から-1したものを使う
EOS_Lobby_AttributeData a;
a.Key = "CREATE_TIME";
a.ValueType = EOS_ELobbyAttributeType::EOS_AT_INT64;
a.Value.AsInt64 = 前回取得した一番若い時間-1;
EOS_LobbySearch_SetParameterOptions opt = {};
opt.Parameter = &a;
opt.ComparisonOp = EOS_EComparisonOp::EOS_CO_LESSTHAN;
EOS_LobbySearch_SetParameter(EOS_HLobbySearch, &opt);
opt.ComparisonOp = EOS_EComparisonOp::EOS_CO_DISTANCE;
EOS_LobbySearch_SetParameter(EOS_HLobbySearch, &opt);
今回は、先ほど最大値を入れていた時間属性に
前回取得したロビーの中で
もっとも古い時間よりも小さな値、を設定し、
小なりの演算子を追加することで、
指定した時間以前に更新されたロビーを
ソートされた状態として取得する、
という処理を行い、
つづきを取得するという機能を実現しております
55
検索まとめ • 検索条件には、属性が設定できる • ロビーID、ユーザーIDも設定できる • 属性に演算子を指定することで絞り込み検索が出来る • 検索結果はサーバー側でソートすることが出来る • 演算子は複数適応することが出来る 検索についてのまとめです、 検索時に属性と演算子を指定することで絞り込みが出来、 検索結果はディスタンスを使うことで距離順ソートすることが出来ます、 演算子は複数同時に適応することも出来ます、 といった内容でした 56
バージョン違いの除外 • プロトコルバージョン違いへの対応 • 属性にバージョン情報を格納 • 検索時に異なるバージョンの除外を 常時適応する • <講演内容の補足> • ゲームのバージョンアップにより キャラクタ間の通信に互換性が無くなることを、 プロトコル違いと称しております バージョン情報をロビー属性に埋め込み、 検索する側のバージョンと一致するものしか 表示しないようにしてます、といった内容です • 伝わりにくい表現であったので、補足をいれました。 続きまして、 ゲームでよくある アップデート後の プロトコル違いを回避するための バージョン情報埋め込みです 本作では検索時に自動的に含める条件式がいくつかあるのですが、 そちらを利用した形で実現しております コードは大差ありませんので、 省略させていただいておりますが、 専用の属性を用意し 整数型の比較処理として実装されています 57
最大人数になったら • 参加上限でも検索結果に表示される • 大半の状況で邪魔 • 検索条件で自動的に除外 • ロビー運用者側で閉鎖情報を入れる • メリット • 名前検索時に上限のロビーが発見可能 参加者が最大でもう参加できないよ、 という時も検索には列挙されてしまいます が、ユーザーからみるとありがたくない状況です、 ということでこちらも識別出来るようにし、除外しています 実装はマッチング主催者の方で、参加者が最大になったら bool属性にtrueを設定するという処理を入れています 検索する側は、常時その属性データがfalseであることを含めた検索を行います EOSでは自前でやるしかないのですが、 自前でやったほうがよい場合もありまして、 たとえば名前検索した場合は、 常時表示するようにし、 ああ人数が満タンだから参加できないな、 と参加できない理由が明瞭となる実装ができます 58
P2P通信について と、いった内容が本作における EOSを利用したロビー実装例の解説となります 続きまして、ピアツーピア部分にスポットを当てた内容となります 59
地球防衛軍6での通信 • 独自UDP/RDUPとして処理される • UDP(順序なし) • UDP(Ordered、順序違反はDrop) • RUDP (順序なし) • マッチング完了後の情報交換はすべてP2Pで行う ゲーム内の通信処理は独自の ユーディーピー/リライアブルユーディピーとして実装されています マッチング完了後の 相互情報交換は サーバ側機能には依存せずに すべてピアツーピア通信で行われています、 サーバ側に送る必要のない情報は 極力送らないという方針です、 サーバに送る情報は、 ロビーの外部に公開する情報や 必要な設定情報のみとしています 60
地球防衛軍6での通信 - ゲーム • 同期対象キャラ数は最大で300程度 • 想定帯域を超えたら必須ではないものの帯域が絞られる • 最優先(RUDP) • キャラクタ生成 • ステージ進行 • 優先(RUDP/UDP) • プレイヤー • それなり(RUDP/UDP) • AIキャラ • いけたらいくわ(UDP) • 現在位置情報 • 最大で1Mbps以下程度になるように調整 • <講演内容の補足> • 話がややこしくなるので省略してしまったのですが、 上記は最小の構成で、こちらに攻撃、ダメージ、撃破、武器発射 などのその他通信が乗ります。こちらが追加で乗った状態で1Mbpsがリミットで制限がかかります。 同時射出20発ランダム拡散弾で全部が着弾時範囲爆破で10mにダメージ、 火炎放射で範囲100mに継続ダメージ、同時発射60発のレーザー(全部別ダメージ判定)、 といった(通信制御からみると好ましくない仕様の)武器が、4人がかりで連射されます • 敵も似たような攻撃をしてきます。 • この後のスライドの通信負荷は、こちらの通信は考慮されていない通信量となっています。 ゲーム中の通信に関しては、何も対策せずに実行すると、 最大300体ほどのキャラを同期させるため、詰みます キャラクタ個別に通信量の削減を行っているのですが、 それだけでは厳しい状況であるため、全体の仕組みとして、 ゆるーく帯域制限がかかるようになっております、 通信帯域の占有は出来ないようにした上で、 ステージ進行とキャラクタ生成を優遇する仕組みにしています、 パケット内のペイロード割合でこれ以上使えないけど、 これぐらいまでなら優先で、といった実装になっています、 それ以外のものは、ゆるやかに通信頻度が落とされたり、 通信そのものがされなくなるといった実装になっています また、その上でどれだけやっても 1Mbps以下にしかならないという制限もされています 61
最大上限が低めに見えるかもしれませんが、 光環境でも意外と出ない、出せない、出すとダメな環境は多いのでこの程度としています
通信負荷について - 1 • 味方10体 小型敵200体 • 40Kbps - 320Kbps 続いて実際のゲームシーンでの通信状況、 おもに通信帯域になりますが、を2シーンほど抜粋してお伝えします こちら味方に人間タイプのキャラクタ10体程度がいるところへ、 小型、小型っていっても人間より大きいサイズなんですが、 小型の地上タイプの敵がビルを破壊しながら出現して、 時速数百キロぐらいで200匹程度同時に襲いかかってくる、というシーンです 大体300Kbps程度で 単純な通信量ではこちらのシーンが一番多いと記憶しています 62
通信負荷について - 2 • 味方5体 中型敵30 飛行型小型敵250体 • 50Kbps - 120Kbps 続いて中型の敵が30体、飛行型の敵が250体ほど出現している状態です 単純な数だけですと、今作中最多の状態がこのぐらいであったかと思います 飛行型は軽量に実装されているため、 帯域のピークまでは行かないような状態です もう少し通信量を増やしてもいいのかもしれませんが、 多少増やした程度ではあまり変化がないのと、 他のキャラと組み合わせしにくくなってしまうので、 このような調整になっています 63
通信 - キャラクター - 1 • AIを複数人で分担をすることで削減 • 選択基準は敵視(攻撃ターゲット)状態 • 敵視された状態次第で受け持ちを動的に決める • 問題が出るAI種はホスト固定 • メリット • こちらを狙っている敵の再現精度が高くなる • 分散されやすくなり帯域が抑えめにできる • デメリット • プレイヤーがヘイト集めをすると帯域が集中しやすい • 遠距離攻撃しているプレイヤーは再現率が低くなりがち キャラクターについてなのですが、 地球防衛軍では、 通信量を分散させるのを目的として、 敵にターゲットされているプレイヤーが 敵AIを担当するという方式を採用しています 攻撃を受けている敵キャラの担当をすることで、 プレイ中の違和感が少なく、 通信も分散されやすくなり、 帯域が抑えられるという所を狙っています 64
通信 - キャラクター - 2 • トリガー方式同期と定期通信 • キャラは定期ごととトリガー単位で通信を行う • 定期(一定時間ごと必ず通信、UDP) • 座標 • 時間経過による変化 • 状況リセット • トリガー(状態変化で通信、RUDP/UDP ) • 状態変化(ステートマシン) • 攻撃 • 大きなダメージ そして、キャラクターは 一定時間ごとに通信を行う定期通信と 状態変化があったときに通信する トリガー通信が個別に動作しております、 スライドで簡易に分類されていますが、 まずスライドで分類された項目で実装し、 問題が発生する箇所を 別の通信方式に置き換えたり、 通信頻度を調整する という感じで調整しております 65
EOSのP2P実装について • EOSのP2P通信自体は素直な実装 • EOS_P2P_AcceptConnection() • EOS_P2P_SendPacket() • EOS_PR_UnreliableUnordereds … UDP • EOS_PR_ReliableUnordered … 順不同必達 • EOS_PR_ReliableOrdered … 順同必達 • EOS_P2P_ReceivePacket() • <講演内容の補足> • プレイヤー間でP2P通信を確立させる際、 通信が確立したのを確認してから実際の通信を行った方がよいです 具体的には、SendPacketを何度かダミーで呼び出し、 自分、相手、双方で通信が確立したのを確認してから(SYN/ACKの2段階で確認する程度でいいかなと)、 実際の通信を行う、といった対策です 同一PC内のマッチングでも通信が初回で確立しないケースが発生することから、 NATはあんまり関係なくて お互いにAcceptConnectする以前はパケットが捨てられるからかな、と思ってますが、 ちゃんと調べていないので、理由はよくわかってません そしてEOSのピアツーピア実装部分なのですが、 比較的素直な実装となっています、 誰かから通信が届いたとコールバックが来たら、 アセプトコネクションを行い通信を許可、 後はセンド 、レシーブを行うことで相互通信が可能です 送信時のライブラリ側機能としてユーディーピー、 順不同リライアブルユーディーピー、 順同リライアブルユーディーピーが利用できます 弊社の場合はすでに構築済みの通信処理があったため、 EOSのユーディーピー部分の上層に、 それをのせる形で利用しておりますが、 そのような運用でも問題なく動作しています 66
まとめ 使用感 最後に、結局使ってみてどうだったの? といったところを共有させていただければと思います 67
よかった - 1 • 運用トラブルなし • 10万弱程度の接続が発生 • 目立った不良はなし • UnrealEngine以外からも利用可能 • 独自環境、別エンジンからの乗り入れも可能 • C++開発環境があれば、即サンプルが動作できる まずは良かった点についてになります 同時アクティブ数が 最大で10万弱程度の規模での運用で トラブルはありませんでした 実績などがわからず、正直そこまで期待しておりませんでしたが 蓋を開けてみれば、こちらが想定していた、 同時接続数を上回ったにもかかわらず、あっさり安定動作していました 次にアンリアルエンジン以外からも 利用可能なのはありがたいと思いました、 C#や携帯などの実装もあり、 エピックアカウント作って即テストが行えるので、 導入試験なども、かなりやりやすい状況だと感じました 68
よかった - 2 • プラットフォーム間での相互乗入れが可能 • 共通化されれて良い • 無償で提供されている • 提供元が著名なため話が通しやすい • 運用フェイズも楽 特殊な修正なしで、各プラットフォームと、 相互乗入れが可能なのはかなり便利に感じました プラットフォームごとにログインの行程だけ異なりますが、そこだけ乗り越えれば ユーザーの統合が出来ている状態で、 使える機能は全プラットフォームで同じことが出来る、 これは大きなメリットだと思います。 無償で提供の部分ですが、 弊社はデベロッパーで、パブリッシャーとは完全に分かれた状態となっております、 この状態、有償のミドルウエア導入した場合、 固定費は開発費から出すとして、 サーバー運用費や運用担当の人員はどこが出すの? みたいな話から始まって結構ややこしい問題になりがちです このあたりを悩まなくていいというのは非常にありがたいと感じました 69
イマイチ - 1 • 情報(サンプル)が不足気味 • 異常系への対策資料 • サンプルを正しく動かすまでが若干難解 • 公式以外のWeb上の資料少なめ(最近増えてきました) つづいて、どうにかなると、よりうれしいなという部分です サンプルがあるので、サンプルがある範囲の正常系は読めばわかるのですが、 異常系の処理が、ほんとにこれでいいのか・・・という疑問が最後まで付きまといました、 エラーおきた後リトライどうすんの?やっていいの?みたいな話ですね このやり方だとダメ!って後から言われるとちょっとしんどい部分なので、 ログイン部分など要所では ある程度エラーの対応が含まれたものが 公式に配布されるとうれしいと思いました、 また、サンプルの動かし方もわかりづらいと感じました、 とりあえず、ビルドは通って動作はする・・・ しかし正常に動作しておらず、どこを触っても反応しない・・・ こちらは、はじめてSDKのサンプルを動作させた時の感想です、 この状態は、ビルドしたサンプルにアプリケーション認証情報が入っていないせいでしたが、 あまり親切ではないのかなと思いました 必要なファイルを用意しないと、ビルドが通らない、 70
問題があればアサートで停止する、といった配慮があると嬉しいなと感じました
イマイチ - 2 • サーバのカスタマイズはできない • 出来ないが、カスタムせずとも十分機能はある • トラブル検出 • 問題発生時にアラートがこない • サーバーは知らぬ間に対処され解消される • ユーザーサポートの方針次第? https://status.epicgames.com/ Epic Games Public Status サーバーのカスタマイズで 困るケースは結構少ないかなと思うのですが、 サーバのカスタマイズはできないようです、 カスタマイズせずとも十分機能としてはそろっていましたが、 もし、どうしても必要が機能がない、 といった状況が発生するとやっかいかもしれません 最後はトラブル時の検出の話です、 サーバーにトラブルが発生している場合の 状況把握が難しいという内容です、 基本として得られる情報は、 公式のステータスサイトを見る形になるので、 ユーザーと同じ程度の情報しか得られません ただ、各プラットフォームに用意されているような情報も同じような状態なので、 それを把握する必要あるの? といわれると無いのかもしれません 71
サーバーの情報は、スライドにありますURLから参照することができます。
やっちまったこと 開発中の失敗例 余録として失敗をいくつかやってしまったので、 そちらも共有させてください。 72
設定ミスで機能試験に入れなかった • EOS管理側にするべき設定が抜けていた • IDプロバイダは資料が少ないので 慎重に設定する • プラットフォーム側の機能で 事前検証が可能ならやっておく こちらはIDプロバイダーに設定が必要なこと自体が わかっていなかったパターンになります、 とある開発環境では、 開発用、検証用、リリース用と環境が別れており、 当然、EOSの開発者サイトでアプリケーションを登録する際に、 IDプロバイダーで それぞれ個別に設定が必要になっていたのですが、 当初気がつかず、 開発用環境のみ設定し、 開発用環境では正しく動作する、 それ以外ではサーバーへ接続できない という状況が発生していました。 プラットフォーマーさんから、検証環境でちゃんと動いてないよ、 と連絡を頂いたのですが、原因がよくわからず、 73
EOSのサポートに質問を投げた所、 迅速に原因を発見して頂き、 解決することが出来ました。
ライセンス不掲載 • EOSはライセンス表記が必要 • 2000行程度あります • 文字コードはwestern windows 1252? • UTF8になるとうれしいな • <講演内容の補足> • EOS-SDK-27379709-v1.16.1に同梱されているファイルは2537行でした。 EOS-SDK-27379709-v1.16.1 ├─Samples ├─SDK └─ThirdPartyNotices └─ThirdPartySoftwareNotice.txt 続きまして、EOSは利用する際にライセンス表記が必要となっております、 EOSのSDK内に該当ファイルがあるのですが、 こちら2000行ほどありまして、 単純に表示すると処理が重く、 ゲーム内に表示するための専用の処理が必要だなぁ、、 と考えていたら搭載を忘れていました・・・ こちらはゲーム内のマニュアルページの一部として掲載されるように デイワンパッチで対応させて頂きました。 74
参考資料 • https://dev.epicgames.com/docs/ja • 公式ドキュメント • https://www.youtube.com/watch?v=zm1y6azGmSk • 無料でオンラインゲーム開発 ~EOS を利用したゲーム開発~ • https://github.com/y-horiuchi-snd/eos_console_test • EOS機能テストをおこなった際のソースコード 以上になります、 本公演で話した情報はこちらのサイトで得た情報などを元に、 独自に解釈した内容となっております、 また、さきほど申しあげましたソースコードは、 こちらのURLのほうにおいてありますので ご興味が湧きましたらご参照ください 75
権利 • ©2023 Sony Interactive Entertainment Inc.“プレイステーション ファミリーマー ク”、“PlayStation”、 “プレイステーション”、 “PS5ロゴ”、“PS5”、 “PS4ロゴ”、 “PS4”、 “プレイステーション シェイプスロゴ”および“Play Has No Limits”は、 株式会社ソニー・インタラクティブエンタテインメントの登録商標または商標です。 • © 2023, Epic Games, Inc. Epic、Epic Games、Epic Games のロゴ、 Fortnite/フォートナイト、Fortnite/フォートナイトのロゴ、Unreal、Unreal Engine、 Unreal Engine のロゴ、Unreal Tournament、Unreal Tournament のロゴは、 米国およびその他の国々における Epic Games, Inc. の商標または登録商標 であり、無断で複製、転用、転載、使用することはできません。その他のブランド や製品名は、それらを所有する会社の商標です。 • ©2023 Valve Corporation. Steam and the Steam logo are trademarks and/or registered trademarks of Valve Corporation in the U.S. and/or other countries. • GitHub®は、GitHub Inc.の商標または登録商標です。 • ©2022 SANDLOT ©2022 D3PUBLISHER 本スライドに登場する商標、ロゴ、製品名は各権利者に帰属します 本日はご清聴頂き、ありがとうございました 76