今天我們要自己假訂一個配對情境,來做一個比官方稍微複雜一點點的 Demo,並且透過這個模擬情境的實踐,來熟悉 Open-Match 在實作上須滿足的接口與函式用法。
隨機產生兩個地區、兩種職業與不同等級條件的配對請求,並且將兩個不同職業才能配對的邏輯,加入我們的配對邏輯中
移除官方 demo (若無部署可以跳過)
kubectl delete namespaces open-match-demo
下載本次範例用 yaml
open-match/open-match-role-location-demo.yml at example-a.2 · WeiWeiWesley/open-match
主要基於官方 yaml 替換掉 demo 與 mmf 的 images 為本次範例所需要的情境
- name: om-demo
image: "weiweiwesley/open-match:example-a.2"
...
- name: om-function
image: "weiweiwesley/mmf_role_location:diff_role.2"
...
部署
kubectl create namespace open-match-demo
kubectl apply -n open-match-demo -f open-match-role-location-demo.yml
以時間亂數產生不同的配對請求,分別將不同型態的條件放到 StringArgs
與 DoubleArgs
內。實務上這些資料,更可能是由撈取使用者資料庫獲得。
var ticketId string
{
ticket := &pb.Ticket{}
//隨機產生不同條件
//兩個地區
//兩種職業
//等級 0~30
switch time.Now().Unix() % 4 {
case 0:
ticket.SearchFields = &pb.SearchFields{
StringArgs: map[string]string{
"location": "Asia/Taiwan",
"role": "knight",
},
DoubleArgs: map[string]float64{
"level": float64(rand.Int31n(30)),
},
}
case 1:
ticket.SearchFields = &pb.SearchFields{
StringArgs: map[string]string{
"location": "Asia/Taiwan",
"role": "archer",
},
DoubleArgs: map[string]float64{
"level": float64(rand.Int31n(30)),
},
}
case 2:
ticket.SearchFields = &pb.SearchFields{
StringArgs: map[string]string{
"location": "Asia/Japan",
"role": "knight",
},
DoubleArgs: map[string]float64{
"level": float64(rand.Int31n(30)),
},
}
case 3:
ticket.SearchFields = &pb.SearchFields{
StringArgs: map[string]string{
"location": "Asia/Japan",
"role": "archer",
},
DoubleArgs: map[string]float64{
"level": float64(rand.Int31n(30)),
},
}
}
req := &pb.CreateTicketRequest{Ticket: ticket}
s.Status = fmt.Sprintf("Create ticket role: %s location: %s", ticket.SearchFields.StringArgs["role"], ticket.SearchFields.StringArgs["location"])
update(s)
time.Sleep(time.Second)
resp, err := fe.CreateTicket(ctx, req)
if err != nil {
panic(err)
}
ticketId = resp.Id
}
Match Function 是我們實作配對邏輯的部份,這邊可以看到我們能針對 ticket.SearchFields
的內容,對請求是否進行同場配對做篩選 ,previousRole
在記錄下玩家角色後,會拒絕配對相同角色的玩家。
func makeMatches(poolTickets map[string][]*pb.Ticket) ([]*pb.Match, error) {
tickets := map[string]*pb.Ticket{}
for _, pool := range poolTickets {
for _, ticket := range pool {
tickets[ticket.GetId()] = ticket
}
}
var matches []*pb.Match
t := time.Now().Format("2006-01-02T15:04:05.00")
thisMatch := make([]*pb.Ticket, 0, 2)
matchNum := 0
previousRole := ""
for _, ticket := range tickets {
log.Println("pairing:", ticket.Id, ticket.SearchFields.StringArgs["role"])
//若同職業則會跳過此次配對
if previousRole != ticket.SearchFields.StringArgs["role"] {
thisMatch = append(thisMatch, ticket)
previousRole = ticket.SearchFields.StringArgs["role"]
}
if len(thisMatch) >= 2 {
matches = append(matches, &pb.Match{
MatchId: fmt.Sprintf("profile-%s-time-%s-num-%d", matchName, t, matchNum),
MatchProfile: matchName,
MatchFunction: matchName,
Tickets: thisMatch,
})
log.Println("pairing success", thisMatch[0].SearchFields.StringArgs["role"], thisMatch[1].SearchFields.StringArgs["role"])
previousRole = ""
thisMatch = make([]*pb.Ticket, 0, 2)
matchNum++
}
}
return matches, nil
}
基於 Open-Match 框架已經將 MMF 獨立為一個服務實體啟動,我們可以利用 kubernetes rolling update 的特性,動態的抽換線上的 MMF。我們可以試著將本篇範例的 MMF,再度更換為官方demo 的映像黨,並重新 apply 上便可以再度恢復成任意兩人即可配對成功。
更換 MMF
- name: om-function
image: "gcr.io/open-match-public-images/openmatch-mmf-go-soloduel:1.2.0"
Just apply again
kubectl apply -n open-match-demo -f open-match-role-location-demo.yml
單純利用 tickets 的資料進行條件篩選,這在 client or MMF 實作上都是非常簡易的,我們可以依照遊戲的各種特性,以及玩家遊玩過程與實體所產生的資料來產生不同的配對條件。本次範例中僅用兩種不同角色即可配對,而那些沒有配對到的玩家,會等到出現不同角色時才配對,這可能會發生一個尷尬的情況:如果大家都是選擇相同角色時,所有人都會卡在配對等待中的狀態。為了避免等待時間過長,之後一點的篇幅會再用一個範例來教大家如何釋放 tickets。
此外由於本次範例是想沿用官方 demo 介面,直接從官方demo fork 出來異動,會有一些 golang 相依上的一些問題,這與 Open-Match 本身的使用上沒有直接相關,所以為了讓範例順利已將 images 放在 dockerHub 上。