Open-matchマッチングプロセス
4754 ワード
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に必要なすべてのパラメータです.
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.
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タイプであり、使用コマンドは
profileごとにk 8 sタスクを作成します.
10 sごとに、またすべてのマッチングタスクが完了すると、
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」 のような複数のチームサイズです.
例:
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は役に立たないようです.
(金慶のコラム2019.1)
https://github.com/GoogleCloudPlatform/open-match
Open-matchは汎用的なゲームマッチングフレームワークです.ゲームによってカスタムマッチングアルゴリズムが提供されます(dockerミラーで提供されます).
複数のプロセスに分け、各プロセス間で1つのredisを共有する.
ゲームウェアに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では、次のフィールドを使用します.
例:
examples\backendclient\profiles\testprofile.json
単純マッチングプロセスSimple mmfのマッチングプロセスは以下の通りです.
結果
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は役に立たないようです.