【Unity】UnityRelayのつかいかた

# ■ はじめに
Unityでネットワーク機能を使うときに必要な機能であるRelayの使い方をまとめます。
(なお、筆者も記事を書きながら学んでます。間違いなどがあればご指摘お願いします。)
(記事の内容は随時追加予定です)

また、**結構ネットワーク関係の専門用語が出てくるので、知識を軽く身に着けておくといいかもです！**(ぼくもお勉強中です)

### 環境
- Unity: `2023.2.0f1`
- UnitHub: `3.6.1`
- Relay: `1.0.5`

また、当記事ではNetcodeでの使用を前提としたRelayの使い方を紹介しています。
- Netcode for Gameobjects: `1.7.0`
- Unity Transport: `1.4.0`

<br>

# ■ UnityRelayとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/d34b7cb1-b6c6-a394-75bd-f8955d53c90e.png)


- Unity公式が提供するのリレーサーバー、Allocation Service(割り当てサービス)
    - **リレーサーバー**：ホストとクライアントの中継役的な役割のサーバー？
    - **Allocation Service**：サーバーの割り当てとかをしてくれる機能

## ● PhotonFusionとの違い


### 料金
|  | PhotonFusion | UnityRelay |
| --- | --- | --- |
| 同時接続数 | 20 CCU | 50 CCU |
| 一月あたりの転送量 | 60GB | 150GB |

https://www.photonengine.com/ja-jp/fusion/pricing

https://unity.com/solutions/gaming-services/pricing#:~:text=Revenue%20share-,Multiplayer,-Relay

# ■使用例
めちゃくちゃ簡素な実装例ですが、こんな感じでコードをもとに参加できます。
また、今回はローカル環境でやってますが、オンラインで遠くのどっかの人とも通信できます。

![CreateAndJoinWithRelay.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/ec39832d-be8b-a25c-5e74-8fcdd9e2685c.gif)


# ■ セットアップ
## ● パッケージのインストール
- PackageManagerからRelayをインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/0e6ca7e1-7bba-6e7f-53d9-14a722fc3f5b.png)



## ● プロジェクト設定
- `ProjectSettings/Services`を表示して、このようになってたらOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/3f4c58a8-cb7f-3e45-096d-518db769126f.png)

- UnityProjectIDがリンクされていない場合、`Link Project`ボタンをクリックする



## ● Unity Cloud
https://cloud.unity.com/

1. Unityアカウントにサインインして、↑のサイトにアクセス
2. 左のサイドバー内の **[プロジェクト]** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/5515a5c4-4262-0fbd-61fc-deb47160ec97.png)
1. プロジェクト一覧が表示されるので、対象のプロジェクトを選択
1. 先ほどのプロジェクト設定でリンクしたプロジェクトがこのように表示されてたらOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/1fda49e4-e085-5464-51c3-6158b64a165b.png)
1. 下の方に **[サービス]** という項目があるので、下の方までスクロールして、Relayを見つけて、 **[起動]** ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/10aef201-bff1-b4f8-597f-0f8486e8b2ec.png)
1. 右上らへんの **[Get Started]** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/fafeb409-0998-2ece-252b-ac8ffbc35cf2.png)
1. セットアップガイドが表示されていますが、全て完了済みなので無視して **[Finish]** ボタンをクリックして完了！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/f0f03809-6a8b-f5af-7159-1b72a3c38a4f.png)



<br>


# ■ 使い方
## ● Relayの初期化
```.cs
async void Awake()
{
    // UnityServicesの初期化
    await UnityServices.InitializeAsync();
}
```

- 一番初めにRelayなどのUnityServicesの初期化を行います

## ● ユーザーのサインイン
```.cs
void SignIn()
{
    // サインイン時にログ表示
    AuthenticationService.Instance.SignedIn += () => {
        print("Sined in:" + AuthenticationService.Instance.PlayerId);
    };

    // 匿名サインイン
    await AuthenticationService.Instance.SignInAnonymouslyAsync();
  }
```
:::note
- `AuthenticationService.Instance`で認証サービスの操作を行えます
- 匿名サインインについての詳細は[こちら(公式ドキュメント)](https://docs.unity.com/ugs/manual/authentication/manual/use-anon-sign-in)



:::




## ● 部屋(Allocation)の作成
```.cs
public async void CreateRelay()
{
    try {
        // 部屋の作成
        Allocation allocation = await RelayService.Instance.CreateAllocationAsync(1);

        // 部屋の参加コードを取得
        string joinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
        print(joinCode);

        // 作成した部屋をもとに、UTPの設定
        var relayServerData = new RelayServerData(allocation, "dtls");
        var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
        transport.SetRelayServerData(relayServerData);

        // ホストとして開始
        NetworkManager.Singleton.StartHost();
    }
    catch (RelayServiceException e) {
        Debug.LogException(e);
    }
}
```
:::note
- `RelayService.Instance`でRelayの機能が利用できます
- `CreateAllocationAsync()`で部屋(**Allocation**)を作成できます
    - 引数には、**参加人数**と**リージョン**(接続地域)を指定できます
        - 参加人数は、<ins>ホストを除いたクライアントの数</ins>です
        - リージョンを省略した場合、自動で決められます

- 作成した部屋の情報をもとに、UnityTransportにサーバーデータを指定します
- `RelayServerData`のコンストラクタで部屋と接続タイプを指定できます
    - 接続タイプは**UTP**や**DTLS**、**WS**などがある
(知識ないので詳細は不明です。時間があれば追記しておきます)

- データをセットしたあとに、`NetworkManager.Singleton.StartHost()`で開始すると、作成した部屋のIPアドレスとかポート番号をもとにゲームが開始される
:::




## ● 部屋への参加
```.cs
	public async void JoinRelay(string joinCode)
	{
		try {
			// コードをもとに部屋に参加
			print($"Joining... (code: {joinCode})");
			var allocation = await RelayService.Instance.JoinAllocationAsync(joinCode);

			// 参加する部屋をもとに、UTPの設定
			var relayServerData = new RelayServerData(allocation, "dtls");
			var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
			transport.SetRelayServerData(relayServerData);

			// クライアントとして参加
			NetworkManager.Singleton.StartClient();
		}
		catch (RelayServiceException e) {
			Debug.LogException(e);
		}
	}
```

## ● プレイヤーの切断
編集中…


:::note
- 作成時に取得した参加コードを使用して、その部屋に参加できます
- サーバー設定は作成時と同じです(※`allocation`の型は`Allocation`ではなく、`JoinAllocation`)
- 作成時と同様に、`NetworkManager`のシングルトンインスタンスを利用してクライアントとして参加
:::


<br>

# ■ さいごに
基本的にこんな感じで扱えます。

結構学習コスト高くてハードル高めですが、いろいろできるので頑張りましょう～～

## ● 参考
- 公式ドキュメント

https://docs.unity.com/ugs/manual/relay/manual/introduction

- 公式サンプルコード

https://docs.unity.com/ugs/en-us/manual/relay/manual/relay-and-utp


- 分かりやすい海外の方の解説動画

https://youtu.be/msPNJ2cxWfw?si=TOqE37Jtpk2RLDQ4