LucifeP(ルシフェP)の日記

Unityでゲームつくっている人です。

Epic Online Services(EOS) + Mirror を使ったUnityゲーム開発【Part2】

Part1ではEpic Online Services(以下、EOS)によるログイン処理まで実装出来ました。
Part2ではEOS + Mirrorによるルームの入室の実装を行います。


Part1はこちらです。

lucifep-angel.hatenablog.com


1. NetworkManager設定

前回、ログイン後に0002_Sample_Homeシーンに遷移するように実装しました。
このシーンでルームの作成ルームへの入室を行えるようにします。

NetworkManager

ルームに関する機能を実装するためには、MirrorのNetworkManagerクラスを配置する必要があります。
そのままNetworkManagerをアタッチした空のオブジェクトを作成してもよいですが、後々拡張すると思いますので新しく継承したクラスCustomNetworkManagerを作っておくことにします。

using System.Collections;
using System.Collections.Generic;
using Mirror;
using UnityEngine;

public class CustomNetworkManager : NetworkManager
{

}

空のオブジェクトを作成してアタッチします。

アタッチしたら以下に従って設定します。

  • DontDestroyOnLoadにチェック
  • OfflineSceneには0002_Sample_Homeをセット
  • Online Sceneには新しく0003_Sample_Onlineシーンを作成してセットしておきます


EosTransport

EosTransportはEpicOnlineTransportで実装されたクラスです。
Mirrorで使用するTransportをこれに置き換えることでEOSのP2Pを使用することが出来るようになります。

NetworkManagerをアタッチしたオブジェクトに、EosTransportもアタッチしておきます。


EosLobbyUI

EOSのルーム機能を使用するためにEOSLobbyクラスを使います。
テスト用にEOSLobbyを継承して、GUIによる操作を追加してくれているEOSLobbyUIクラスがありますので、今回はこちらを使います。

空のオブジェクトを作成してアタッチします。

実際にゲームを作り始める際は、EOSLobbyUIクラスを参考に独自のクラスをつくると良いと思います。

Memo ここまでで、MirrorによるNetworkManagerとEOSLobbyクラスの機能が重複しているようにみえてくると思います。
実はEOSLobbyの内部では、内部でMirrorのStartHostあるいはStartClientを呼び出すようにつくられて、Mirrorを利用する形で実装されています。
EOSのルーム機能を使用せずMirrorだけで良いのでは?と私は一瞬考えてしまいましたが、EOSのP2P機能を使用するためにEOSのルームに入室する必要があるのだと思います。
そのため、内部的にはMirrorのルームとEOSのルームの2つに入室しています。退室処理の実装には注意が必要です。
(※EOS公式ではルームではなくロビーという言葉が用いられます。)


GamePlayer

NetworkManagerのPlayerPrefabにNetworkBehaviourのゲームオブジェクトをセットする必要があります。
各プレイヤーが動かすプレイヤー自身のゲームオブジェクトだと捉えていただいて問題ないです。

NetworkBehaviourであれば何でも構いませんが、ちょうどMirrorのサンプル実装に使い勝手の良いゲームオブジェクトが実装されていますのでそれを使います。

Projectの検索窓にGamePlayerと検索して、そのゲームオブジェクトをPlayerPrefabにセットします。


最終的に、以下のような状態になればOKです。


2. オンラインシーン設定

空のシーンでも問題ありませんが、シーン遷移してきたときにGamePlayerが落下してしまうので床をつくっておきます。
適当にPlaneを作成して、Positionは(0, 0, 0)にしておきます。


3. 実際にルーム作成してみる

0001_Sample_Loginから開始して、ログインに成功して0002_Sample_Homeシーンに遷移するとGUIが表示されます。

Create Lobbyをクリックすると、ルームを作成して、ホスト兼クライアントとして入室します。
入室に成功すると、0003_Sample_Onlineシーンに遷移して、カプセルのオブジェクトが生成されます。


4. マルチプレイ

ここまで出来たら、ビルドしてマルチプレイのテストをしてみましょう。

Windows向けにビルドしたら、exeを実行して立ち上げます。

同一PCで複数のクライアントでEOSにログインするには3つの方法があります。

  • EpicGamesアカウント等を使うアカウント認証
  • バイスIDを使う認証
  • DevAuthToolを使う認証 (デバッグ専用)

これらについてはPart1で説明していますので詳しくはそちらを参照ください。

今回はデバイスIDを使う認証で進めます。

ルーム作成と入室

1つ目のクライアントはこれまでどおり普通にログインして、ルーム作成まで進めてください。

2つ目のクライアントでは、ログイン前にReCreateDeviceIDにチェックを入れてログインします。
バイスID情報は複数保持することが出来ないため、一度削除して再生成することで複数クライアントのログインを通しています。

本格的に実装を進める際はDevAuthToolを使う認証 (デバッグ専用) をおすすめします。

2つ目のクライアントでログイン出来たら、今度はFind Lobbiesをクリックします。
しばらくすると、下記画像のように存在するルーム一覧と入室のためのJoinボタンが表示されます。

1つ目のクライアントで作成したルーム名であることと、PlayerCountが0でないことを確認してJoinをクリックして入室します。

GamePlayerオブジェクトが2つ表示されていれば成功です。





次回はEOSのバージョンを1.14.2から1.15.4にアップデートします。

【Unity】インスペクターに変数の検索窓を追加するエディタ拡張

Unityのインスペクターに検索窓を追加するエディタ拡張を作成しました。
変数をたくさん持つScriptableObjectから必要な変数を探すのに便利です。



1. スクリプト

検索窓を追加するエディタ拡張スクリプトです。

実際に使用する際は[CustomEditor(typeof(GameData))]GameDataを任意のクラス名に置き換えてください。
また、ビルド時のエラーや容量増加を防ぐためにEditorフォルダ下に配置してください。

using UnityEngine;
using UnityEditor;

namespace Sakineko
{
    [CustomEditor(typeof(GameData))]
    public classGameDataEditor : Editor
    {
        private string search = "";
        private bool clearClicked;   // 検索窓をクリア
        private bool isReturnFocus;  // 少し遅らせてフォーカスを検索窓に戻す

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            using (new EditorGUILayout.HorizontalScope())
            {
                EditorGUILayout.LabelField("Search");

                // アイコン
                var image = EditorGUIUtility.IconContent("Search On Icon").image;
                EditorGUILayout.LabelField(new GUIContent(image), GUILayout.Height(16), GUILayout.Width(16));

                //フォーカス戻すためコントロールに名前付け
                GUI.SetNextControlName("Search");
                search = EditorGUILayout.TextField(search);

                // フォーカスを検索窓に戻す
                // (1)フォーカスを外す (2)フォーカスを戻す で2回更新する必要があるので戻す処理を遅らせる
                if (isReturnFocus)
                {
                    GUI.FocusControl("Search");
                    isReturnFocus = false;
                }
                if (clearClicked)
                {
                    isReturnFocus = true;
                }

                // Clearボタン
                clearClicked = GUILayout.Button("Clear");
                if (clearClicked)
                {
                    search = "";

                    //フォーカスを外さないと入力が残ったように見える
                    GUI.FocusControl("");
                }
            }

            EditorGUILayout.Space();

            //検索なし
            if (search == "")
            {
                base.OnInspectorGUI();
            }
            //検索あり
            else
            {
                var iter = serializedObject.GetIterator();

                iter.NextVisible(true);
                using (new EditorGUI.DisabledScope(true))
                {
                    EditorGUILayout.PropertyField(iter, true);
                }

                while (iter.NextVisible(true))
                {
                    // 大文字・小文字を区別しない
                    if (!iter.name.ToLower().Contains(search))
                    {
                        continue;
                    }

                    EditorGUILayout.PropertyField(iter, true);
                }
            }

            serializedObject.ApplyModifiedProperties();
        }
    }
}


2. 使い方

以下のようにGameDataというScriptableObjectを継承したクラスがあった場合を想定します。

using UnityEngine;

namespace Sakineko
{
    [CreateAssetMenu(fileName = "GameDataSO", menuName = "ScriptableObjects/GameDataSO")]
    public class GameData : ScriptableObject
    {
        public int a;
        public int b;
        public int c;
        public int d;
        public int e;
    }
}


一番上に検索窓が追加されています。

検索対象の文字列を含む変数のみがインスペクター上に表示されます。

別のGitHubアカウントのリモートレポジトリへプレイベートレポジトリをプッシュする方法

Git初心者なので間違いあるかもですが、備忘録です。
自分用のメモを兼ねているので冗長ですが丁寧に手順を追っていきます。


はじめに

個人アカウントのプライベートレポジトリを訳あって、社内で共有したいということがありました。
レポジトリ内部には公開できない内容も含まれているためパブリックにするわけにはいかず、コミット履歴も含みたいため社内で新規レポジトリとして作成するのも候補から外れました。
社内全体で共有したかったため、Collaboratorsも選択肢から外れました。

ローカルレポジトリから新たにリモートレポジトリを作成して、別アカウントのリモートレポジトリへプッシュする方法を知り、この方法で解決しました。

以下では2つのGitHubアカウントを個人アカウント社内アカウントとして説明を続けます。


動作環境



1. SSHキーを個人アカウントに登録

社内PCから個人アカウントにアクセスできるようにSSHキーを登録します。

.sshフォルダへ移動

C:\Users\[ここはユーザー名]\.sshに移動します。
.sshフォルダが無ければ作成します。

SSHキーを作成

コマンドプロンプトを起動して、以下のコードでSSHキーを作成します。
file_nameには任意のファイル名を入力します。

ssh-keygen -t rsa -f file_name

パスワードの設定を促されるためEnterキーを2度押して、作成を完了させます。
例えば、file_nameをhome_keyとした場合は以下の2つのファイルが作成されます。

  • home_key
  • home_key.pub


公開鍵のhome_key.pubテキストエディタで開いて、Ctrl + Aで全選択してコピーしてGitHubに登録します。

GitHubページでのSSHキー登録先は以下の手順で辿り着けます。
1. GitHubページ右上のアイコンをクリック
2. Settings
3. 画面左メニューのSSH and GPG Keys
4. 画面右上のNew SSH key

Titleには識別しやすいよう任意の名前を入力し、keyの欄に先ほど作成して中身をコピーした公開鍵を貼り付けます。
Add SSH key をクリックして登録完了です。

configファイルを作成

以下のようにconfigファイルを作成します。
既に作成済みであれば、configファイルは.sshフォルダ内にあります。

SSHキーは以下で作成したものとします。

  • 社内アカウント: work_key
  • 個人アカウント: home_key

HostNameは以下で作成することにします。

  • 社内アカウント: github.com
  • 個人アカウント: github.com.home
Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/work_key

Host github.com.home
  HostName github.com
  User git
  IdentityFile ~/.ssh/home_key
  TCPKeepAlive yes
  IdentitiesOnly yes



2. 対象レポジトリをクローン

対象レポジトリのSSHのURLはgit@github.com:[アカウント名/レポジトリ名].gitになっていますが、github.comのところをgithub.com.homeに置き換えます。

git clone git@github.com.home:[個人アカウント名/ローカルレポジトリ名].git


Note:
configのHostNameを置き換える点が重要です。
今回は、「個人→社内」 でしたが、「社内→個人」 の場合でも適切に置き換えれば逆のパターンも対応可能です。
その場合は後述の`remote add`コマンド実行時もHostNameを適切に置き換えます。



3. プッシュ先のレポジトリを作成

社内アカウントでプレイベートなレポジトリを任意の名前で作成しておきます。



4 ローカルレポジトリからリモートレポジトリを作成

クローンしたプロジェクト直下に移動して下記コマンドを実行します。
リモートレポジトリ名には「3. プッシュ先のレポジトリを作成」で作成したレポジトリ名を入力します。
remote_repoには任意の名前を入力します。

git remote add remote_repo git@github.com:[社内アカウント名/リモートレポジトリ名].git



5 リモートレポジトリをプッシュ

remote_repoは「#4 ローカルレポジトリからリモートレポジトリを作成」でremote_repoに指定した名前を使います。
--all をつけるとmasterブランチだけでなく、全ブランチをプッシュしてくれます。

git push remote_repo --all


これでコミット履歴も含めて、個人のレポジトリを社内で共有することが出来ました。

Epic Online Services(EOS) + Mirror を使ったUnityゲーム開発【Part1】

Epic Online Services(以下、EOS)のC#SDKをUnityで使う方法を備忘録として残します。


開発環境

  • Windows 10
  • Unity 2021.3.4
  • C# EOSSDK 1.15.4 (途中でバージョンアップしたので1.14.2からの導入を含みます)
  • Mirror 70.0.0


はじめに

EOSによりサーバーを自分で用意しなくてもオンラインゲームをつくることができます。 EOSは様々なサービスを提供してくれており、そのうちの一つにP2P機能があります。

P2PそのままではUnityでゲーム開発は厳しいですが、 ありがたいことに、EOSを使ってMirrorのTransportを実装してくださった方がいますので使わせていただきます。 これを使うことにより、Mirrorを使ってオンラインゲームの開発が行えます。

今回利用させていただくEpicOnlineTransportのGitレポジトリ github.com

また、今回は利用しませんが、Playeverywhere社開発の公式サンプルもあります。 EOSの使い方で分からないところがあれば参考になります。 github.com


0. Epic Online Services利用準備

EpicGamesアカウントを作成

EOSを利用するためにはEpicGamesアカウントが必要ですので、下記リンクからアカウント作成します。
https://dev.epicgames.com/portal

アプリページを作成

下記リンクよりDeveloper Potalにログインします。
https://dev.epicgames.com/portal

1. ページ左側メニューの 製品を作成をクリックしてアプリページを作成。
製品名は任意の名前を入力します。


2. その後 左側メニューの 製品設定 からクライアントとクライアントポリシーを作成
新規クライアントを追加 をクリックします。
任意のクライアント名を記入して、クライアントポリシーを選択します。
クライアントポリシーは未作成なので、 +新規クライアントポリシーを追加 をクリックします。
任意のクライアントポリシーの名称を記入して、クライアントポリシーの種類にはPeer2Peerを選択して、そのまま保存します。

3. 認証情報の確認
SDKのダウンロードと認証情報 のページ下部に 製品, クライアント, アプリケーション, サンドボックス, デプロイメント のIDが見つかると思います。
これらのIDは後ほど使います。
クライアントとアプリケーションが存在していることを確認してください。


1. EpicOnlineTransport導入

Mirrorのインポート

Unityアセットストアより最新のMirrorのダウンロードしてインポートします。
執筆当時は70.0.0が最新でした。

EpicOnlineTransportのインポート

下記リンクからEpicOnlineTransportの最新のunitypackageをダウンロード後 起動してUnityにインポートします。 github.com

私は1.5.0をインストールしましたが、執筆当時最新の1.5.1をおすすめします。
(1.5.1の変更の取り込みについては後述します)


1.5.0をインストールした場合はエラーが出るので、EosTransport.csを修正します。

1.5.1をインストールした場合でもMirrorのバージョンが新しい場合はServer.csでエラーが出ているかもしれません。


unitypackageからダウンロードすると、 Assets/Mirror/Runtime/Transport/EpicOnlineTransport にEpicOnlineTransportの実装があります。

配置場所がMirrorフォルダ内部になっているため、支障はありませんが管理しづらいため分離します。 今回はAssetsフォルダ直下に_Assetsフォルダを作成してまとまることにしました。

以下のように配置を修正しました。

  • EOS : Assets/_Assets/EpicOnlineTransport
  • Mirror : Assets/_Assets/Mirror

配置を変えた影響で、このままだとエラーが出てしまうので少し修正します。 EOSSDKComponent.csのlibraryPathが文字列でパスを持っているので、変更した配置場所に合わせて書き換えます。

// 修正前
var libraryPath = "Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/" + Config.LibraryName;  

// 修正後
var libraryPath = "Assets/_Assets/EpicOnlineTransport/EOSSDK/" + Config.LibraryName;  


また、EpicOnlineTransport/EOSSDK/iOS/EOSSDK.framework は100MBを超えており、GitLFSの対象になってしまうため、不要であれば削除をおすすめします。 ※EOSSDK.frameworkはiOSビルドに必要になります。


2. 最新のEOSSDK導入

先程インポートしたEpicOnlineTransportには既にEOSSDKが含まれていますが、最新バージョンに更新します。
EOSSDKは EpicOnlineTransport/EOSSDK に置かれています。
EOSSDK/CoreEOSSDK/Generatedソースコードで、残りは各プラットフォームでの実行に必要なライブラリです。

最新バージョンに更新する場合は、CoreとGeneratredを全置き換えとこれらのライブラリを置き換える必要があります。
Windowsの場合はEOSSDK-Win64-ShippingとEOSSDK-Win32-Shippingだけ最低限置き換えれば大丈夫です。

最新のSDKは下記Developer Potalからダウンロードできます。 https://dev.epicgames.com/portal

「0. Epic Online Services利用準備 / 3. 認証情報確認」で開いたページの上部に SDKをダウンロード というボタンが見つかると思います。
SDKの種類としてC#SDKを選択し、任意のバージョンをダウンロードします。
Part1のこの記事では1.14.2で進めています。

※バージョン1.15に破壊的変更があったため、EpicOnlineTransportで使う場合には大規模な書き換え作業が必要になります。
書き換え作業については軽く説明するつもりですが、多少古くてもすぐ動かしたい方はバージョン1.14.2をおすすめします。

C#SDKをダウンロードしたら、前述のとおりCoreフォルダとGeneratedフォルダを丸々置き換えます。
ビルド対象のライブラリも忘れずに置き換えます。
注意点として、ライブラリのPlatform settingsがデフォルトだと以下画像のように両方にチェックされているため、修正します。

修正前の設定(EOSSDK-Win64-Shipping)

修正後の設定(EOSSDK-Win64-Shipping)

EOSSDK-Win32-Shipping はx86にチェックして、x64のチェックを外し、同様にしてください。 Windows用のライブラリに限りませんが、他プラットフォームについては割愛します。


3. Unity側 設定

EosApiKeyを作成

Project内右クリックから、Create/EOS/API Key をクリックして、認証情報を格納するScriptableObjectを作成します。

作成したEosApiKeyを開いて、中の項目を適切に入力します。

- Epic Product Name
「0. Epic Online Services利用準備」で作成したアプリ名を入力します。

- Epic Product Version
任意のバージョンを入力します。

- Epic Product Id
「0. Epic Online Services利用準備 / 3. 認証情報確認」で確認した製品 のI製品Dを入力します。

- Epic Sandbox Id
「0. Epic Online Services利用準備 / 3. 認証情報確認」で確認したサンドボックスサンドボックスIDを入力します。

- Epic Development Id
「0. Epic Online Services利用準備 / 3. 認証情報確認」で確認したデプロイメント のデプロイメントIDを入力します。

- Epic Client Id
「0. Epic Online Services利用準備 / 3. 認証情報確認」で確認したクライアント のクライアントIDを入力します。

- Epic Client Secret
「0. Epic Online Services利用準備 / 3. 認証情報確認」で確認したクライアント のクライアントシークレットを入力します。

EOSSDKComponenetをシーンに作成

初期ロードシーンに空オブジェクトを作成し、EOSSDKComponentをアタッチします。
インスペクター上でApiKeys欄にEosApiKeyをセットします。

後のために、EOSSDKComponentのDelayed Initializationにチェックを入れておきます。


ここまでで最低限のセットアップは完了です。


4. ログイン

ログイン方法の種類

EOSへのログイン方法はいくらかあります。

  • EpicGamesアカウント等を使うアカウント認証
  • バイスIDを使う認証
  • DevAuthToolを使う認証 (デバッグ専用)

DevAuthToolを使う認証は、デバッグ専用の認証方法です。
ツールはダウンロードしたSDK内の
SDK/Tools/EOS_DevAuthTool-win32-x64- XXX.zip を解凍して起動できます。
予めツール内に複数のアカウントをログインさせ、CredentialNameと紐付けておくことで、ログイン処理を簡略化できます(後述します)。

バイスIDを使う認証は、最も簡単で扱いやすい認証方法です。
初めてデバイスIDの認証行う際に、PC内にデバイスID情報が1つ作成されます。
以降は意図的に削除しない限り、このデバイスID情報を用いてログインを行います。
削除は専用のAPIを呼び出すことや、Windowsの資格情報マネージャーのWindows資格情報にeos-sdk:XXXXXXXXXのような形で保存されているため削除することができます。

iOSAndroidの場合は端末内にデバイスID情報が作成され、これはアプリのアンインストールと共に削除されます。
保存場所は未調査です。
ご存知の方いましたらコメントで教えていただけますと幸いです。

今回は扱いやすさを重視して、基本的にデバイスIDを使う認証で進めていきます。

ログイン処理
EOSSDKComponentシングルトン

ログインを行う処理を書いていきたいのですが、EOS実装のコアとなるEOSSDKComponentクラスを扱いやすくするためにシングルトン処理を書き替えます。
書き換えは必須ではありませんが、以降のスクリプトは置き換え後になりますのでご了承ください。

// 変更前
protected static EOSSDKComponent instance;
protected static EOSSDKComponent Instance
{
    get
    {
        if (instance== null)
        {
            return new GameObject("EOSSDKComponent").AddComponent<EOSSDKComponent>();
        }
        else
        {
            return instance;
        }
    }
}

// 変更後
protected static bool Exist => _Inst != null;
protected static EOSSDKComponent _Inst;
public static EOSSDKComponent Inst
{
    get
    {
        if (_Inst != null) return _Inst;

        _Inst = FindObjectOfType<EOSSDKComponent>(true);
        return _Inst;
    }

    set { _Inst = value; }
}


DontDestroyOnLoad

EOSSDKComponentがシーン遷移で破棄されないようにDontDestroyOnLoad指定を行います。 Awakeのあとシングルトンの変数にインスタンスに代入した後で設定します。

private void Awake()
{
    // Prevent multiple instances
    if (_Inst != null)
    {
        Destroy(gameObject);
        return;
    }
    _Inst = this;
    DontDestroyOnLoad(gameObject);


EosLogin.cs

実際のログイン処理を扱うEosLogin.csを作成します。
次の項目のUI画面と合わせてみて頂くとわかりやすいかもしれません。

機能としては以下のとおりです。

  • 認証方法の選択
  • ログインボタンクリック時にEOS初期化処理呼び出し
  • EOS初期化終了後のコールバック設定

DevAuthToolを使う場合は、事前ログインしたアカウントに紐付ける名前を決めることができますが、このとき決めた名前をCredentialNameとして渡します。
recreateDeviceIdはデバイスID情報の再生成用のフラグです。
削除処理は後ほどEOSSDKComponentに追記します。

作成したら、空のオブジェクトを作成してアタッチしておきます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System;
using UnityEngine.UI;
using Epic.OnlineServices.Auth;
using EpicTransport;
using Epic.OnlineServices;
using UnityEngine.SceneManagement;

namespace Sakineko.Sample
{
    public class EosLogin : MonoBehaviour
    {
        [SerializeField] private TMP_Dropdown eosLoginType;     // ログイン方法を選択
        [SerializeField] private Button loginButton;            // ログインボタン
        [SerializeField] private TMP_InputField credentialName; // CredentialName(※これはDevAuthToolによるログインで使う)
        [SerializeField] private Toggle recreateDeviceId;       // デバイスIDを作り直すかどうか(※これはデバイスIDによるログインで使う)

        [Space]
        [Mirror.Scene]
        public string nextScene; // ログイン後に遷移するシーン

        private void Awake()
        {
            // Dropdown
            var options = new List<TMP_Dropdown.OptionData>();
            foreach (var str in Enum.GetNames(typeof(EosLoginType)))
            {
                options.Add(new TMP_Dropdown.OptionData(str));
            };
            eosLoginType.AddOptions(options);

            // Callback
            loginButton.onClick.AddListener(OnLoginButtonClicked);

            var eos = EOSSDKComponent.Inst;
            eos.onLoginSucceed += OnLoginSucceed;
            eos.onLoginFailed += OnLoginFailed;
        }

        private void OnLoginButtonClicked()
        {
            var eos = EOSSDKComponent.Inst;
            var loginType = (EosLoginType)Enum.ToObject(typeof(EosLoginType), this.eosLoginType.value);

            switch (loginType)
            {
                // アカウントを使う認証
                case EosLoginType.Account:
                    eos.authInterfaceLogin = true;
                    eos.authInterfaceCredentialType = LoginCredentialType.AccountPortal;
                    eos.connectInterfaceCredentialType = ExternalCredentialType.Epic;
                    break;
                // DevAuthToolを使う認証
                case EosLoginType.DevAuthTool:
                    eos.authInterfaceLogin = true;
                    eos.authInterfaceCredentialType = LoginCredentialType.Developer;
                    eos.connectInterfaceCredentialType = ExternalCredentialType.Epic;
                    eos.devAuthToolCredentialName = credentialName.text;
                    break;
                // デバイスIDを使う認証
                case EosLoginType.DeviceID:
                    eos.authInterfaceLogin = false;
                    eos.authInterfaceCredentialType = LoginCredentialType.Developer;
                    eos.connectInterfaceCredentialType = ExternalCredentialType.DeviceidAccessToken;
                    eos.recreateDeviceId = recreateDeviceId.isOn;
                    break;
            }

            Login();
        }

        private void OnLoginSucceed()
        {
            Debug.Log($"OnLoginSucceed");

            SceneManager.LoadScene(nextScene);
        }

        private void OnLoginFailed()
        {
            Debug.LogError($"OnLoginFailed");
        }

        private void Login()
        {
            // EOSの初期化処理
            EOSSDKComponent.Initialize();
        }

        public enum EosLoginType
        {
            DeviceID,
            DevAuthTool,
            Account,
        }
    }
}
UI配置

ログイン方法の選択用としてDropDown,
DevAuthToolのCredentialName入力用にInputField,
ログインボタンとしてButton,
バイスIDの削除用としてToggleを配置します。

nextSceneにはログイン後のシーンをセットします。
ここでは0002_Sample_Home としました。

EOSSDKComponent.csにコールバック追加

EOSSDKComponent.csにログイン成功時と失敗時のコールバックを追加します。

  • 成功時のコールバック onLoginSucceed
  • 失敗時のコールバック onLoginFailed


EOSSDKComponentクラスに変数追加

public Action onLoginSucceed;
public Action onLoginFailed;


OnAuthInterfaceLoginメソッドに追加

private void OnAuthInterfaceLogin(Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo)
{
    if (loginCallbackInfo.ResultCode == Result.Success)
    {
        Debug.Log("Auth Interface Login succeeded");

        string accountIdString;
        Result result = loginCallbackInfo.LocalUserId.ToString(out accountIdString);
        if (Result.Success == result)
        {
            Debug.Log("EOS User ID:" + accountIdString);

            localUserAccountIdString = accountIdString;
            localUserAccountId = loginCallbackInfo.LocalUserId;
        }

        ConnectInterfaceLogin();

        // Change to next scene
        onLoginSucceed?.Invoke();
    }
    else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode))
    {
        Debug.Log("Login returned " + loginCallbackInfo.ResultCode);
                
    // Faile to login 
        onLoginFailed?.Invoke();
    }
}


OnConnectInterfaceLoginメソッドに追加

private void OnConnectInterfaceLogin(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo)
{
    if (loginCallbackInfo.ResultCode == Result.Success)
    {
        Debug.Log("Connect Interface Login succeeded");

        string productIdString;
        Result result = loginCallbackInfo.LocalUserId.ToString(out productIdString);
        if (Result.Success == result)
        {
            Debug.Log("EOS User Product ID:" + productIdString);

            localUserProductIdString = productIdString;
            localUserProductId = loginCallbackInfo.LocalUserId;
        }

        initialized = true;
        isConnecting = false;

        var authExpirationOptions = new Epic.OnlineServices.Connect.AddNotifyAuthExpirationOptions();
        authExpirationHandle = EOS.GetConnectInterface().AddNotifyAuthExpiration(authExpirationOptions, null, OnAuthExpiration);
                
    // Change to next scene
        onLoginSucceed?.Invoke();
    }
    else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode))
    {
        Debug.Log("Login returned " + loginCallbackInfo.ResultCode + "\nRetrying...");
        EOS.GetConnectInterface().CreateUser(new Epic.OnlineServices.Connect.CreateUserOptions() { ContinuanceToken = loginCallbackInfo.ContinuanceToken }, null, (Epic.OnlineServices.Connect.CreateUserCallbackInfo cb) =>
        {
            if (cb.ResultCode != Result.Success) { Debug.Log(cb.ResultCode); return; }
            localUserProductId = cb.LocalUserId;
            ConnectInterfaceLogin();
        });
    }
}
バイスID削除処理

バイスID削除処理をEOSSDKComponentクラスに追加します。


EOSSDKComponentクラスに変数追加

[NonSerialized] public bool recreateDeviceId;


InitializeImplementationメソッドに削除処理を追加
以下の記述をEOS = PlatformInterface.Create(ref options);より後に追加します。

if (recreateDeviceId)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
    var deleteDeviceIdOptions = new Epic.OnlineServices.Connect.DeleteDeviceIdOptions();
    EOS.GetConnectInterface().DeleteDeviceId(ref deleteDeviceIdOptions, null, OnDeleteDeviceId);
#else
    Debug.LogWarning($"Delete devideID is valid only development build or UnityEditor.");
#endif
}


InitializeImplementationメソッドのデバイスID作成処理に条件を追加

// 変更前
if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken)

// 変更後
if (recreateDeviceId && connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken)


5. 実際にログインしてみる

Unityエディタを実行して、ドロップダウンからDeviceIDを選択して、Loginボタンをクリックします。
※初回ログイン時はReCreateDeviceIDのチェックをONにします。(そうしないとデバイスID情報が作成されないように作りました)

無事に事前に設定しておいたnextSceneに遷移できれば成功です。



次回はMirror側の実装に移ります。


Part2

lucifep-angel.hatenablog.com