# MatchMaker のフロー

## 概要

Diarkis MatchMaker はマッチメイキングで実現したいことに合わせて、2つの方式を用意しております。

* Host/Search 型: ホストがマッチングを開始し、ゲストがサーチして条件の合うホストを検索、参加する方式。クライアントから条件を指定してマッチングすることを想定しており、ルームマッチングのようなクライアントが好きな条件で検索、入室したいような機能に適しています。また、ホストはパスワードによるロックも可能です。
* Ticket 型: サーチとホストの両方を行う Ticket を発行して自動でマッチングを行う方式。サーバー側でTicket Type ごとにフィルタリング条件を設定することで、クライアントは任意の Ticket Type を指定するだけでマッチングを開始できます。\
  また、クライアントの更新なしにサーバー更新だけで変更することも可能です。\
  ランクマッチなどユーザーのプロパティによって自動マッチングするような機能に適しています。

どちらの方式も、マッチメイキングのルール定義である profile に対して、検索条件に指定する property を定義します。

{% hint style="warning" %}
サーバーをカスタマイズする場合は Enterprise プランの契約が必要になります。
{% endhint %}

## 処理フロー

### Host/Search 型

この方式はクライアントから送信した profileID、 property を元にルームを作成、検索するシンプルな方式です。サーバー側はマッチメイキングの profile に利用する property を定義するだけで、マッチメイキングをすぐに開始することができます。

ホストは任意の条件を指定して募集し、ゲストは条件に合うホストのリストを取得して任意のルームに入室できるため、リストから参加したいルームを検索したい場合に適しています。

基本的な流れは以下の通りです。

1. ホストが profile、 property を指定してルームを作成しマッチングを開始
2. ゲストが profile、 property を指定してルームを検索
3. ゲストが検索結果から任意のルームを指定してルーム参加
4. ルーム入室中は各種操作を実施可能
   1. メッセージ同期
   2. ルーム退出
   3. （ホストのみ）強制退出
   4. （ホストのみ）ルーム削除（解散）

{% @mermaid/diagram content="sequenceDiagram
actor h as Host
actor s as Search
participant du as DiarkisUDP
participant dh as DiarkisHTTP(Storage)

Note over du: 初期化フェーズ
alt マッチングルールを定義
du->>du: matching.Define(profileID, props)
Note left of du: profileID ごとにマッチングに利用する properties を定義する
end

alt ルーム作成（ホストが実施）
h->>du: hostMatchmaking(ver=1,cmd=100)
du->>du: ルーム作成処理
du->>dh: matchmaking データを登録(matching/Add)
du-->>h: ルーム作成完了(roomID)
end

alt ルーム検索（ゲストが実施）
s->>du: listMatchmaking(ver1,cmd=207)
du->>dh: matchmaking データを検索
dh-->>du: return results
du-->>s: ルーム検索完了(検索結果)
end

alt ルーム参加（ゲストが実施）
s->>du: claimMatchmaking(ver=1,cmd=205)
du->>du: ルーム作成処理
alt ルームが満室になったら
du->>dh: matchmaking データを削除
end
du-->>s: ルーム参加完了(roomID,ownerID,memberIDs)
end

alt メッセージ同期
s->>du: syncMatchmakingMembers(ver=1,cmd=204)
du-->>s: メッセージプッシュ(ver=1,cmd=204,message)
du-->>h: メッセージプッシュ(ver=1,cmd=204,message)
du-->>s: メッセージ同期完了("OK")
end

alt ルーム退出
s->>du: leaveMatchmaking(ver=1,cmd=203)
du->>du: ルーム退出処理
du-->>s: ルーム退出プッシュ(ver=1,cmd=203,message)
du-->>h: ルーム退出プッシュ(ver=1,cmd=203,message)
du-->>s: ルーム退出完了("OK")
end

alt 強制退出（ホストのみ）
s->>du: kickFromMatchmaking(ver=1,cmd=217)
du->>du: 強制退出処理
du-->>s: 強制退出プッシュ(ver=1,cmd=217,message)
du-->>h: 強制退出プッシュ(ver=1,cmd=217,message)
du-->>s: 強制退出完了("OK")
end

alt ルーム削除（解散）（ホストのみ）
s->>du: disbandMatchmakingHost(ver=1,cmd=202)
du->>du: ルーム削除処理
du->>dh: matchmaking データを削除
du-->>s: ルーム削除プッシュ(ver=1,cmd=202,message)
du-->>h: ルーム削除プッシュ(ver=1,cmd=202,message)
du-->>s: ルーム削除完了("OK")
end" fullWidth="true" %}

### Ticket 型

マッチングを自動的に行うために Ticket と呼ばれるものを発行する方式です。

Ticket にはフェーズがあり、発行時は検索を繰り返し、一定の回数を検索して一致するものがなければ、 Add フェーズに入り、他人から検索される状態になります。メンバーが最大に達すると完了フェーズに入りマッチング完了状態になります。

また、Ticket Type ごとに発行可能なため、様々な条件のマッチメイキングに対応できます。

さらに、各種コールバックを利用することで、 Ticket Type を指定するだけで、 Diarkis サーバー側で property を API サーバーと連携して取得したり、位置情報と組み合わせて近い人同士をマッチングさせる、最大人数に達成しなくてもマッチングを完了させるなど、複雑なマッチング条件を構築することも可能です。

ランクマッチなど複雑でセキュアなマッチングを実現したい場合に有効な方式となります。

Ticket 型の代表的なコマンドは以下の通りです。

* チケット発行: チケットを発行してマッチングを開始する
* メッセージ同期: マッチングしたメンバーとメッセージのやりとりをする
* チケットキャンセル (オーナーのみ): チケットを削除してマッチングをキャンセルする。ルームに入室したメンバー全員が退出となります
* ルーム退出: マッチングして入室したルームから退出する

処理フローはサーバー側は少々複雑となりますが、クライアントが利用するコマンドなどはシンプルになるので、サーバー更新だけでマッチメイキングの処理を変更することが可能となります。

{% hint style="success" %}
Diarkis サーバーテンプレート Ticket 型の実装 example があります。こちらも参考にしてください。

<https://github.com/Diarkis/diarkis-server-template/tree/develop/examples/matching>
{% endhint %}

{% @mermaid/diagram content="sequenceDiagram
actor Client1 as クライアント1 (Player A)
actor Client2 as クライアント2 (Player B)
participant Server as Diarkis UDP
participant Storage as Diarkis HTTP<br/>(Storage)
participant Callbacks as アプリケーション<br/>コールバック<br/>(Diarkis UDP に登録)

```
Note over Server: 初期化フェーズ
alt マッチングルールを定義
  Server->>Server: matching.Define(profileID, props)
  Note right of Server: profileID ごとにマッチングに利用する properties を定義する
end
loop ticketType ごとに各種コールバック登録
  Note over Server, Callbacks: 必要に応じて ticketType ごとに様々なタイミングでフック処理を追加できる
  Server->>Callbacks: SetOnIssueTicket(ticketType, callback): チケット発行時のコールバック
  Server->>Callbacks: SetOnTicketAllowMatchIf(ticketType, callback): マッチ判定時のコールバック
  Server->>Callbacks: SetOnTicketMatch(ticketType, callback): マッチング成功時のコールバック
  Server->>Callbacks: SetOnTicketMemberJoined(ticketType, callback) メンバーがルームに入ったときのコールバック
  Server->>Callbacks: SetOnTicketMemberJoinedAnnounce(ticketType, callback) メンバーがルームに入ったときのアナウンス
  Server->>Callbacks: SetOnTicketMemberLeave(ticketType, callback) メンバーがルームを退出したときのコールバック
  Server->>Callbacks: SetOnTicketMemberLeaveAnnounce(ticketType, callback) メンバーがルームを退出したときのアナウンス
  Server->>Callbacks: SetOnTicketCanceled(ticketType, callback) マッチングキャンセル時のコールバック
  Server->>Callbacks: SetOnMatchedTicketCanceled(ticketType, callback) マッチしたチケットがキャンセルされたときのメンバーのコールバック
  Server->>Callbacks: SetOnTicketComplete(ticketType, callback) マッチング完了時のコールバック
  Server->>Callbacks: SetOnTicketTimeout(ticketType, callback) タイムアウト時のコールバック
end

Note over Client1, Storage: Player A がチケットを開始
Client1->>Server: issueTicket(ver=1,cmd=218,ticketType)
Server->>Server: StartTicket(ticketType, userData)
Server->>Callbacks: OnIssueTicket callback 実行
Callbacks-->>Server: TicketParams 返却
Server->>Server: Ticket 作成。検索フェーズに移行
Server->>Client1: チケット作成完了("OK")
activate Server

Note over Server: 検索フェーズ (Player A)
loop Search Interval
    Server->>Storage: SearchWithRangeWithTags() Ticket 検索
    Storage-->>Server: 検索結果 (空)
    Server->>Server: searchInterval ミリ秒の間 sleep
    Note right of Server: searchTries 回または emptySearches 回空検索になるまで繰り返す
end

Server->>Server: Add フェーズに移行
Server->>Server: マッチング用ルーム作成
Server->>Storage: 自分の Ticket を matchmaking データに追加
Note right of Server: 他人が Ticket を検索できる状態になる
deactivate Server

Note over Client2, Storage: Player B がチケットを開始
Client2->>Server: issueTicket(ver=1,cmd=218,ticketType)
Server->>Server: StartTicket(ticketType, userData)
Server->>Callbacks: OnIssueTicket callback 実行
Callbacks-->>Server: TicketParams 返却
Server->>Server: Ticket作成。検索フェーズに移行
Server->>Client2: チケット作成完了("OK")
activate Server

Note over Server: 検索フェーズ (Player B)
loop Search Interval
    Server->>Storage: SearchWithRangeWithTags() Ticket 検索
    Storage-->>Server: 検索結果 (Player A を発見!)
    Server->>Server: マッチング用ルームに入室を試行
    
    Note over Server: マッチ判定
    Server->>Callbacks: OnAllowMatchIf callback 実行
    Callbacks-->>Server: true (マッチ許可)
    
    Server->>Server: Player A のマッチング用ルームに参加
    Server->>Server: 自身の Ticket を削除
end
deactivate Server

Note over Server: マッチ成功処理
Server->>Server: ルーム入室後の処理を実行
Server->>Callbacks: OnMatchedMemberJoined callback 実行
Server->>Callbacks: OnMatchedMemberJoinedAnnounce callback 実行

alt OnMatch が true を返す場合は maxMembers に達しなくてもマッチングを完了状態にできる
    Server->>Callbacks: OnMatch callback 実行
    Callbacks-->>Server: true
    Server->>Server: markAsComplete(): 完了フェーズに移行

else maxMembers に達した場合
    Server->>Server: メンバー数チェック
    Server->>Server: markAsComplete(): 完了フェーズに移行
    Server->>Callbacks: OnTicketComplete callback 実行
    Callbacks-->>Server: 完了メッセージ
    Server->>Client1: マッチング完了通知
    Server->>Client2: マッチング完了通知
else まだメンバーが不足している場合はタイムアウト時間を延長
    Server->>Storage: addToMatchmaking(): matchmaking データのタイムアウト延長
    Note over Server: 追加のプレイヤーを待機
end


Note over Client1,Storage: Ticket 参加中に任意で呼び出すコマンド
alt メッセージ同期
    Note over Client2: Ticket の他のメンバーとメッセージ同期
    Client1->>Server: TicketBroadcast(ver=1,cmd=224)
    Server->>Client1: メッセージ通知
    Server->>Client2: メッセージ通知
    Server->>Client1: メッセージ同期完了("OK")
else キャンセル処理 (オーナーのみ)
    Note over Client2: キャンセル処理
    Client1->>Server: CancelTicket(ver=1,Cmd=222)
    Server->>Server: Stop() - Ticket 削除
    Server->>Callbacks: OnTicketCanceled callback 実行
    Server->>Client2: キャンセル通知
    Server->>Callbacks: OnMatchedTicketCanceled callback 実行
    Server->>Client1: キャンセル完了("OK")
else ルーム退出 (オーナーが退出した場合はキャンセル)
    Note over Client2: ルーム退出処理
    Client2->>Server: LeaveFromTicketMatchmaking(ver=1,Cmd=225)
    Server->>Server: ルーム退出
    Server->>Callbacks: OnMatchedMemberLeaveAnnounce callback 実行
    Server->>Client2: ルーム退出通知
    Server->>Callbacks: OnMatchedMemberLeave callback 実行
    Server->>Client1: ルーム退出完了("OK")
end

Note over Server: タイムアウト処理 (並行動作)
par
    Server->>Server: Ticket タイムアウト監視
    alt タイムアウト発生
        activate Server
        Server->>Server: timeoutTicket(): タイムアウト処理
        Server->>Storage: removeFromMatchmaking(): matchmaking データを削除
        Server->>Server: Ticket 削除
        Server->>Server: Room 削除
        Server->>Callbacks: OnTicketTimeout callback 実行
        Server->>Callbacks: OnMatchedTicketTimeout callback 実行
        Server->>Client1: タイムアウト通知
        Server->>Client2: タイムアウト通知
        deactivate Server 
    end
end

Note over Server, Storage: 完了フェーズ
alt 
  Server->>Storage: removeFromMatchmaking():matchmaking データを削除
  Server->>Server: Ticket 削除
end" fullWidth="true" %}
```

## 参考

Diarkis MatchMaking のサーバー API の詳細については、以下を参照してください。

* <https://docs.diarkis.io/docs/server/v1.1.0/diarkis/matching/index.html>


---

# 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-modules/matchmaker/matchmaker-flow.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.
