---
title: [Tokyo DevDays 26&#039;] Epic Online Servicesを使い始めるために
tags:  #devdays #ue5 #eos #epic online services  
author: [エピック ゲームズ ジャパン](https://docswell.com/user/EpicGamesJapan)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/2EVVYDL3EQ.jpg?width=480
description: 2026年8月26日に開催されました「Unreal Engine Tokyo Dev Days 26&#039;」イベントの「Epic Online Servicesを使い始めるために」講演のスライドです。  公式サンプル EOS-Getting-Started をベースに、ログイン・ロビー・P2P・実績・クラウドセーブまでをコードで追います。 サンプル: https://github.com/EpicGames/EOS-Getting-Started ドキュメント: https://dev.epicgames.com/docs/epic-online-services
published: September 01, 26
canonical: https://docswell.com/s/EpicGamesJapan/K9N62V-2026-09-01-111742
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/2EVVYDL3EQ.jpg)

Epic Online Services
を使い始めるために
Epic Games Japan
Software Engineer, Developer Relations
YooCheol Choe(チェ)


# Page. 2

![Page Image](https://bcdn.docswell.com/page/57GL9YXYEL.jpg)

はじめに
自己紹介
1. Epic Games Japan / Software Engineer, Developer Relations
EOS 導入・技術サポートを担当しています
2. 普段やっていること
EOS 実装レビュー、不具合の切り分け
3. 今日は
「EOS をこれから触る UE 開発者」に向けて、最短ルートを案内する側です


# Page. 3

![Page Image](https://bcdn.docswell.com/page/4EQYWM86JP.jpg)

はじめに
今日の流れ
1. EOS とは何か
サービスを名前で一通り。無料 / クロスプラットフォーム / モジュール式という前提も
2. 動いているところを見る
公式サンプルを 2 クライアントで起動した画面と、そのときの実ログ
3. Dev Portal で準備する
Product と Client、Sandbox と Deployment、Stat と実績の定義
4. UE から呼ぶ
ini など 3 ファイルのセットアップと、全機能に共通する 4 ステップのコード
ベースは公式サンプル EOS-Getting-Started です


# Page. 4

![Page Image](https://bcdn.docswell.com/page/KJ4WKV2M71.jpg)

EOS とは何か
EOS とは
ゲームに必要なオンライン機能を、
Epic が運用まで引き受けてくれるサービス
具体的には
ログイン
実績
フレンド
ランキング
ロビー
クラウドセーブ
マッチメイキング
ボイスチャット
不正対策
Fortnite を支えているのと同じ基盤が、そのまま公開されています


# Page. 5

![Page Image](https://bcdn.docswell.com/page/LE1YX3MY7G.jpg)

EOS とは何か
EOS の 4 つの特徴
無料
利用料なし。CCU 課金も
ホスティング費用も不要
クロス
プラットフォーム
ストア非依存
エンジン非依存
PC / Console / Mobile を
横断して同じ API
Steam でも使えます
UE 以外からも使えます
「まず試す」までのハードルが、ほぼありません
モジュール式
必要な機能だけ選んで
使えます


# Page. 6

![Page Image](https://bcdn.docswell.com/page/GEWGNP31J2.jpg)

EOS とは何か
サービス構成の全体像
大きく 4 つのカテゴリに整理できます
Account &amp; Social
Multiplayer
Player &amp; Game Data
Trust &amp; Safety
Epic Account Services
Lobbies
Stats
Easy Anti-Cheat
Connect
Sessions
Achievements
Player Reports
Friends
Peer-to-Peer
Leaderboards
Sanctions
Presence
Voice Chat
Player Data Storage
Overlay
Title Storage


# Page. 7

![Page Image](https://bcdn.docswell.com/page/47ZL3KVXJ3.jpg)

サービスマップ
アカウント &amp; マルチプレイ
Epic Account Services (EAS)
Epic アカウントでのログイン、フレンド、プレゼンス
Connect
Steam / コンソール / Device ID などを 1 つの PUID に
Lobbies
マッチ前の待合室。参加者と属性の変更をバックエンドが push
Sessions
マッチ登録 / 検索
Peer-to-Peer
NAT 越えのピア間通信
Voice (RTC)
Lobby に自動連動する音声チャット


# Page. 8

![Page Image](https://bcdn.docswell.com/page/YJ6WXQ5PJV.jpg)

サービスマップ
進行度 &amp; ストレージ
Stats
数値を積む。クライアントは加算を送るだけ
Achievements
Stat のしきい値到達で自動解除、または直接解除
Leaderboards
グローバル / フレンド範囲のランキング
Player Data Storage
プレイヤーごとのセーブデータ（読み書き可）
Title Storage
開発側がアップロードする読み取り専用の設定 / データ
Title Storage のアップロードは Dev Portal 側 - アプリを更新せずに値を変えられます


# Page. 9

![Page Image](https://bcdn.docswell.com/page/GJ5MXRYPJ4.jpg)

導入事例
めっちゃカメレオン
いま挙げたサービスを、実際にこう使っている例です
約 34 万
2,000 万本 超
ピーク同時接続
Steam・2026 年 6 月
累計販売本数
発売 2 週間で 1,000 万本
実質 2 名 / 約 2 ヶ月
Connect, Lobby, P2P
開発規模
使用した EOS 機能
サーバーを増設せずに、アクセスの急増をそのまま吸収しました


# Page. 10

![Page Image](https://bcdn.docswell.com/page/LE3WXP56E5.jpg)

動いているところ
完成したものを、先に見てください
公式サンプルを 2 クライアントで起動した状態
1. 別々の EOS アカウント
DevAuthTool の dev1 / dev2 でログイン
2. 同じ Lobby に入っている
Lobbies が参加者を同期
3. P2P で直結
NAT 越えは EOS がやってくれる
4. 専用サーバーは 0 台
自前のホスティングなし


# Page. 11

![Page Image](https://bcdn.docswell.com/page/8EDK2LDM7G.jpg)

動いているところ
もう 1 人が、同じロビーに入ってくる
さきほどの画面が、どう動いていたのか - 実際のログで追えます
client1（host）- 部屋が無いので自分で作り、あとは待つだけ
client2（guest）- 探して、見つかったので入る
09:36:56
[FindSessions] Finding lobby.
09:37:59
[FindSessions] Finding lobby.
09:36:59
[CreateLobby] Creating lobby...
09:38:00
[HandleFindSessionsCompleted] Found lobby.
09:37:01
[HandleCreateLobbyCompleted] Lobby LobbyName created.
09:38:00
[JoinSession] Joining lobby.
09:38:01
[HandleParticipantJoined] Player joined lobby LobbyName.
09:38:02
[HandleJoinSessionCompleted] Joined lobby.
そのあと、両方のログに同じ 1 行 - 上が client2、下が client1（LocalUserId と RemoteUserId が逆になっているだけ）
09:38:06
Connection established. LocalUserId=[000...bdd] RemoteUserId=[000...475] ... NetworkType=[EOS_NCT_DirectConnection]
09:38:07
Connection established. LocalUserId=[000...475] RemoteUserId=[000...bdd] ... NetworkType=[EOS_NCT_DirectConnection]


# Page. 12

![Page Image](https://bcdn.docswell.com/page/V7PK12XQJ8.jpg)

動いているところ
実績が自動で解除される
ゲーム側に解除判定のコードはありません
1. ジャンプで Stat が増える
ゲームが送るのは「+1」だけ - コード 1 行
2. しきい値に到達すると解除
しきい値は Dev Portal 側で定義します
3. 解除の行はログに出ません
UpdateStat は失敗したときだけログを出します
ログに出るのは 「返ってきた側」 だけ - 集計も解除も、バックエンドの仕事です
09:36:56 LogEOSSDK:
LogEOSUI: Social Overlay: Achievements populated for (c4d...d1e).
09:39:03 LogEOSOSSTutorial: [HandleQueryLeaderboardComplete] Player Id: c4d8983a...|0002dd92..., Rank: 1
09:39:03 LogEOSOSSTutorial: [HandleQueryLeaderboardComplete] Player Id: 69330677...|00022998..., Rank: 2


# Page. 13

![Page Image](https://bcdn.docswell.com/page/2JVVYDLPJQ.jpg)

動いているところ
終了して再起動すると、位置が戻る
Player Data Storage によるクラウドセーブ
1. 終了時の位置を保存
ファイル名は CharacterPawnLocation - コードで指定します
2. 再起動後、同じ場所から
ローカルファイルではなくクラウドから読む
3. 別の PC でも同じ
同じアカウントなら進行度がついてくる
起動直後に読み、終了直前に書く - 実ログに出るのはこの 2 行です
09:36:55 LogEOSOSSTutorial: [HandleLoginCompleted] Loading cloud data and searching for a session...
09:42:53 LogEOSSDK:
LogEOSPlayerDataStorage: Promoted local scratch file to cache after successful upload to cloud storage.


# Page. 14

![Page Image](https://bcdn.docswell.com/page/5EGL9YXQJL.jpg)

Dev Portal
Product 一覧
EOS の設定は、すべてこの管理画面から行います
1. Organization を作り、その中に
Product を作ると出てくる画面です
2. Product = ゲーム 1 本。
この下に Client と Sandbox が並びます
まずは Product を 1 つ作るところから始まります


# Page. 15

![Page Image](https://bcdn.docswell.com/page/4JQYWM8W7P.jpg)

Dev Portal
Client の作成
Product の設定から Client と Client Policy を作ります
1. Client = ゲームビルドが EOS に
接続するときの資格です
（ClientId / ClientSecret）
2. Client Policy で機能を選びます
使う権限だけを入れるのがおすすめ
ClientSecret はリポジトリにコミットしないでください


# Page. 16

![Page Image](https://bcdn.docswell.com/page/K74WKV21E1.jpg)

Dev Portal
環境は、どう分けるのか
ini に書く SandboxId と DeploymentId - この 2 つは役割がまったく違います
1. Sandbox = 環境のティア
Product - ゲーム 1 本
Live / Stage / Dev の 3 つが並びますが、
EOS だけを使う製品で必要なのは Live
Sandbox ： Live
環境ティア。EGS の配信段階に紐づく単位
2. Stage / Dev は既定で無効
製品作成時に一緒に作られ、EGS の機能を
使い始めるまでボタンが押せません
Deployment ： dev
Deployment ： live
開発用データ（非公開）
本番データ
3. Deployment = データの隔離単位
開発用データは Deployment を追加して分けます
開発中は、どの Deployment に書き込んでいるかを必ず意識してください


# Page. 17

![Page Image](https://bcdn.docswell.com/page/LJ1YX3M5EG.jpg)

Dev Portal
Sandbox と Deployment
実際のポータル画面で確認します
1. Sandbox は Live / Stage / Dev の 3 つ 押せるのは Live の行だけです
2. Live の中に Deployment が 2 つ 開発用の dev と本番用の live
ini に書く SandboxId / DeploymentId は、この画面から取ります


# Page. 18

![Page Image](https://bcdn.docswell.com/page/GJWGNP3W72.jpg)

Dev Portal
Stat の定義
名前と集計方法を決めます
1. 例: NUMBEROFJUMPS を
SUM で定義
2. 集計方法は SUM / LATEST /
MIN / MAX の 4 つ 累計 / 最新値 / 自己ベスト
3. ゲーム側のコードには、
この名前しか出てきません
集計方法が SUM でないと、+1 を送り続けても値は 1 のままです


# Page. 19

![Page Image](https://bcdn.docswell.com/page/4EZL3KV273.jpg)

Dev Portal
Achievement の定義
Stat のしきい値と紐づけます
1. 解除条件をポータル側に持たせます
2. ゲーム側は Stat を送るだけで
よくなります
ここの設定 1 つが、ゲーム側のコードを 1 行消します


# Page. 20

![Page Image](https://bcdn.docswell.com/page/Y76WXQY67V.jpg)

どう使うか
EOS を UE から呼ぶ 3 つの経路
経路
状態
いまの様子
OnlineSubsystemEOS
安定
Lyra を含むサンプルと情報が多く、出荷実績も多い。今日の内容も
すべて OSSv1
OnlineServicesEOS
Beta
UE の新しいオンライン設計。プラグインはまだ Beta 扱い
EOS SDK を直接叩く
可能
UE のネットワークに乗らない特殊要件、非 UE との共通実装
OSSv1 / OSSv2 とも Blueprint 公開はありません - Blueprint から使いたい場合はサードパーティ製プラグインになりますが、そちらは
Epic のサポート対象外です
EOSPlus は UE 5.7 でエンジンから削除されました（移行先は EOS + NPI）。EOSPlus 前提の古い記事に注意してください。


# Page. 21

![Page Image](https://bcdn.docswell.com/page/G75MXRG574.jpg)

セットアップ
必要なのは 3 ファイルだけ
1.
2.
3.
.uproject
Build.cs
DefaultEngine.ini
プラグインを有効化する
依存モジュールを追加する
EOS の設定と資格情報を書く


# Page. 22

![Page Image](https://bcdn.docswell.com/page/9J29XDYGER.jpg)

セットアップ 1 / 3
.uproject - プラグインを有効化
EOS_OSS_Tutorial.uproject
&quot;Plugins&quot;: [
{ &quot;Name&quot;: &quot;OnlineSubsystemEOS&quot;, &quot;Enabled&quot;: true },
{ &quot;Name&quot;: &quot;EOSShared&quot;,
&quot;Enabled&quot;: true },
{ &quot;Name&quot;: &quot;VoiceChat&quot;,
&quot;Enabled&quot;: true },
{ &quot;Name&quot;: &quot;EOSVoiceChat&quot;,
&quot;Enabled&quot;: true }
]
手で書き足すのは、この 4 行だけ - OnlineSubsystemEOS と EOSShared、ボイスを使うなら残り 2 つ
VoiceChat / EOSVoiceChat - ボイスに必要。サンプルは EOSAntiCheat も有効化しています
エディタの Plugins 画面から入れても同じです


# Page. 23

![Page Image](https://bcdn.docswell.com/page/DEY482GGJM.jpg)

セットアップ 2 / 3
Build.cs - 依存モジュールと機能スイッチ
1. 公開依存 - OSS を呼ぶために必要
PublicDependencyModuleNames.AddRange(new string[] {
..., &quot;OnlineSubsystem&quot;, &quot;OnlineSubsystemUtils&quot;, &quot;OnlineSubsystemEOS&quot; });
2. 非公開依存 - ボイスと通信で使う
PrivateDependencyModuleNames.AddRange(new string[] {
&quot;VoiceChat&quot;, &quot;EOSVoiceChat&quot;, &quot;EOSShared&quot;, &quot;HTTP&quot;, &quot;Json&quot;, ... });
3. 機能スイッチ - サンプル固有。既定は両方 0
PrivateDefinitions.Add(&quot;P2PMODE=0&quot;);
PrivateDefinitions.Add(&quot;ACMODE=0&quot;);
// 1 にすると Lobby + P2P が有効
// 1 にすると Anti-Cheat が有効
P2PMODE=0 のままだとロビーのコードは丸ごとビルドされません


# Page. 24

![Page Image](https://bcdn.docswell.com/page/VJNYQ8G878.jpg)

セットアップ 3 / 3
DefaultEngine.ini - 4 ブロック
1. EOS を有効にして、既定のサービスにする
[OnlineSubsystemEOS]
bEnabled=true
[OnlineSubsystem]
DefaultPlatformService=EOS
2. NetDriver を差し替える - まず削除、そして追加
-NetDriverDefinitions=(DefName=&quot;GameNetDriver&quot;,
DriverClassName=&quot;/Script/OnlineSubsystemUtils.IpNetDriver&quot;, ...)
+NetDriverDefinitions=(DefName=&quot;GameNetDriver&quot;,
DriverClassName=&quot;/Script/SocketSubsystemEOS.NetDriverEOS&quot;, ...)
3. EOS の挙動設定
[/Script/OnlineSubsystemEOS.EOSSettings]
DefaultArtifactName=Client
bUseEAS=True
bUseEOSConnect=True
4. 資格情報 - Dev Portal からコピーして埋める
+Artifacts=(ArtifactName=&quot;Client&quot;, ClientId=&quot;&quot;, ClientSecret=&quot;&quot;,
ProductId=&quot;&quot;, SandboxId=&quot;&quot;, DeploymentId=&quot;&quot;, EncryptionKey=&quot;&quot;)


# Page. 25

![Page Image](https://bcdn.docswell.com/page/YE9PDKWXJ3.jpg)

セットアップ
Dev Portal の値と ini の対応
DefaultEngine.ini の項目
Dev Portal のどこから取るか
ProductId
Product 設定ページ
SandboxId
Sandbox 一覧 - Live / Stage / Dev
DeploymentId
その Sandbox 配下の Deployment - 開発用はここで分ける
ClientId
Client 作成時に発行
ClientSecret
Client 作成時に発行（再表示不可のものは再生成）
EncryptionKey
ポータルでは発行されません - 自分で生成する 64 桁の 16 進数
ここが 1 文字違うと EOS の初期化そのものが失敗します


# Page. 26

![Page Image](https://bcdn.docswell.com/page/GE8D3RN9ED.jpg)

核心
パターンは 1 つだけ
ログインでもロビーでも実績でもセーブでも、この 4 ステップです
1. インターフェースを取得する
IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
IOnlineXxxPtr Xxx = Subsystem ? Subsystem-&gt;GetXxxInterface() : nullptr;
2. 完了デリゲートをバインドする
XxxDelegateHandle = Xxx-&gt;AddOnXxxCompleteDelegate_Handle(
FOnXxxCompleteDelegate::CreateUObject(this, &amp;ThisClass::HandleXxxCompleted));
3. 非同期で呼び出す
if (!Xxx-&gt;Xxx(...)) { /* 同期的な失敗 -&gt; ハンドルをすぐ解放 */ }
4. コールバックで結果を処理し、ハンドルを解放する
void HandleXxxCompleted(bool bWasSuccessful, ...)
{
/* ... */
Xxx-&gt;ClearOnXxxCompleteDelegate_Handle(XxxDelegateHandle);
}


# Page. 27

![Page Image](https://bcdn.docswell.com/page/LELMVKPM7R.jpg)

核心
サンプルのコメントにも、そう書いてあります
&quot;All functions that access the OSS will have this structure: 1-Get OSS interface, 2-Bind delegate for callback
and 3-Call OSS interface function ...&quot;
- EOSPlayerController.cpp:345
2 番目の Bind delegate だけ、渡し方が 2 通りあります
Add / Clear ...Delegate_Handle 型
先に登録してハンドルを保管し、コールバックで解放します - ログイン、セッション、ファイル書き込みなど
呼び出しの引数で渡す型（per-call）
登録も解放も要りません - UpdateStats / WriteAchievements / ReadFriendsList / SetPresence / QueryReceipts / Checkout など
どちらの型かは、インターフェースのヘッダで引数を見れば分かります


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4JMYG246JW.jpg)

モジュール 1
ログイン - EAS と EOS Connect
Epic Account Services
EOS Connect
・Epic アカウントでのログイン
・Steam / コンソール / Device ID を束ねる
・フレンド、プレゼンス、オーバーレイ
・1 人 = 1 つの PUID になります
・Epic のソーシャル機能が使えます
・ゲーム機能（Lobby / Stats 等）の主体
PUID (Product User Id) = EOS の中でのプレイヤー ID。P2P の接続先アドレスにもこの ID を使います


# Page. 29

![Page Image](https://bcdn.docswell.com/page/PJR9ZMWN79.jpg)

モジュール 1
ログイン - 呼ぶ側
1. インターフェースを取得
IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
IOnlineIdentityPtr Identity = Subsystem-&gt;GetIdentityInterface();
2. 完了デリゲートをバインド
LoginDelegateHandle = Identity-&gt;AddOnLoginCompleteDelegate_Handle(
0, FOnLoginCompleteDelegate::CreateUObject(
this, &amp;ThisClass::HandleLoginCompleted));
3. 非同期で呼び出す
// 起動引数（-AUTH_TYPE=... ）を見て自動でログインしてくれる
if (!Identity-&gt;AutoLogin(0)) { /* 失敗 -&gt; ハンドル解放 */ }
AutoLogin は非同期です。この直後はまだログインしていません


# Page. 30

![Page Image](https://bcdn.docswell.com/page/PEXQ9VP8JX.jpg)

モジュール 1
ログイン - 受け取る側
EOSPlayerController.cpp:391
void AEOSPlayerController::HandleLoginCompleted(
int32 LocalUserNum, bool bWasSuccessful,
const FUniqueNetId&amp; UserId, const FString&amp; Error)
{
if (bWasSuccessful)
{
// ここから先で、やっと他の EOS 機能を呼べる
SetupNotifications();
}
// 4. 成否にかかわらずハンドルを解放する
Identity-&gt;ClearOnLoginCompleteDelegate_Handle(0, LoginDelegateHandle);
}
すべての EOS 機能は、ここが成功してから始めます


# Page. 31

![Page Image](https://bcdn.docswell.com/page/3EK9PQDLED.jpg)

モジュール 1
開発中のログイン - DevAuthTool
1. Epic アカウントで一度ログインする
2. Credential Name を付けて保存
（dev1 / dev2）
3. エディタ側は起動引数で
その名前を指定する
エディタ / クライアントの起動引数
-AUTH_TYPE=developer -AUTH_LOGIN=localhost:8081 -AUTH_PASSWORD=dev1


# Page. 32

![Page Image](https://bcdn.docswell.com/page/L73WXPR675.jpg)

モジュール 1
DevAuthTool は何を代行しているか
代行するのは認証だけです - Artifact の指定は自分で書きます
出荷（EGS 経由）
開発中（DevAuthTool）
認証
-AUTH_TYPE=exchangecode - Launcher が渡す
-AUTH_TYPE=developer - ツールが代行
Artifact
-epicapp - Launcher が渡す
-epicapp - 代行なし。自分で書く
1. credential 1 個 = Epic アカウント 1 個
ローカルで 2 人分を検証するには、別の Epic アカウントを 2 つ用意します
2. 起動引数はプロセスごとに 1 つ
ウィンドウを 2 つではなく、プロセスを 2 つ立ち上げます
3. ツールなしでも動きます
bPreferPersistentAuth=True なら初回だけブラウザ認証 - 1 人で確認するならこれで十分です


# Page. 33

![Page Image](https://bcdn.docswell.com/page/87DK2LYMJG.jpg)

動きを読む
コードとログを対応させる - ホスト側
右の列は実ログからの引用です（LogEOSOSSTutorial=VeryVerbose 設定済み）
コード
実際に出るログ
Identity-&gt;AutoLogin(0)
[Login] Logging into EOS via AutoLogin.
HandleLoginCompleted
[HandleLoginCompleted] Login succeeded - Player
c4d8983a...|0002dd92...
Session-&gt;FindSessions(0, Search)
[FindSessions] Finding lobby.
検索結果 0 件 -&gt; CreateLobby()
（ログなし - ここで作成側に分岐します）
Session-&gt;CreateSession(...)
[CreateLobby] Creating lobby...
HandleCreateLobbyCompleted
[HandleCreateLobbyCompleted] Lobby LobbyName created.
ゲスト側は 4 行目から先が JoinSession -&gt; ClientTravel に変わるだけです


# Page. 34

![Page Image](https://bcdn.docswell.com/page/VJPK126QE8.jpg)

動きを読む
参加・退出はホストに通知される
バインドするデリゲート
実際に出るログ
AddOnSessionParticipantJoinedDelegate_Handle
[HandleParticipantJoined] Player joined lobby LobbyName.
AddOnSessionParticipantLeftDelegate_Handle
[HandleParticipantLeft] Player left lobby LobbyName.
ポーリングは不要 - バックエンドから push されます。参加者リストの UI はこれで更新します
登録はログイン成功後 - HandleLoginCompleted の中でバインドします
解放を忘れない - EndPlay で Clear...Delegate_Handle を呼びます


# Page. 35

![Page Image](https://bcdn.docswell.com/page/2EVVYD3PEQ.jpg)

モジュール 2
Stats - 数値を積む
1. インターフェースを取得
IOnlineStatsPtr Stats = Subsystem-&gt;GetStatsInterface();
2. 更新内容を組み立てる
FOnlineStatsUserUpdatedStats UpdatedStats{ UserId.ToSharedRef() };
UpdatedStats.Stats.Add(&quot;NUMBEROFJUMPS&quot;,
FOnlineStatUpdate{ 1, ...::Unknown });
// 集計方法は Dev Portal 側
3. 呼び出す - ここは型の「例外」でコールバックを直接渡す
Stats-&gt;UpdateStats(UserId.AsShared(), { UpdatedStats },
FOnlineStatsUpdateStatsComplete::CreateWeakLambda(this,
[this](const FOnlineError&amp; Result) { /* ... */ }));
クライアントが送るのは「+1」だけ。判定はバックエンドです


# Page. 36

![Page Image](https://bcdn.docswell.com/page/57GL9Y3QEL.jpg)

モジュール 2
Achievements - 自動解除と直接解除
EOSPlayerState.cpp:164 付近
IOnlineAchievementsPtr Achievements = Subsystem-&gt;GetAchievementsInterface();
// 直接解除する場合 - Properties の「キー」だけが ID として使われる
FOnlineAchievementsWriteRef WriteObject =
MakeShared&lt;FOnlineAchievementsWrite, ESPMode::ThreadSafe&gt;();
WriteObject-&gt;Properties.Add(AchievementId, FVariantData());
// 値は未使用
Achievements-&gt;WriteAchievements(*UserId, WriteObject,
FOnAchievementsWrittenDelegate::CreateUObject(
this, &amp;ThisClass::HandleAchievementsWritten));
自動解除 - Dev Portal で Stat のしきい値を設定しておけば、ゲーム側の解除コードは不要
直接解除 - ストーリー進行など、Stat で表せない条件のときに使う


# Page. 37

![Page Image](https://bcdn.docswell.com/page/4EQYWM5WJP.jpg)

モジュール 2
Leaderboards - グローバルとフレンド
1. グローバル - 順位の範囲で取る
IOnlineLeaderboardsPtr Leaderboards = Subsystem-&gt;GetLeaderboardsInterface();
FOnlineLeaderboardReadRef ReadRef(new FOnlineLeaderboardRead());
ReadRef-&gt;LeaderboardName = &quot;JUMPERLEADERBOARD&quot;;
Leaderboards-&gt;ReadLeaderboardsAroundRank(0, 10, ReadRef);
// 上位 10 件
2. フレンド範囲 - 対象ユーザーの配列を渡す
Leaderboards-&gt;ReadLeaderboards(FriendUserIds, ReadRef);
// ReadLeaderboardsForFriends() は UE 5.8 では使えません（後述）
Stats -&gt; Achievements -&gt; Leaderboards は 1 セットで設計します


# Page. 38

![Page Image](https://bcdn.docswell.com/page/KJ4WKV9171.jpg)

モジュール 4
ロビーを作る
1. インターフェースを取得してデリゲートをバインド
IOnlineSessionPtr Session = Subsystem-&gt;GetSessionInterface();
CreateLobbyDelegateHandle = Session-&gt;AddOnCreateSessionCompleteDelegate_Handle(
FOnCreateSessionCompleteDelegate::CreateUObject(
this, &amp;ThisClass::HandleCreateLobbyCompleted));
2. 設定を組み立てる（次のスライドで詳しく）
TSharedRef&lt;FOnlineSessionSettings&gt; Settings = MakeShared&lt;FOnlineSessionSettings&gt;();
Settings-&gt;NumPublicConnections = 3;
Settings-&gt;bShouldAdvertise
= true;
3. 呼び出す
if (!Session-&gt;CreateSession(0, LobbyName, *Settings)) { /* 失敗時の解放 */ }
「Session」インターフェースでロビーを作ります - 名前に注意


# Page. 39

![Page Image](https://bcdn.docswell.com/page/LE1YX3K57G.jpg)

モジュール 4
この 4 行が、ロビーの性格を決めます
CreateLobby() の中の設定
Settings-&gt;bIsDedicated
= false;
Settings-&gt;bUseLobbiesIfAvailable
= true;
Settings-&gt;bUseLobbiesVoiceChatIfAvailable = true;
Settings-&gt;bUsesPresence
= true;
// Session ではなく Lobby になる
// ボイスも有効になる（今日は扱いません）
// フレンドから参加できる
bUseLobbiesIfAvailable - 同じ API で、裏側が Sessions から Lobbies に切り替わります
bUsesPresence - フレンドリストやオーバーレイから、そのまま参加できるようになります
専用サーバーを使うかどうかも、1 行目のフラグ 1 つです


# Page. 40

![Page Image](https://bcdn.docswell.com/page/GEWGNPDWJ2.jpg)

モジュール 4
探して、入って、繋がる
1. 接続文字列を解決する
FString ConnectString;
Session-&gt;GetResolvedConnectString(SearchResult, NAME_GamePort, ConnectString);
2. 検索結果は「値コピー」で保持する
// 参照で持つとダングリングする - ハマりやすい箇所
SessionToJoin = SearchResult;
3. ClientTravel - 宛先は IP:Port ではなく PUID
ClientTravel(ConnectString, ETravelType::TRAVEL_Absolute);
09:38:02 LogNet:
Browse: EOS:0002dd92.../Game/ThirdPerson/Maps/ThirdPersonMap
09:38:06 LogEOSP2P:
Connection established. NetworkType=[EOS_NCT_DirectConnection]


# Page. 41

![Page Image](https://bcdn.docswell.com/page/47ZL3KG2J3.jpg)

モジュール 6
フレンドとプレゼンス
1. フレンド一覧を読む - 型は同じ
IOnlineFriendsPtr Friends = Subsystem-&gt;GetFriendsInterface();
Friends-&gt;ReadFriendsList(0, EFriendsLists::ToString(EFriendsLists::Default),
FOnReadFriendsListComplete::CreateUObject(this, &amp;ThisClass::HandleRead));
// コールバックが返ってから GetFriendsList() で取り出す
2. 自分の状態を公開する
FOnlineUserPresenceStatus Status;
Status.State
= EOnlinePresenceState::Online;
Status.StatusStr = TEXT(&quot;ThirdPersonMap で対戦中&quot;);
Presence-&gt;SetPresence(*UserId, Status, /* 完了デリゲート */);
フレンドリーダーボードは、この一覧をそのまま土台にしています


# Page. 42

![Page Image](https://bcdn.docswell.com/page/YJ6WXQQ6JV.jpg)

モジュール 6
ソーシャルオーバーレイ - 開くのは 1 行
1. フレンド一覧とオンライン状態
UI は EOS 側が持っています ゲーム側の実装は 0 行
2. ゲームへの招待をここから送る
招待は EOS 側が送ります ゲームから送るなら SendSessionInviteToFriend
3. 受け取った側は、そのままロビーへ
OnSessionUserInviteAccepted -&gt; JoinSession
External-&gt;ShowFriendsUI(0);
- オーバーレイを出すコードは、これだけです


# Page. 43

![Page Image](https://bcdn.docswell.com/page/GJ5MXRR5J4.jpg)

モジュール 7
Title Storage - 配信後に値を変える
LoadTitleData() - EOSPlayerController.cpp:1722
IOnlineTitleFilePtr TitleFile = Subsystem-&gt;GetTitleFileInterface();
// 1. まずファイル一覧を列挙する
TitleFile-&gt;EnumerateFiles();
// 2. 一覧が返ってきたら、必要なファイルを読む
TitleFile-&gt;ReadFile(FileName);
読み取り専用 - 開発側が Dev Portal からアップロードします
使いどころ - イベント日程、バランス調整値、緊急のお知らせ
タグを一致させる - ini の +TitleStorageTags と Dev Portal 側のタグを揃えます


# Page. 44

![Page Image](https://bcdn.docswell.com/page/9E29XDDG7R.jpg)

モジュール 7
Player Data Storage - クラウドセーブ
1. 保存 - 位置をシリアライズして書き込む
IOnlineUserCloudPtr UserCloud = Subsystem-&gt;GetUserCloudInterface();
TArray&lt;uint8&gt; Data; FMemoryWriter Writer(Data);
Writer &lt;&lt; Location;
UserCloud-&gt;WriteUserFile(*UserId, FileName, Data);
2. 読み込み - Title Storage と同じ「列挙 -&gt; 読む」
UserCloud-&gt;EnumerateUserFiles(*UserId);
// まず一覧
UserCloud-&gt;ReadUserFile(*UserId, FileName);
// コールバックの後で GetFileContents() を呼ぶ
UserCloud-&gt;GetFileContents(*UserId, FileName, LoadData);
サンプルは FVector 1 つだけを保存しています。実際のゲームでは USaveGame 派生クラスを使ってください。


# Page. 45

![Page Image](https://bcdn.docswell.com/page/D7Y4822GEM.jpg)

まとめ
ここまでが、サンプルで動かせる範囲です
ロビーを作って、参加して、
同じマップで合流する
フレンド一覧とゲームへの招待
（オーバーレイ）
Stat の加算から実績が
自動で解除される
同じリポジトリに、今日触れなかったものも入っています
Ecom（ストアと購入） / Sessions（専用サーバー） / プレイヤー通報 /
制裁の照会 / Easy Anti-Cheat / 専用サーバーのボイス
書き方はどれも同じです。今日の型が、そのまま読む手がかりになります
終了時の位置がクラウドに残り、
次の起動で戻る


# Page. 46

![Page Image](https://bcdn.docswell.com/page/VENYQ888J8.jpg)

まとめ
よく詰まるところ 1〜3
1. ログインのコールバック前に EOS を呼んでしまう
原因 - AutoLogin は非同期です。HandleLoginCompleted が成功してから始めてください
対処 - GetLoginStatus(0) == ELoginStatus::LoggedIn で守る
2. DefaultEngine.ini の Artifacts が空のまま
原因 - リポジトリにコミットされている値は全部空文字です
対処 - Dev Portal から 6 項目をコピー。DefaultArtifactName と名前を一致させる
3. NetDriver の差し替えを「+」だけで済ませてしまう
原因 - BaseEngine.ini の IpNetDriver が先にマッチします（first-match）
対処 - 必ず「-」で削除してから「+」で追加する


# Page. 47

![Page Image](https://bcdn.docswell.com/page/Y79PDKKXE3.jpg)

まとめ
よく詰まるところ 4〜5
4. ロビーのコードが丸ごとビルドされない
原因 - Build.cs の P2PMODE が既定で 0 になっています
対処 - P2PMODE=1 にしてリビルド。ACMODE とは独立です
5. オーバーレイ関連がエディタで動かない
原因 - EOS オーバーレイは PIE では制限があります
対処 - Ecom のチェックアウトなどはパッケージ済み Win64 クライアントで検証する
この 6 項目は 1 枚のチェックリストとして配布します。セットアップで止まったら、まずここを見てください。


# Page. 48

![Page Image](https://bcdn.docswell.com/page/G78D3RR97D.jpg)

まとめ
よく詰まるところ 6 - Policy にない機能は呼べない
6. 起動しただけで赤い 403 のエラーが数行出る
原因 - Client Policy に ecommerce の権限が入っていないので、バックエンドが呼び出しを拒否しています
対処 - 使う機能なら Dev Portal で権限を追加。使わない機能なら、このエラーは無視して構いません
Ecom を使わない設定のまま起動したときの実ログ
09:36:55 LogEOSSDK: Warning:
Error response received from backend. ServiceName=[Ecommerce],
OperationName=[GetOffersForEpicAccount], Url=[&lt;Redacted&gt;], HttpStatus=[403], ...
ErrorMessage=[Sorry, it appears that your client is missing the required
[ecommerce] policy to call this API.], ...
09:36:55 LogOnline: Error:
EOS: [FOnlineStoreEOSV2::QueryOffers] result code (EOS_AccessDenied)
09:36:55 LogEOSOSSTutorial: Error: [HandleQueryStoreOffersCompleted] Failed: result code (EOS_AccessDenied)
バックエンドのエラーは ServiceName と ErrorMessage だけ読めば原因が分かります


# Page. 49

![Page Image](https://bcdn.docswell.com/page/L7LMVKKMJR.jpg)

まとめ
ここから始められます
写真を撮る時間を取ります
公式サンプル
github.com/EpicGames/EOS-Getting-Started
今日見たコードは、すべてこのリポジトリの中にあります
EOS ドキュメント
dev.epicgames.com/docs/epic-online-services
サービスごとの解説とインターフェース仕様
Dev Portal
dev.epicgames.com/portal
Product / Client / Sandbox の作成と、実績・統計の定義
EOS Status
status.epicgames.com
「急に繋がらない」ときに、まずここを見てください


# Page. 50

![Page Image](https://bcdn.docswell.com/page/4EMYG226EW.jpg)

Thank you
ご清聴ありがとうございました


