Open-matchマッチングプロセス


Open-matchマッチングプロセス
(金慶のコラム2019.1)
https://github.com/GoogleCloudPlatform/open-match
Open-matchは汎用的なゲームマッチングフレームワークです.ゲームによってカスタムマッチングアルゴリズムが提供されます(dockerミラーで提供されます).
複数のプロセスに分け、各プロセス間で1つのredisを共有する.
  • フロントエンドは、プレイヤーがredisに参加することを受信し、成功した後、プレイヤーにルームウェアアドレス
  • を通知する.
  • バックエンド、ゲームのマッチングルールを設定し、ルームウェアアドレス
  • を設定する.
  • MMFOrc、マッチングアルゴリズム(MMF)
  • を起動する
  • MMFは、マッチングアルゴリズムをカスタマイズし、redisを読み取るプレイヤーを取得し、マッチングに成功すると結果をredisに書き込む.1セットだけマッチして終了します.

  • ゲームウェアにopen-matchのフロントエンドとバックエンドを接続するプロセスをfrontendclientとDirectorと呼びます.入力は2つの部分に分けられ、1つはプレイヤー情報、2つは対局情報である.Directorがバックエンドに対局情報を入力と、次から次へと対局者リストが受信される.Directorは各対局に部屋を開き、バックエンドの部屋の住所を通知する必要があります.バックエンドは部屋アドレスをredisに書き込み、フロントエンドが部屋アドレスを読み取るとfrontendclientに通知し、プレイヤーを部屋に入れる.
    test/cmd/frontendclient
    模擬ホール服またはチーム服、フロントエンドAPIを接続し、プレイヤー/チームのマッチングを要求する.成功するとルームウェア(DGS)のアドレス(Assignment)が届きます.
    Playerは実際には1つのチームであり、IDフィールドはスペースで区切られた複数のIDである.パラメータタイプはPlayerであるが、CreatePlayer()パラメータはチーム全体であり、GetUpdates()パラメータは単一のプレイヤーである.
    main()には複数のプレイヤーが作成され、各プレイヤーはGetUpdates()を呼び出して結果を取得し、go waitForResults()で結果を処理します.waitForResult()は、ストリーム内の一致結果を読み出し、resultsChanに押し込みます(ただし、resultsChanは印刷にのみ使用されるようです).すべてのプレイヤーはgインスタンスにマージされ、CreatePlayer()要求マッチングを呼び出す.
    cleanup()はDeletePlayer()を呼び出してマッチング要求を削除し,チーム全体を削除するだけでなく,単一プレイヤーを削除する必要がある.
    最終的に結果が合っていないようなので、resultChanからAssignmentを取得し、そのアドレスudpClient()を使用する.
    この例を見ればfrontendが理解できる.proto
    examples/backendclient
    MatchObject.Propertiesはtestprofile.jsonが読み取ったのは、Profileと名前を変えたほうがいいですか?pbProfileはMatchObjectですが、ProfileはMatchObjectと同じですか?Profileの定義はMMFに必要なすべてのパラメータです.pbProfile.Properties = jsonProfileは2回繰り返した.
    ListMatches()は、このProfileのすべての一致をリストします.マッチングを受信したら、CreateAssignments()でルームウェアアドレスをAssignmentと呼び、すべてのゲームクライアントに送信する必要があります.
    cmd/frontendapi
    CreatePlayer()は、Playerオブジェクトをredisに書き込む、キー値をPlayerとする.Id、タイプはHSETです.Playerの各attributeをZSETに追加します.ここでPlayerはプレイヤーのグループです.
    GetUpdates()は2 sおきにredisを読み出し,Playerデータが変化した場合に送信する.ここでPlayerはシングルプレイヤーです.
    CreatePlayer()に1人のプレイヤーしかいない場合、書き込まれたPlayerはGetUpdates()で読み込まれたプレイヤーと同じredisキーとなる.
    cmd/backendapi
    CreateMatch()のprofileタイプはMatchObjectであり、試合の制限条件である.profileはredisに書き込み、キーはprofile.Id.requestKey := xid() + "." + profile.Idは、requestKeyをredisセット「profileq」に追加する.その後、2 sごとにredisをクエリーし、requestKeyキーが表示されるかどうかを確認し、値を返します.
    ListMatch()は2 s毎にCreateMatch()を呼び出す.
    DeleteMatch()はIdというキーのみを削除します.
    CreateAssignments()は、複数のチームにAssignment、すなわちルームアドレスを設定します.すべてのRosterのPlayerオブジェクトを巡回し、redisでAssignmentを設定.(Assignmentが変更されると、フロントエンドの更新がトリガーされます.)すべてのPlayerをIdは「proposed」から「deindexed」に移動し、この2つはZSETであり、加算時間に分けられる.Rosterは試合中の陣営であるべきで、例えば紅方、藍方、各陣営には複数のチームがある.
    DeleteAssignments()は、すべてのPlayerオブジェクトのみを巡回してAssignmentフィールドを削除します.
    cmd/mmforc
    マッチングフローはmmforc(matchmaking function orchestrator)によって制御される.
    mmforcは、redisのprofileqから毎秒100人のメンバーを取り出す、profileqはsetタイプであり、使用コマンドはSPOP profileq 100である.
    profileごとにk 8 sタスクを作成します.
    	// Kick off the job asynchrnously
    	go mmfunc(ctx, profile, cfg, defaultMmfImages, clientset, &pool)
    

    10 sごとに、またすべてのマッチングタスクが完了すると、checkProposals、すなわちevaluatorタスクを作成する必要があります.
    profileqの要素profileは文字列、matchObjectIDです.profileID. Profile IDをキーとして、MatchObjectオブジェクトであるredisからprofileの内容を読み込むことができます.
    profileの内容はjson列で、「jsonkeys.mmfImages」はmmf(matchmaking function)ミラーです.
    プロファイルの読み込みに失敗した場合、またはmmfImagesが空の場合は、デフォルトのミラーが使用されます.mmfImagesは今後、複数のミラーをサポートします.
    MMF_*経由環境変数は各種パラメータに伝達する.
    mmf
    例:examplesfunctionsgolangmanual-simple
    環境変数「MMF_PROFILE_ID」からprofile IDを解析し、redisにprofile、HSETタイプを問い合わせる.
    profileからpoolsフィールド、すなわち一致条件を取ります.poolsは複数のpoolに分ける、各poolには複数のfilterがあり、各filterはredisに該当するPlayerを取り出す.
    profileでは、次のフィールドを使用します.
  • 「properties.playerPool」json列は、「mmr:100-999」
  • などのフィルタ条件です.
  • 「properties.roster」json列は、「red:4」
  • のような複数のチームサイズです.
    例:examples\backendclient\profiles\testprofile.json単純マッチングプロセス
    Simple mmfのマッチングプロセスは以下の通りです.
  • redisからprofileを問合せ、フィルタ条件と各チームサイズ
  • を取得する.
  • 各フィルタ条件はredisにクエリされ、すべての結果の交差はオプションメンバー
  • である.
  • ignoreList、すなわち最近800 sで一致したメンバー、すなわちproposalおよびdeindexed ZSETリストを除去する.
  • オプションメンバー数が小さすぎる場合insufficient_Playersを終了し、
  • を終了します.
  • 各チームメンバーを割り当てる
  • redisに結果
  • を記録する.
    結果
    profileにroster、すなわち各陣営のメンバーリストを追加し、prososalKey.に格納する.チームを区別しないメンバーリストを保存します.そして「proposalq」にprososalKeyを追加
    詳細
    poolRostersは(pool名、filter attribute)をキー、値はPlayer IDリストである.redisから照会する条件を満たすPlayer IDを保存する.
    overlapsはpool名をキーとして、そのpool中の全てのfilterに適合するPlayer IDリストを保存するignore listを除去する.
    rostersはprofileの「properties.rosters」フィールドです.何の役に立つか分からない.rostersを巡り、各陣営のプレイヤーごとにpoolに対応するPlayerIDを見つけてmo.Rostersに保存する.その中でprofileRostersは役に立たないようです.