首先我们会介绍 Director 是如何实作的,并介绍 Director 跟 Open-Match 核心互动的方式。而 Director 在完成配对指派的过程中,向核心调用 Match Function 所需完成的逻辑与接口,会一并於本编介绍。
Director 透过持续向 Open-Match Backend 呼叫,取出 Matches(配对组合) ,并且将符合配对逻辑的 Matches 与 DGS(游戏服务器)介接,可对照 demo director.go 状态 "Connecting to backend" 至 "Match Match: Sending Request" 的部分。
MatchProfile (配对剖析)用来定义一场配对的条件或规格,藉由这些限制来决定哪一些玩家可以参与本次配对。MatchProfile 被传递至 Match Function 参与配对逻辑,以 MatchProfile 的条件搭配上 Match Function 的逻辑筛选,完成後产出配对结果。
type MatchProfile struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Name of this match profile.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// Set of pools to be queried when generating a match for this MatchProfile.
Pools []*Pool `protobuf:"bytes,3,rep,name=pools,proto3" json:"pools,omitempty"`
// Customized information not inspected by Open Match, to be used by the match
// making function, evaluator, and components making calls to Open Match.
// Optional, depending on the requirements of the connected systems.
Extensions map[string]*any.Any `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
实作时需注意 Pools 将决定取用含有哪些条件的配对池
req := &pb.FetchMatchesRequest{
Config: &pb.FunctionConfig{
Host: "om-function.open-match-demo.svc.cluster.local",
Port: 50502,
Type: pb.FunctionConfig_GRPC,
},
//Pools 将决定取用含有哪些条件的配对池
Profile: &pb.MatchProfile{
Name: "1v1",
Pools: []*pb.Pool{
{
Name: "Everyone",
},
},
},
}
stream, err := be.FetchMatches(ds.Ctx, req)
if err != nil {
panic(err)
}
透过给定 Pool.DoubleRangeFilters
, Pool.StringEqualsFilters
, Pool.TagPresentFilters
可决定哪些条件可进入配对池。在上面的 demo 的例子来说,由於没有指定 Pool filter 内容,所以所有的条件都可以进入配对。
type Pool struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// A developer-chosen human-readable name for this Pool.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// Set of Filters indicating the filtering criteria. Selected tickets must
// match every Filter.
DoubleRangeFilters []*DoubleRangeFilter `protobuf:"bytes,2,rep,name=double_range_filters,json=doubleRangeFilters,proto3" json:"double_range_filters,omitempty"`
StringEqualsFilters []*StringEqualsFilter `protobuf:"bytes,4,rep,name=string_equals_filters,json=stringEqualsFilters,proto3" json:"string_equals_filters,omitempty"`
TagPresentFilters []*TagPresentFilter `protobuf:"bytes,5,rep,name=tag_present_filters,json=tagPresentFilters,proto3" json:"tag_present_filters,omitempty"`
// If specified, only Tickets created before the specified time are selected.
CreatedBefore *timestamp.Timestamp `protobuf:"bytes,6,opt,name=created_before,json=createdBefore,proto3" json:"created_before,omitempty"`
// If specified, only Tickets created after the specified time are selected.
CreatedAfter *timestamp.Timestamp `protobuf:"bytes,7,opt,name=created_after,json=createdAfter,proto3" json:"created_after,omitempty"`
}
Match Function (配对函式)於配对过程中被核心所调用,开发者需依据游戏的需求,实作符合各种标签属性的配对方法,透过 MatchProfiles(配对剖析) 里的 Tickets 产出每一场 Matches(配对组合)。
Run 为满足 Open-Match 所需要 interface 的方法,可直接参考范例做法将配对池取出後,透过自订义的 makeMatches (配对逻辑)
完成期望的配对请求。
// 满足 interface
// Run is this match function's implementation of the gRPC call defined in api/matchfunction.proto.
func (s *matchFunctionService) Run(req *pb.RunRequest, stream pb.MatchFunction_RunServer) error {
// Fetch tickets for the pools specified in the Match Profile.
log.Printf("Generating proposals for function %v", req.GetProfile().GetName())
poolTickets, err := matchfunction.QueryPools(stream.Context(), s.queryServiceClient, req.GetProfile().GetPools())
if err != nil {
log.Printf("Failed to query tickets for the given pools, got %s", err.Error())
return err
}
// 自定义配对逻辑
proposals, err := makeMatches(poolTickets)
if err != nil {
log.Printf("Failed to generate matches, got %s", err.Error())
return err
}
log.Printf("Streaming %v proposals to Open Match", len(proposals))
// Stream the generated proposals back to Open Match.
for _, proposal := range proposals {
if err := stream.Send(&pb.RunResponse{Proposal: proposal}); err != nil {
log.Printf("Failed to stream proposals to Open Match, got %s", err.Error())
return err
}
}
return nil
}
//自定义配对逻辑
func makeMatches(poolTickets map[string][]*pb.Ticket) ([]*pb.Match, error) {
//TODO 做一些条件筛选
...
return matches, nil
}
停留回想:要进入下一篇前,整理回顾一下环境篇的笔记思绪。 今日要点: 》环境篇回顾整理 》系列目录...
“萤幕时间”是 iOS 12 中引入的一项新功能,专门帮助用户有效地使用 iPhone 管理时间,防...
一提到「搜寻引擎优化」(Search Engine Optimization, SEO),许多人可...
前言 昨天我们写好了测试的 model,今天就来用他实作吧。 test_main 我们先从最简单的 ...
filter filter() 会建立一个新的阵列,其内容为原阵列的每一个元素经由回呼函式判断後所回...