Steam アカウントでの EOS へのログイン方法

# 記事概要
Epic Online Services (EOS) を Steam からも使ってみたいけど、ドキュメントが少なくて開発が難しいという声を最近良く聞きます。

これまで、EOS の使い方の記事を2本ほど ([記事1](https://qiita.com/EGJ-Daiki_Terauchi/items/e23b2c60738df13d34c3), [記事2](https://qiita.com/EGJ-Daiki_Terauchi/items/b81eed48bbbe969b28a4))書いてきましたが、どちらも Epic アカウントの利用が前提でした。

今回は UE から Steam アカウントを使ってEOS を利用する方法を紹介します。


## 目的
- Steam アカウントを使って UE から EOS の[ゲームサービス](https://dev.epicgames.com/docs/ja/game-services)を利用できるようにする

## 方針
- 利用するアカウントシステムは Steam アカウントのみ
- OnlineSubsystem (OSS) を利用する (OnlineSubsystemSteam + OnlineSubsystemEOS)

## 前提条件
- Steam ランチャーがインストールされている
- Steam アカウントを所持している
- SteamWorks 上でアプリが作成済み
- UE5.2 がインストール済み

# EOS 側の設定
1. [Developer Protal](https://dev.epicgames.com/portal/ja/) にログインし、自分の組織以下に新しい製品を作成します。(本記事では "SteamEOSLogin" という名前を使っています)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/7f0fba88-bc0b-1342-a0a4-12f36fbef2c0.png)
2. 製品の作成が完了したら、製品の詳細画面から「製品設定」=>「クライアント」タブを開き、新規にクライアントポリシーとクライアントを作成します。
   クライアントポリシーの種類は、自分の作りたいゲームに合わせて適切に設定してください。今回のサンプルでは "Peer2Peer" でOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/a1ff92fd-49a6-955c-aa96-b2f9f6af11a9.png)
2. 次に "IDプロバイダ" タブを開き、Steam用の IDプロバイダを追加します。
    このとき、"SteamNetworkingIdentity" の値は SteamWorks 1.57 以降のバージョンで利用する値ですが、UE5.2 ではそれより古いバージョンのみをサポートしているため、今回はこちらの値を削除し、空の状態で登録してください。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/af636157-e736-25d8-76a4-3e0bd3d2d1f8.png)

2. "製品設定" => "サンドボックス" => "IDプロバイダ" から、前段で作成した Steam の ID プロバイダをサンドボックスに紐づけます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/c765ffc1-6232-33b2-c529-aa3addbd1f3a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/a21e0a17-850a-66eb-3b7b-d3308a9a6a81.png)

ここまでで EOS 側の設定は完了です。
今回は、Epic アカウントを利用しないので、Epic Account Service の設定は不要となります。

## OnlineSubsystem EOS と EOSPlus について
今回のサンプル実装では、EOS と Steam 両方の OSS を併用します。
このように、EOS と その他のプラットフォームの OSS を同時に利用する場合、EOS 側の OSS として EOSPlus を利用します。

EOSPlus は他の OSS と同様のインタフェースを提供しますが、内部の実装としては EOS の OSS と 各プラットフォームのOSS をうまく連携させて、EOS 上のデータ (プレゼンス、ゲームセッション、統計、etc) をプラットフォームシステム上に同期させる、OSS のラッパーとして動作します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/c41967aa-3d0b-0c13-c7b1-a7769b122347.png)

今回のサンプルでは Login() を呼び出すと、EOS Plus の内部では
1. OnlineSubsystemSteam を利用してログイン用のトークンを取得
1. 取得したトークンを使って OnlineSubsystemEOS の Login 処理を実行する

という形となっています。


# OnlineSubsystem の設定
OSS EOSPlus を Default Platform Service、OSS Steam を Native Platform Service として設定します。

今回は、サードパーソンテンプレートを使用します。新規プロジェクトを作成後、プラグインの設定からOnline Subsystem EOS, Online Subsystem Steam の両方を有効化してください。

1. OSS EOS を利用するには、プロジェクト設定から前の手順で作成した Client ID など各種値を設定する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/b34cdce5-d444-ee48-db38-fc700dbca327.png)
    * 今回は Epic アカウントを利用しないため "Use Epic Account for EOS login" からチェックを外し、"Use EOS Connect APIs to create and link Product User IDs" にチェックを入れてください

1. DefaultEngine.ini ファイルに設定を追加していきます。 
* デフォルトで利用するOSS とネイティブプラットフォーム (今回は Steam) にアクセスするために利用する OSS を指定
```
[OnlineSubsystem]
DefaultPlatformService=EOSPlus
NativePlatformService=Steam
```
* OSS EOS 及び OSS EOS Plus を有効化
```
[OnlineSubsystemEOS]
bEnabled=true

[OnlineSubsystemEOSPlus]
bEnabled=true
```
* OSS Steam の有効化及び App ID を指定
```
[OnlineSubsystemSteam]
bEnabled=true
SteamDevAppId=XXXX
```
* バックエンドシステムとして EOS を利用するため、ネットドライバをEOS のものを利用するように指定
```
[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemEOS.NetDriverEOS",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

[/Script/OnlineSubsystemEOS.NetDriverEOS]
bIsUsingP2PSockets=true
```
* (今回は不要ですが) OSS EOS を利用するApp と OSS EOS Plus を利用する App 同士で通信出来るように設定を追加 
```
[/Script/OnlineSubsystemUtils.OnlineEngineInterfaceImpl]
!CompatibleUniqueNetIdTypes=ClearArray
+CompatibleUniqueNetIdTypes=EOS
+CompatibleUniqueNetIdTypes=EOSPlus
MappedUniqueNetIdTypes=(("EOS","EOSPlus"))
```

# ログイン及びセッション作成/参加の実装
[こちら](https://qiita.com/EGJ-Daiki_Terauchi/items/e23b2c60738df13d34c3#oss-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E5%AE%9F%E8%A3%85)の記事と同様の機能を実装したものが、以下のGitHub レポジトリにおいてあります
https://github.com/uguisuan/UE5_EOSwithSteamAccount
* キー入力イベントを取得する方法が若干変わっており、[Enhanced Input](https://docs.unrealengine.com/5.2/ja/enhanced-input-in-unreal-engine/) を利用した形となっています
*  AMyPlayerController::Login() の実装で、IOnlineIdentity::AutoLogin() は利用せず、代わりに IOnlineIdentity::Login() を利用してください

```C++:AMyPlayerController.cpp
void AMyPlayerController::Login()
{
...
	int ControllerId = LP->GetControllerId();
	if (Identity->GetLoginStatus(ControllerId) != ELoginStatus::LoggedIn)
	{
		// Login処理後に呼び出されるコールバックを登録
		Identity->AddOnLoginCompleteDelegate_Handle(ControllerId, FOnLoginCompleteDelegate::CreateUObject(this, &AMyPlayerController::OnLoginCompleteConstruct));
		// 起動引数から認証情報を取得してログインする
        // Credentials は不要
		Identity->Login(ControllerId, {}); 
	}
...
}
```

# ゲーム起動
以上で各種設定が完了です。
PIE では EOS SDK が正しく動作しないため、スタンドアローンモードでゲームを起動してください。

ゲーム起動後右下にSteam のポップアップが表示されたら Steam アカウントでのログインが完了しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571320/305f94ce-f93d-79ac-d7cd-5b8d952fdd99.png)

キーボードの"L"を押下すると Steam アカウントを利用して EOS へのログインを実行します。
EOS へのログイン完了後、以下の処理が実行可能です。

* "H": セッションをホストする
* "F": セッションを検索して、見つかれば参加する
* "K": 参加中のセッションを削除する

なお、Steam クライアントが起動していないと Steam 用の認証トークンが取得できずエラーとなりますので、必ずSteam クライアントを起動している状態でゲームを実行してください。

下記GitHub レポジトリに今回作成したサンプルプロジェクトをおいてあります。
各種IDなどはダミー値を設定してありますので、ご利用の際は適切な値を設定してください。
https://github.com/uguisuan/UE5_EOSwithSteamAccount