# Tutorial 1 - Minimal Setup

このチュートリアルでは、Diarkis Unity SDK を使ってサーバーに接続するための最小限のコードを実装します。余分な機能は一切持たせず、接続の仕組みそのものに集中できる構成です。

終了時には以下のことが身についています:

* コアオブジェクト（`DiarkisNetworkManager` / `DiarkisInterface` / `DiarkisEventHandler`）の取得と使い方
* イベントコールバックの登録と解除
* HTTP 認証と UDP 接続を **2 ステップに分けて** 呼び出す方法
* 接続イベント（成功 / 失敗 / 切断）を受け取って状態表示する方法

Room・MatchMaker・Field などの機能モジュールは次のチュートリアル以降で扱います。

SDK の構成

コードを書く前に、主要コンポーネントの関係を把握しておきましょう。

#### DiarkisNetworkManager

Unity プロジェクトにおける Diarkis SDK のエントリーポイントです。シングルトン `MonoBehaviour` であり、`DiarkisNetworkManager.Instance` に初めてアクセスしたとき自動的に生成されます。手動で作成する必要はありません。

```
DiarkisNetworkManager（シングルトン MonoBehaviour）
  └─ DiarkisInterface（名前で管理、複数持てる）
       ├─ ConnectionManager（接続フロー管理）
       ├─ EventHandler（イベントコールバックのハブ）
       ├─ DiarkisUdp / DiarkisTcp（トランスポート）
       ├─ DiarkisRoom（ルーム機能）
       ├─ DiarkisMatchMaker（マッチメイキング）
       └─ DiarkisField / DiarkisP2P / ...（その他機能モジュール）
```

```mermaid
flowchart TD
    TM["Tutorial1MinimalSetupManager
あなたのゲームコード"]

    subgraph PLUGIN["Diarkis Unity Plugin"]
        DNM["DiarkisNetworkManager
シングルトン MonoBehaviour
C++ ランタイム初期化"]
    end

    subgraph SDK["Diarkis C# SDK  —  Core/Client/"]
        DI["DiarkisInterface
1サーバー接続
= 1インスタンス"]
        CM["ConnectionManager
接続フロー管理"]
        EH["EventHandler
コールバックハブ"]
        TR["DiarkisUdp / DiarkisTcp
トランスポート"]
        RM["DiarkisRoom
ルーム機能"]
        MM["DiarkisMatchMaker
マッチメイキング"]
        DI --- CM
        DI --- EH
        DI --- TR
        DI --- RM
        DI --- MM
    end

    subgraph INTEROP["SWIG バインディング  —  Core/Interop/"]
        SW["自動生成 C# バインディング
P/Invoke で
ネイティブ呼び出し"]
    end

    subgraph NATIVE["ネイティブ"]
        LIB["libdiarkis（C++）
メモリ管理
パケット処理
プロトコル実装"]
    end

    TM -->|"Connect · Disconnect
GetDiarkisInterface"| DNM
    DNM -->|"名前で辞書管理
毎フレーム Update"| DI
    EH -.->|"コールバック
OnUDPConnect など"| TM
    CM -->|"P/Invoke"| SW
    TR -->|"P/Invoke"| SW
    SW --> LIB
```

`DiarkisNetworkManager` の主な責務:

* **C++ ランタイムの初期化・終了** — `Awake()` で Diarkis コアを起動します
* **複数インターフェースの管理** — 名前をキーとした辞書で `DiarkisInterface` を管理します。ゲームサーバーとチャットサーバーに同時接続する場合など、複数の接続を持てます
* **毎フレームのポーリング** — `Update()` で全インターフェースの `UpdateComponents()` を呼び出し、C++ 側で受信したパケットを C# のコールバックへ届けます
* **シーンをまたいで保持** — `DontDestroyOnLoad` で永続化されます

#### DiarkisInterface

1 つの `DiarkisInterface` は、1 つのサーバー接続とそのすべての機能を束ねたオブジェクトです。`DiarkisNetworkManager.GetDiarkisInterface(name)` で取得または生成し、名前を省略するとデフォルト（空文字列）になります。

```csharp
DiarkisInterface diarkis = DiarkisNetworkManager.GetDiarkisInterface("");

// 各機能モジュールへのアクセス
DiarkisRoom       room       = diarkis.Room;
DiarkisMatchMaker matchMaker = diarkis.MatchMaker;
```

各機能チュートリアルでは、この `diarkis.Room` / `diarkis.MatchMaker` を起点に操作します。

`DiarkisInterface` は Diarkis の C++ コアライブラリへの C# ラッパーです。内部では **SWIG** によって自動生成された C# バインディング（`Core/Interop/`）を通じて P/Invoke でネイティブライブラリを呼び出しています。毎フレームの `UpdateComponents()` が不可欠ですが、`DiarkisNetworkManager` が代行するので開発者が意識する必要はありません。

#### DiarkisEventHandler

`DiarkisEventHandler` は `DiarkisInterface` の**コールバックハブ**です。接続成功・失敗・受信メッセージ・マッチメイキング結果など、SDK が発生させるすべてのイベントはここを通じて登録します。

```csharp
DiarkisEventHandler handler = diarkis.EventHandler;
```

**コールバックの登録**

```csharp
handler.OnUDPConnect(OnConnect, this);
```

* 第 1 引数はコールバックメソッドです。
* 第 2 引数は**オーナー** — 任意のオブジェクトで、通常は `this` を渡します。オーナーは後で一括解除するときに使います（クリーンアップ 参照）。

**コールバックのシグネチャ**

各イベントには決まったシグネチャがあります。

| イベント                 | コールバックシグネチャ                          |
| -------------------- | ------------------------------------ |
| `OnEndpointReceived` | `Action<DiarkisHTTPAuthDataModel>`   |
| `OnUDPConnect`       | `Action<DiarkisConnectionEventArgs>` |
| `OnUDPDisconnect`    | `Action<bool>`（再接続フラグ）               |
| `OnUDPFail`          | `Action<string>`（エラーメッセージ）           |
| `OnHttpError`        | `Action<string>`（エラーメッセージ）           |

シンプルな処理はラムダで書くこともできます。

```csharp
handler.OnUDPFail(_ => SetState("UDP 接続失敗", ColorRed, false), this);
```

#### ConnectionManager

`DiarkisInterface` の内部コンポーネントで、接続シーケンスを管理します。Diarkis への接続は 2 ステップで構成されています。

```mermaid
flowchart TD
    S1["ステップ 1: HTTP 認証<br/>SendGetServerEndpointRequest()"]
    S2["ステップ 2: UDP 接続<br/>ConnectWithAuthData()"]
    EV1[OnEndpointReceived]
    EV2[OnUDPConnect]
    ERR1[OnHttpError]
    ERR2[OnUDPFail]

    S1 --> EV1
    S1 --> ERR1
    EV1 -->|"Connect UDP を押す"| S2
    S2 --> EV2
    S2 --> ERR2
```

### なぜ 2 ステップに分けるのか

実際のゲームでは、クライアントが Diarkis HTTP サーバーへ直接リクエストを送ることは推奨されません。**クライアントキーなどのシークレットを保護する**ため、HTTP 認証は認証機能を持つゲームサーバーなどを経由して行うことをご検討ください。

```mermaid
sequenceDiagram
    participant C as クライアント
    participant G as ゲームサーバー
    participant D as Diarkis HTTP サーバー
    participant U as Diarkis UDP サーバー

    Note over C,D: 推奨フロー（本番）
    C->>G: 接続リクエスト（ログイン済みセッション）
    G->>D: HTTP 認証（ClientKey はサーバー側で管理）
    D-->>G: エンドポイント情報（host, port, 暗号化キー）
    G-->>C: エンドポイント情報を転送

    Note over C,U: ステップ 2（クライアントが直接実行）
    C->>U: UDP 接続（エンドポイント情報を使用）
    U-->>C: OnUDPConnect
```

このサンプルはその **2 ステップを明示的に分けて呼び出す**実装を示しています。`connectOnAuthResponse = false` を設定することで、HTTP レスポンス受信後も UDP 接続を自動開始せず、明示的に制御できます。

#### 本番での AuthData の受け取り方

このサンプルでは `SendGetServerEndpointRequest` を使ってクライアントが直接 Diarkis HTTP サーバーへリクエストを送り、`OnEndpointReceived` でパース済みの認証データを受け取っています。

本番では、ゲームサーバーが Diarkis HTTP サーバーへリクエストを送り、その結果を JSON 文字列としてクライアントへ転送します。クライアントはその JSON を `DiarkisAuthResponse.ParseFromJson()` でパースして `ConnectWithAuthData` に渡します。

```csharp
// ゲームサーバーから JSON 文字列を受け取ったコールバック内で（例）
// {"serverType":"UDP","serverHost":"10.0.0.1","serverPort":"7200",
//  "sid":"abc123...","encryptionKey":"...","encryptionIV":"...","encryptionMacKey":"..."}
void OnJsonReceivedFromGameServer(string json)
{
    DiarkisAuthResponse authResponse = new DiarkisAuthResponse();
    if (authResponse.ParseFromJson(json))
    {
        DiarkisHTTPAuthDataModel authData = new DiarkisHTTPAuthDataModel(authResponse);
        diarkis.ConnectWithAuthData(authData, useConnectionManager: true);
    }
}
```

`SendGetServerEndpointRequest` はサンプル・開発時のショートカットです。本番コードでは使わないことを推奨します。

#### ショートカット: DiarkisNetworkManager の Connect()

2 ステップを分けずに 1 回の呼び出しで接続したい場合（簡単なプロトタイプなど）、`DiarkisNetworkManager` の `Connect` メソッドを使うと HTTP 認証と UDP 接続を自動でまとめて実行できます。

```csharp
DiarkisNetworkManager.Connect(INTERFACE_NAME, HOST, CLIENT_KEY, uid, "UDP");
```

手軽ですが各ステップのタイミングを細かく制御することはできません。HTTP 認証をサーバー側で行う本番環境では、このチュートリアルで示した 2 ステップ方式を推奨します。

### シーンのセットアップ

**前提条件**: Unity 6000.0.64f1 以降、Diarkis Unity SDK がプロジェクトにインポート済み

`Tutorials/Scenes/Tutorial1-MinimalSetup.unity` を開きます。シーンには `Tutorial1-Minimal-UI`（Canvas / ボタン / Network State テキスト）と `TutorialManager`（`Tutorial1MinimalSetupManager` アタッチ済み）が含まれています。

#### シーンへの DiarkisNetworkManager の配置

前述のとおり `DiarkisNetworkManager` は実行時に自動生成されますが、**シーンに `DiarkisNetworkManager` GameObject をあらかじめ配置しておくことを推奨します**。

> **Inspector フィールドとコードの違い:** `DiarkisNetworkManager` は `PreStoredHttpHost`・`PreStoredClientKey`・`UseRandomUID` を Inspector に公開しています。これは**デバッグ用の便宜機能**であり、再コンパイルなしにエンドポイントを素早く切り替えるのに便利です。このチュートリアルのコードは同じプロパティをランタイムで明示的に設定しており、これが本番環境で推奨されるアプローチです。コードは Inspector の値が適用された後に実行されるため、コードによる設定が常に優先されます。

<figure><img src="https://669307705-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlFJ89PMX2ike3NyauXNM%2Fuploads%2FoSqM9gVm6o9a0163swPL%2Fimage.png?alt=media&#x26;token=a8c0eca3-a79b-45f3-ae9c-7a0d63b9d2c2" alt=""><figcaption></figcaption></figure>

`Tutorials/Scripts/Tutorial1MinimalSetupManager.cs` を開き、定数を環境に合わせて変更してください。

```csharp
private const string HOST       = "127.0.0.1:7000"; // 本番では自社ゲームサーバーのアドレス
private const string CLIENT_KEY = "";               // 発行済みのクライアントキー
private const string UID        = "";               // 空文字の場合はランダム生成
```

UID はサーバー上でこのクライアントを一意に識別する値です。空文字にすると `Guid.NewGuid()` でランダム生成されます。衝突が起きないため手軽なテストに便利です。ダイレクトメッセージや特定のルーム操作など、2 つのインスタンスがお互いを既知の ID で参照する必要がある場合は、`"player-1"` のような固定値を設定してください。

<figure><img src="https://669307705-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlFJ89PMX2ike3NyauXNM%2Fuploads%2FzTOA7onUfkKXOCAkyCHe%2Fimage.png?alt=media&#x26;token=b91be3eb-8f81-4333-b1d7-0723a30f331c" alt=""><figcaption></figcaption></figure>

### コードの解説

#### Start() — 初期化とイベント登録

SDK オブジェクトを取得し、すべてのコールバックを登録する場所です。Diarkis のイベントはすべて `DiarkisEventHandler` を通じて届くので、これが最初にやるべきことです。

```csharp
private void Start()
{
    DiarkisInterface diarkis = DiarkisNetworkManager.GetDiarkisInterface(INTERFACE_NAME);
    DiarkisEventHandler handler = diarkis.EventHandler;

    // ステップ 1 の結果
    handler.OnEndpointReceived(OnEndpointFetched, this);
    handler.OnHttpError(_ => SetState("HTTP 認証エラー", ColorRed, false), this);

    // ステップ 2 の結果
    handler.OnUDPConnect(OnConnect, this);
    handler.OnUDPDisconnect(OnDisconnect, this);
    handler.OnUDPFail(_ => SetState("UDP 接続失敗", ColorRed, false), this);
}
```

各登録呼び出しの第 2 引数に渡している `this` が**オーナー**です。これにより `OnDestroy` で一括解除できます（クリーンアップ 参照）。

`OnEndpointReceived` は SDK が HTTP レスポンスをパースして `DiarkisHTTPAuthDataModel` を組み立てたタイミングで発火します。`connectOnAuthResponse = true` の場合は SDK が自動で UDP 接続を開始するため、**このコールバック内で `ConnectWithAuthData` を呼ばないでください**（二重接続が発生します）。`connectOnAuthResponse = false`（このサンプルの設定）の場合のみ、任意のタイミングで手動呼び出しします。

#### ステップ 1: エンドポイント取得

```csharp
private void OnFetchEndpointClicked()
{
    DiarkisInterface diarkis = DiarkisNetworkManager.GetDiarkisInterface(INTERFACE_NAME);

    // false にすることで、HTTP レスポンス受信時に UDP 接続を自動開始しない
    diarkis.connectOnAuthResponse = false;

    diarkis.SetClientKey(CLIENT_KEY);
    diarkis.HttpHost = HOST;

    // レスポンスは OnEndpointReceived → OnEndpointFetched で受け取る
    diarkis.SendGetServerEndpointRequest("UDP", useConnectionManager: false);
}

private void OnEndpointFetched(DiarkisHTTPAuthDataModel authData)
{
    // authData には接続に必要な全情報が入っている:
    //   authData.ServerHost / ServerPort — 接続先
    //   authData.Sid                     — セッション ID
    //   authData.EncryptionKey / IV / MacKey — 暗号化情報
    //
    // この authData をそのままステップ 2 の ConnectWithAuthData に渡す。
    _authData = authData;
    _endpointFetched = true;
    SetState("エンドポイント取得済み — UDP 接続可能", ColorBlue, false);
}
```

`connectOnAuthResponse = false` が 2 ステップ分割の鍵です。これを設定しないと HTTP レスポンスを受け取った瞬間に UDP 接続が始まり、ステップ 2 を手動で呼ぶ意味がなくなります。

#### ステップ 2: UDP 接続

```csharp
private void OnConnectUdpClicked()
{
    // ステップ 1 の OnEndpointFetched で受け取った authData を使って UDP 接続を開始する
    DiarkisNetworkManager.GetDiarkisInterface(INTERFACE_NAME)
        .ConnectWithAuthData(_authData, useConnectionManager: true);
}
```

`ConnectWithAuthData` は authData の SID・EncryptionKey・EncryptionIV・EncryptionMacKey を使って UDP 接続を開始します。結果は `OnUDPConnect` または `OnUDPFail` で届きます。

#### コールバック

`Start()` で登録したコールバックに接続イベントが届きます。

```csharp
private void OnConnect(DiarkisConnectionEventArgs args)
{
    if (args.GetStatus() == DiarkisConnectStatus.DCS_Success)
        SetState("接続済み", ColorGreen, true);
    else
        SetState("接続失敗", ColorRed, false);
}

private void OnDisconnect(bool reconnecting)
{
    // reconnecting が true の場合は自動再接続の試みが進行中
    if (!reconnecting)
        SetState("未接続", ColorRed, false);
}
```

`DiarkisConnectionEventArgs.GetStatus()` は `DiarkisConnectStatus` 列挙型を返します。`OnUDPConnect` は成功・失敗どちらでも発火するため、必ずステータスを確認してください。

`OnUDPDisconnect` の `reconnecting` フラグが `true` のとき、SDK はすでに自動再接続を試みています。この場合は「再接続中...」などの UI 表示にとどめ、最終切断として扱わないようにしましょう。

#### OnDestroy() — クリーンアップ

```csharp
private void OnDestroy()
{
    DiarkisNetworkManager.GetEventHandler(INTERFACE_NAME)?.UnregisterCallbacks(this);
}
```

`UnregisterCallbacks(this)` は `this` をオーナーとして登録した**すべての**コールバックを一括解除します。イベントごとに個別に解除する必要はありません。シーン遷移やオブジェクト破棄時に必ず呼んでください。これを怠ると、破棄済みオブジェクトへの参照がコールバックとして残り続けます。

### 動作確認

シーンの設定とコードの理解が整ったら、Play モードに入り **Fetch Endpoint** → **Connect UDP** の順にボタンを押してください。Network State ラベルが緑色になり「接続済み」と表示されれば成功です。**Disconnect** ボタンで初期状態に戻ります。

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlFJ89PMX2ike3NyauXNM%2Fuploads%2Fgit1V968Z28muiEhzYl2%2FRecording%202026-03-12%20084623.webm?alt=media&token=6e6c8ad6-9668-4cbf-a8b8-302965532f88>" %}

### 接続フロー

```mermaid
flowchart TD
    B1([Fetch Endpoint]) --> F1["SendGetServerEndpointRequest()"]
    F1 -->|成功| R1[OnEndpointReceived]
    F1 -->|失敗| E1[OnHttpError]

    R1 --> B2([Connect UDP])
    B2 --> F2["ConnectWithAuthData()"]
    F2 -->|成功| R2[OnUDPConnect]
    F2 -->|失敗| E2[OnUDPFail]
```

接続の基本が確認できたら、次のチュートリアルに進みましょう。

* **Tutorial 2 - Ticket MatchMaker**: チケット方式のマッチメイキング
* **Tutorial 3 - Host/Search MatchMaker**: ホスト/サーチ方式のマッチメイキング
* **Tutorial 4 - Room**: 入室・メンバー管理・ブロードキャスト
