Day6 Director & Match Function

首先我们会介绍 Director 是如何实作的,并介绍 Director 跟 Open-Match 核心互动的方式。而 Director 在完成配对指派的过程中,向核心调用 Match Function 所需完成的逻辑与接口,会一并於本编介绍。

Director

Director 透过持续向 Open-Match Backend 呼叫,取出 Matches(配对组合) ,并且将符合配对逻辑的 Matches 与 DGS(游戏服务器)介接,可对照 demo director.go 状态 "Connecting to backend" 至 "Match Match: Sending Request" 的部分。

https://i.imgur.com/I4Mdxw7.png

MatchProfile

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

透过给定 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

Match Function (配对函式)於配对过程中被核心所调用,开发者需依据游戏的需求,实作符合各种标签属性的配对方法,透过 MatchProfiles(配对剖析) 里的 Tickets 产出每一场 Matches(配对组合)。

https://i.imgur.com/4RcjOnA.png

Run

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
}

<<:  [DAY6]从0开始装k8s(1)-kind

>>:  个人管理 - 抓到组织的脉动,把事情做在前面

【Day 10】Google Apps Script - 环境篇回顾整理

停留回想:要进入下一篇前,整理回顾一下环境篇的笔记思绪。 今日要点: 》环境篇回顾整理 》系列目录...

如何解锁iPhone 萤幕时间密码?

“萤幕时间”是 iOS 12 中引入的一项新功能,专门帮助用户有效地使用 iPhone 管理时间,防...

外贸谷歌SEO入门技巧:从优化标题和调整文字排版开始

一提到「搜寻引擎优化」(Search Engine Optimization, SEO),许多人可...

Day 16 实作测试 (2)

前言 昨天我们写好了测试的 model,今天就来用他实作吧。 test_main 我们先从最简单的 ...

JavaScript Day18 - 阵列操作(filter、find、findIndex)

filter filter() 会建立一个新的阵列,其内容为原阵列的每一个元素经由回呼函式判断後所回...