Nakama 매치메이커 기능을 사용하면 사용자는 다른 사용자(팀 동료 또는 상대방)를 검색하고 짝을 지어 대결, 그룹을 형성하거나 프로젝트에 내장된 기타 소셜 기능에 참여할 수 있습니다.
매치메이커는 사용자 풀과 매치메이킹 요청(“티켓”)을 유지 관리하고 좋은 대결이 발견될 때마다 이들을 함께 배치합니다. 특정 사용자에 대한 “좋은 대결"의 정의는 해당 매치메이커 티켓에 정의된 기준을 기반으로 합니다. 대결이 발견되기까지의 시간은 기준이 얼마나 구체적으로 정의되었는지와 현재 매치메이킹 풀에 있는 사용자 수에 따라 매우 다양합니다. 매치메이킹 기간이 너무 길거나 대결이 전혀 발견되지 않으면 기준을 넓혀 보십시오.
매치메이킹은 활성 플레이어(오픈 소켓 연결이 있는 사용자)에만 적용됩니다. 매치메이커 티켓을 제출하면(사용 가능한 플레이어의 매치메이커 풀에 자신을 추가) 사용자는 대결을 찾거나 요청을 취소할 때까지 풀에 남습니다. 사용자가 연결을 끊으면 보류 중인 매치메이킹 요청도 취소됩니다.
매치메이킹은 Nakama의 대결 목록 기능과 다릅니다. 매치메이커가 사용자를 함께 배치하여 새 대결을 시작하는 데 사용되는 반면, 대결 목록은 사용자에게 즉시 가입할 수 있는 기존 대결을 표시하는 데 사용됩니다. 매치메이킹 또는 대결 목록 사용을 결정하는 것은 프로젝트 목표 및 요구 사항을 기반으로 하는 설계 고려 사항(기술적 고려 사항 아님)입니다.
매치메이커 기능에 영향을 미치는 몇 가지 매개변수를 Nakama 구성에 사용할 수 있습니다.
사용자가 한 번에 가질 수 있는 최대 동시 티켓 수를 설정하여 사용자가 지나치게 많은 티켓을 제출하는 것을 방지하고 이전 티켓을 절대 취소하지 못하도록 만들 수 있습니다.
매치메이커가 사용자의 “이상적인”(크기) 대결을 찾으려고 시도하는 시간 간격과, 덜 이상적인(크기) 대결을 허용하기까지의 간격의 수를 설정하여, 사용자의 대기 시간을 조정하고 이상적인 대결을 찾는 것과 더 빨리 대결을 시작하는 것 사이의 균형을 조정할 수 있습니다.
역매칭 정밀도 및 임계값 플래그는 역매칭 정밀도 활성화 여부와 기간을 지정하는 데 사용됩니다. 활성화된 경우(rev_precision이 true로 설정된 경우), 매치메이커는 양방향으로 매치의 유효성을 검사합니다(즉, 플레이어 A가 플레이어 B와 매치할 때 플레이어 B도 플레이어 A와 매치하는지 확인합니다). 양방향 매칭이 아닌 경우, 매치메이커는 rev_threshold 간격 동안 양방향 매칭을 계속 검색합니다. 간격 수(기본값은 1) 내에 양방향 매치를 찾지 못하면 매치메이커는 단방향 매치를 반환합니다.
var(errInternal=runtime.NewError("internal server error",13))funcInitModule(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,initializerruntime.Initializer)error{initializer.RegisterBeforeRt("MatchmakerAdd",func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*rtapi.Envelope)(*rtapi.Envelope,error){message,ok:=in.Message.(*rtapi.Envelope_MatchmakerAdd)if!ok{returnnil,errInternal}// If the string properties contains a region value of "europe", modify it to "europe-west"
ifvalue,ok:=message.MatchmakerAdd.StringProperties["region"];ok&&value=="europe"{message.MatchmakerAdd.StringProperties["region"]="europe-west"}returnin,nil})returnnil}
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
functionInitModule(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,initializer: nkruntime.Initializer){initializer.registerRtBefore("MatchmakerAdd",beforeMatchmakerAdd)}constbeforeMatchmakerAdd : nkruntime.RtBeforeHookFunction<nkruntime.EnvelopeMatchmakerAdd>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,envelope: nkruntime.EnvelopeMatchmakerAdd):nkruntime.EnvelopeMatchmakerAdd|void{constregion=envelope.matchmakerAdd.stringProperties["region"];// If the string properties contain a region value of "europe", modify it to "europe-west"
if(region&®ion=="europe"){envelope.matchmakerAdd.stringProperties["region"]="europe-west";}returnenvelope;}
Server
1
2
3
4
5
6
7
8
9
10
nk.register_rt_before(function(context,payload)localregion=payload.matchmaker_add.string_properties["region"]-- If the string properties contain a region value of "europe", modify it to "europe-west"ifregion=="europe"thenpayload.matchmaker_add.string_properties["region"]="europe-west"endreturnpayloadend,"MatchmakerAdd")
매치메이커 요청을 제출할 때 사용자는 최소 및 최대 수를 모두 지정해야 합니다. 여기서 minCount은(는) 허용 가능한 가장 작은 대결 크기를, maxCount은(는) 허용 가능한 가장 큰 대결 크기를 나타내며 둘 다 요청을 제출하는 플레이어가 포함됩니다.
매치메이커는 항상 제공된 최대 수에서 대결을 시도합니다. 사용자가 충분하지 않은 경우 최소 수 이상이라면 최대 수에 가장 가까운 크기가 대결로 반환됩니다.
예를 들어 최소 수가 2이고 최대 수가 4인 경우 매치메이커는 사용자와 일치시킬 다른 3명의 플레이어를 찾으려고 시도합니다. 3명의 일치하는 플레이어가 없는 경우 매치메이커는 다른 2명과 일치시키려고 시도하고 2명이 안되는 경우 마지막으로 다른 플레이어 1명만 찾습니다.
사용 가능한 사용자가 최소 수에도 못 미치면 대결이 반환되지 않고 사용자는 풀에 남습니다.
var(errInternal=runtime.NewError("internal server error",13))funcInitModule(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,initializerruntime.Initializer)error{initializer.RegisterBeforeRt("MatchmakerAdd",func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*rtapi.Envelope)(*rtapi.Envelope,error){message,ok:=in.Message.(*rtapi.Envelope_MatchmakerAdd)if!ok{returnnil,errInternal}// Force min count to be 4 and max count to be 8
message.MatchmakerAdd.MinCount=4message.MatchmakerAdd.MaxCount=8returnin,nil})returnnil}
Server
1
2
3
4
5
6
7
8
9
10
11
functionInitModule(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,initializer: nkruntime.Initializer){initializer.registerRtBefore("MatchmakerAdd",beforeMatchmakerAdd)}constbeforeMatchmakerAdd : nkruntime.RtBeforeHookFunction<nkruntime.EnvelopeMatchmakerAdd>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,envelope: nkruntime.EnvelopeMatchmakerAdd):nkruntime.EnvelopeMatchmakerAdd|void{// Force min count to be 4 and max count to be 8
envelope.matchmakerAdd.minCount=4envelope.matchmakerAdd.maxCount=8returnenvelope;}
Server
1
2
3
4
5
6
7
nk.register_rt_before(function(context,payload)-- Force min count to be 4 and max count to be 8payload.matchmaker_add.min_count=4payload.matchmaker_add.max_count=8returnpayloadend,"MatchmakerAdd")
Code snippet for this language C++/Unreal/Cocos2d-x has not been found. Please choose another language to show equivalent examples.
Code snippet for this language Defold has not been found. Please choose another language to show equivalent examples.
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.
매치메이커는 5의 배수인 총 일치 플레이어 수가 포함된 결과만 반환하며, 먼저 최대 25개를 반환한 다음 20, 15 등의 방식으로 최대 수를 반환합니다. 23명의 일치하는 플레이어가 있어도 반환된 결과는 20명의 플레이어입니다.
매치메이커에 사용자를 추가할 때 before 후크를 사용하여 수 승수를 정식으로 제어할 수도 있습니다:
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var(errInternal=runtime.NewError("internal server error",13))funcInitModule(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,initializerruntime.Initializer)error{initializer.RegisterBeforeRt("MatchmakerAdd",func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*rtapi.Envelope)(*rtapi.Envelope,error){message,ok:=in.Message.(*rtapi.Envelope_MatchmakerAdd)if!ok{returnnil,errInternal}// Force the count multiple to be in multiples of 5
message.MatchmakerAdd.CountMultiple=&wrapperspb.Int32Value{Value:5}returnin,nil})returnnil}
Server
1
2
3
4
5
6
7
8
9
10
functionInitModule(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,initializer: nkruntime.Initializer){initializer.registerRtBefore("MatchmakerAdd",beforeMatchmakerAdd)}constbeforeMatchmakerAdd : nkruntime.RtBeforeHookFunction<nkruntime.EnvelopeMatchmakerAdd>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,envelope: nkruntime.EnvelopeMatchmakerAdd):nkruntime.EnvelopeMatchmakerAdd|void{// Force the count multiple to be in multiples of 5
envelope.matchmakerAdd.countMultiple=5;returnenvelope;}
Server
1
2
3
4
5
6
nk.register_rt_before(function(context,payload)-- Force the count multiple to be in multiples of 5payload.matchmaker_add.count_multiple=5returnpayloadend,"MatchmakerAdd")
Code snippet for this language Defold has not been found. Please choose another language to show equivalent examples.
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.
매치메이커에 사용자를 추가할 때 before 후크를 사용하여 쿼리를 정식으로 제어할 수도 있습니다:
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var(errInternal=runtime.NewError("internal server error",13))funcInitModule(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,initializerruntime.Initializer)error{initializer.RegisterBeforeRt("MatchmakerAdd",func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,in*rtapi.Envelope)(*rtapi.Envelope,error){message,ok:=in.Message.(*rtapi.Envelope_MatchmakerAdd)if!ok{returnnil,errInternal}// Force the matchmaking request to use the * query
message.MatchmakerAdd.Query="*"returnin,nil})returnnil}
Server
1
2
3
4
5
6
7
8
9
10
functionInitModule(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,initializer: nkruntime.Initializer){initializer.registerRtBefore("MatchmakerAdd",beforeMatchmakerAdd)}constbeforeMatchmakerAdd : nkruntime.RtBeforeHookFunction<nkruntime.EnvelopeMatchmakerAdd>=function(ctx: nkruntime.Context,logger: nkruntime.Logger,nk: nkruntime.Nakama,envelope: nkruntime.EnvelopeMatchmakerAdd):nkruntime.EnvelopeMatchmakerAdd|void{// Force the matchmaking request to use the * query
envelope.matchmakerAdd.query="*";returnenvelope;}
Server
1
2
3
4
5
6
nk.register_rt_before(function(context,payload)-- Force the matchmaking request to use the * querypayload.matchmaker_add.query="*"returnpayloadend,"MatchmakerAdd")
매치메이킹 요청의 성공 또는 대결을 찾는 데 필요한 시간은 모두 매치메이커에서 활성화된 사용자 풀과 대결에서 찾는 특정 기준에 따라 달라지므로 보장되지 않습니다.
동일한 요청을 반복적으로 제출해도 결과는 같습니다. 이러한 이유로 매치메이킹 요청에 인위적인 시간 제한을 두는 것은 권장되지 않습니다.
활성 사용자 수와 매치메이킹에 사용된 해당 기준에 따라 원하는 정확한 대결을 찾기가 어렵거나 불가능할 수 있습니다.
사용 중인 기준을 효과적으로 “확장"하려면 플레이어는 티켓마다 이전 티켓보다 더 허용적인 쿼리가 있는 여러 티켓을 제출해야 합니다.
예를 들어, 플레이어가 해당 지역에 있고 정확히 동일한 기술 수준에 있는 다른 플레이어와 대결하기를 원하지만 결과를 얻지 못하는 경우, 후속 티켓은 다른 지역을 포함하도록 확장될 수 있고 플레이어의 수준과 비슷한 기술 수준 _범위_가 허용될 수 있습니다.
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
letquery="+properties.region:europe +properties.rank:5";constminCount=2;constmaxCount=4;conststringProperties={region:"europe"};constnumericProperties={rank:8};varticket=awaitsocket.addMatchmaker(query,minCount,maxCount,stringProperties,numericProperties);// ... if no match is found within a certain time, request a new ticket with looser criteria
query="+properties.region:europe +properties.rank:>=3 +properties.rank:<=7";varnewTicket=awaitsocket.addMatchmaker(query,minCount,maxCount,stringProperties,numericProperties);
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
varquery="+properties.region:europe +properties.rank:5";varstringProperties=newDictionary<string,string>(){{"region","europe"}};varnumericProperties=newDictionary<string,int>(){{"rank",8}};varmatchmakerTicket=awaitsocket.AddMatchmakerAsync(query,2,4,stringProperties,numericProperties);// ... if no match is found within a certain time, request a new ticket with looser criteriaquery="+properties.region:europe +properties.rank:>=3 +properties.rank:<=7";varnewMatchmakerTicket=awaitsocket.AddMatchmakerAsync(query,2,4,stringProperties,numericProperties);
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
autosuccessCallback=[](constNMatchmakerTicket&ticket){std::cout<<"Matchmaker ticket: "<<ticket.ticket<<std::endl;};int32_tminCount=2;int32_tmaxCount=4;stringquery="+properties.region:europe +properties.rank:5";NStringMapstringProperties;NStringDoubleMapnumericProperties;stringProperties.emplace("region","europe");numericProperties.emplace("rank",8.0);rtClient->addMatchmaker(minCount,maxCount,query,stringProperties,numericProperties,successCallback);// ... if no match is found within a certain time, request a new ticket with looser criteria
query="+properties.region:europe +properties.rank:>=3 +properties.rank:<=7";rtClient->addMatchmaker(minCount,maxCount,query,stringProperties,numericProperties,successCallback);
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Stringquery="+properties.region:europe +properties.rank:5";intminCount=2;intmaxCount=4;Map<String,String>stringProperties=newHashMap<String,String>(){{put("region","europe");}};Map<String,Double>numericProperties=newHashMap<String,Double>(){{put("rank",8.0);}};MatchmakerTicketmatchmakerTicket=socket.addMatchmaker(query,minCount,maxCount,stringProperties,numericProperties).get();// ... if no match is found within a certain time, request a new ticket with looser criteriaquery="+properties.region:europe +properties.rank:>=3 +properties.rank:<=7";MatchmakerTicketnewMatchmakerTicket=socket.addMatchmaker(query,minCount,maxCount,stringProperties,numericProperties).get();
func_ready():# First, setup the socket as explained in the authentication section.socket.connect("received_matchmaker_matched",self,"_on_matchmaker_matched")func_on_matchmaker_matched(p_matched:NakamaRTAPI.MatchmakerMatched):print("Received MatchmakerMatched message: %s"%[p_matched])print("Matched opponents: %s"%[p_matched.users])
Code snippet for this language Defold has not been found. Please choose another language to show equivalent examples.
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.
매치메이커 결과에는 매치된 모든 사용자와 각각의 [properties]이(가) 포함됩니다.
결과에는 이 일치하는 플레이어 그룹의 새 대결에 가입하는 데 사용할 수 있는 토큰 또는 대결 ID도 포함됩니다. 포함되는 항목은 대결 유형에 따라 다릅니다. 클라이언트 중계 대결의 경우 토큰이 제공되고 서버 정식 대결의 경우 대결 ID가 제공됩니다.
정식 대결의 경우 매치메이커 결과가 반환될 때 서버 후크를 사용하여 서버에서 새 대결을 생성할 수 있습니다.
Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var(errUnableToCreateMatch=runtime.NewError("unable to create match",13))funcInitModule(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,initializerruntime.Initializer)error{iferr:=initializer.RegisterMatchmakerMatched(func(ctxcontext.Context,loggerruntime.Logger,db*sql.DB,nkruntime.NakamaModule,entries[]runtime.MatchmakerEntry)(string,error){matchId,err:=nk.MatchCreate(ctx,"lobby",map[string]interface{}{"invited":entries})iferr!=nil{return"",errUnableToCreateMatch}returnmatchId,nil});err!=nil{logger.Error("unable to register matchmaker matched hook: %v",err)returnerr}returnnil}
Nakama의 실시간 파티를 통해 사용자는 지정된 세션 동안만 유지되는 단기 팀으로 뭉쳐서 함께 플레이할 수 있습니다. 일단 파티로 그룹화되면 이 플레이어들은 함께 매치메이킹을 할 수 있어 궁극적으로 같은 대결에 배정됩니다.
각 파티에는 지정된 리더가 있으며 일반적으로 해당 파티를 만든 사용자입니다. 이 리더는 매치메이킹에 사용할 기준을 설정하고 해당 파티를 매치메이커 풀에 추가합니다:
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Register the matchmaker matched handler (the party leader and party members should all do this)
socket.onmatchmakermatched=(matched)=>{socket.joinMatch(null,matched.token);};// Create a party as the party leader
constparty=awaitsocket.createParty(true,2);// Accept any incoming party requests
socket.onpartyjoinrequest=(request)=>{request.presences.forEach(presence=>{awaitsocket.acceptPartyMember(request.party_id,presence);});};// As the leader of the party, add the entire party to the matchmaker
constticket=awaitsocket1.addMatchmakerParty(party.party_id,"*",3,4,null,null);
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Register the matchmaker matched handler (the party leader and party members should all do this)socket.ReceivedMatchmakerMatched+=asyncmatched=>awaitsocket.JoinMatchAsync(matched);// Create a party as the party leadervarparty=awaitsocket.CreatePartyAsync(true,2);// Accept any incoming party requestssocket.ReceivedPartyJoinRequest+=asyncrequest=>{foreach(varpresenceinrequest.Presences){awaitsocket.AcceptPartyMemberAsync(request.PartyId,presence);}};// As the leader of the party, add the entire party to the matchmakervarticket=awaitsocket.AddMatchmakerPartyAsync(party.Id,"*",3,4);