# Tutorial 5 - Direct Message

このチュートリアルでは、Diarkis の **Direct Message (DM)** 機能を実装します。DM は UID を指定して特定のクライアントへサーバー経由で 1 対 1 メッセージを届けます。

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

* `DirectMessage.Send()` で特定 UID へ DM を送信する方法
* `OnDMMessage` で受信コールバックを登録する方法
* `DiarkisDirectMessageEventArgs` から送信者 UID とペイロードを取得する方法
* `OnDMMessageResponse` で配信確認（Ack）を受け取る方法（省略可）

Tutorial 1 の接続フローが前提です。このシーンは `Start()` で自動接続します。

### Direct Message とは

Room のブロードキャストはルーム内の全員（自分を除く）に届きます。DM は **UID を明示的に指定した 1 クライアントにだけ**届きます。相手がルームに参加しているかどうかは関係ありません。

```mermaid
flowchart LR
    A[クライアント A] -->|"DM: targetUID=B"| SRV[(Diarkis サーバー)]
    SRV -->|中継| B[クライアント B]
    SRV -.->|届かない| C[クライアント C]
```

| メソッド                  | 宛先             | 用途例                 |
| --------------------- | -------------- | ------------------- |
| `SendBroadcastToRoom` | ルーム内の全員（自分を除く） | ゲーム状態の同期            |
| `DirectMessage.Send`  | 指定した 1 クライアント  | フレンドへのチャット、プライベート通知 |

DM は P2P ではなく**サーバー経由**です。送信先の UID さえわかれば、同じルームに参加していなくても送信できます。

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

`Tutorials/Scenes/Tutorial5-DirectMessage.unity` を開き、定数を環境に合わせて変更してください。

```csharp
private const string HOST       = "127.0.0.1:7000";
private const string CLIENT_KEY = "";
private const string UID        = ""; // 空文字の場合はランダム生成
```

Play モードに入るとシーンが自動接続します。一方のクライアントの **My UID** をコピーし、もう一方の **Target UID** フィールドに貼り付けてメッセージボタンを押してください。

### コードの解説

#### イベントの登録

```csharp
DiarkisInterface diarkis = DiarkisNetworkManager.GetDiarkisInterface(INTERFACE_NAME);
DiarkisEventHandler handler = diarkis.EventHandler;

handler.OnUDPConnect(OnConnect, this);
handler.OnUDPDisconnect(OnDisconnect, this);
handler.OnUDPFail(_ => SetNetworkState("接続失敗", ColorRed), this);
handler.OnHttpError(_ => SetNetworkState("HTTP 認証エラー", ColorRed), this);

handler.OnDMMessage(OnMessageReceived, this);
handler.OnDMMessageResponse(_ => { /* 配信確認：省略可 */ }, this);
```

`OnDMMessage` を登録するだけで、自分の UID 宛に送られたすべての DM を受け取れます。

| イベント                  | 発火タイミング                 | コールバックシグネチャ                             |
| --------------------- | ----------------------- | --------------------------------------- |
| `OnDMMessage`         | 自分の UID 宛の DM が届いた      | `Action<DiarkisDirectMessageEventArgs>` |
| `OnDMMessageResponse` | 送信した DM がサーバーに到達した（省略可） | `Action<DiarkisDMResponseEventArgs>`    |

#### DM の送信

```csharp
private void OnSendClicked(string message)
{
    string targetUID = _targetUIDInput.text.Trim();
    if (string.IsNullOrEmpty(targetUID)) return;

    byte[] bytes = Encoding.UTF8.GetBytes(message);
    DiarkisNetworkManager.GetDiarkisInterface(INTERFACE_NAME).DirectMessage.Send(targetUID, bytes);

    // DM は送信者自身には届かないため、ローカルに表示する
    AddChatLine($"[自分 → {targetUID}] {message}");
}
```

ペイロードは任意のバイト列です。ここでは UTF-8 エンコードしたテキストを送っていますが、MessagePack や JSON などで構造化しても構いません。

#### DM の受信

```csharp
private void OnMessageReceived(DiarkisDirectMessageEventArgs e)
{
    string senderID = e.GetSenderID();

    DiarkisByteVector payload = e.GetPayload();
    if (payload == null || payload.Count == 0) return;

    byte[] bytes = new byte[payload.Count];
    for (int i = 0; i < payload.Count; i++)
        bytes[i] = payload[i];

    string message = Encoding.UTF8.GetString(bytes);
    AddChatLine($"[{senderID}] {message}");
}
```

`GetPayload()` は `DiarkisByteVector` を返します。インデックスアクセスで `byte[]` に変換してから UTF-8 デコードします。このパターンは Tutorial 4 の `OnRoomMemberBroadcast` と同じです。

#### 配信確認（省略可）

```csharp
handler.OnDMMessageResponse(_ => {
    // Diarkis サーバーがメッセージを受信したことの確認
}, this);
```

サーバーへの到達確認が必要な場合に使います。多くのユースケースでは不要です。

### メッセージフロー

```mermaid
sequenceDiagram
    participant A as クライアント A
    participant S as Diarkis サーバー
    participant B as クライアント B

    A->>S: DirectMessage.Send(targetUID=B, payload)
    S-->>A: OnDMMessageResponse（省略可）
    S->>B: OnDMMessage（senderID=A, payload）
```

### 次のステップ

Tutorial 6 では **Group** を学びます — 文字列 ID で識別される軽量な pub/sub チャンネルで、複数のクライアントが同じチャンネルにブロードキャストできます。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.diarkis.io/diarkis-client/chtoriaru/unity-chtoriaru/tutorial-5-direct-message.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
