跳到主要内容

规则集参考

1. 概述

以下文档首先提供了一个带有注释的规则集示例,帮助读者建立规则集组件的基本概念,然后介绍规则集语法的架构。

2. 规则集示例

这里是一个带有详细注释的规则集示例。

  • 它展示了两个玩家属性:
    • skill:表示玩家的技能点数,该属性在 PGOS 玩家数据中定义,其值将由 PGOS 后端自动获取。
    • mode:表示玩家在进入匹配前选择的游戏模式,该属性在规则集中定义,其值应由游戏客户端通过 PGOS SDK 传递。
// The section of playerAttributes describes the player attributes used in the matching rules
"playerAttributes": [
{
"name": "skill", // The skill value of a player, the most common case is calculated by ELO algorithm
"key": "skill", // With this key, this attribute will be automatically retrieved from Player KVData in which key is "skill"
"type": "number", // Data type of attribute, can be "number" or "string"
"default": 0,
"partyAggregation": "avg" // Use the avg value for multiplayer matchmaking ticket
},
{
"name": "mode", // The game mode such as PvP or PvE, which must be submited from game client
"type": "string", // Data type of attribute, can be "number" or "string"
"default": "solo"
}
],
  • 它定义了两支队伍:
    • 红队:4~8名玩家。
    • 蓝队:4~8名玩家。
// The section of "teams" describes the team structure of the game
// The matchmaking system will try to gather as many players as the maxPlayers indicates. And it will compromise to minPlayers if there are not enough players in matchmaking pool.
"teams": [
{
"name": "red", // The size of red team is 4~8 players
"maxPlayers": 8,
"minPlayers": 4
},
{
"name": "blue", // The size of blue team is 4~8 players
"maxPlayers": 8,
"minPlayers": 4
}
],
  • 它有四个规则:
    • skillRule:使战斗中玩家的技能值尽可能接近。
    • modeRule:确保玩家选择的模式值必须相同。
    • countRule1:确保红队和蓝队拥有相同数量的玩家。
    • countRule2:效果与countRule1相同,但展示了另一种配置方式。
// You can add multiple rule descriptions to the section of "rules", and PGOS searches for players based on these rules
"rules": [
{
// Makes the skill value of players in a battle as close as possible.
"name": "skillRule",
"type": "distanceRule",
"measurements": [
"flatten(teams[*].players.playerAttributes[skill])"
],
"referenceValue": "avg(flatten(teams[*].players.playerAttributes[skill]))",
"maxDistance": 50
},
{
// Guarantees that mode value players selected must be the same.
"name": "modeRule",
"type": "comparisonRule",
"measurements": [
"flatten(teams[*].players.playerAttributes[mode])"
],
"operation": "="
},
{
// Guarantees that both red and blue team has equal number of players.
"name": "countRule1",
"type": "comparisonRule",
"measurements": [
"count(teams[*].players)"
],
"operation": "="
},
{
// Effects the same as countRule1, but demonstrates another way to configure.
"name": "countRule2",
"type": "comparisonRule",
"measurements": [
"count(teams[blue].players)"
],
"referenceValue": "count(teams[red].players)",
"operation": "="
}
],
  • 它有两种扩展方式:
    • 如果在5秒内未找到匹配对局,skillRule的maxDistance将扩展到100,在10秒时扩展到200。
    • 如果在5秒内未找到匹配,最小队伍人数将减少到2人,在10秒时减少到1人。
// The section of "expansions" is "rules" expansions
// The meaning of the first expansion is:
// (1). Wait for 5s, if thereis no matchmaking result, then modify rules[skillRule].maxDistance to 100,
// modify rules[distanceRuleExample].maxDistance to 15
// (2). Wait for 10s,if thereis no matchmaking result,then modify rules[skillRule].maxDistance to 200,
"expansions": [
{
// If no matches are found after 5 seconds, the maxDistance of `skillRule` is expaned to 100, and 10 seconds for 200.
"target": "rules[skillRule].maxDistance",
"steps": [
{
"waitTimeSeconds": 5,
"value": 100
},
{
"waitTimeSeconds": 10,
"value": 200
}
]
},
{
// If no matches are found after 5 seconds, the minimum team size is decreased to 2 players, and 10 seconds for just 1 player.
"target": "teams[*].minPlayers",
"steps": [
{
"waitTimeSeconds": 5,
"value": 2
},
{
"waitTimeSeconds": 10,
"value": 1
}
]
}
]

最后,完整的规则集如下:

{
"version": "v1.0",
"playerAttributes": [
{
"name": "skill",
"type": "number",
"default": 0
},
{
"name": "mode",
"type": "string",
"default": "solo"
}
],
"teams": [
{
"name": "red",
"maxPlayers": 8,
"minPlayers": 4
},
{
"name": "blue",
"maxPlayers": 8,
"minPlayers": 4
}
],
"rules": [
{
"name": "skillRule",
"type": "distanceRule",
"measurements": [
"flatten(teams[*].players.playerAttributes[skill])"
],
"referenceValue": "avg(flatten(teams[*].players.playerAttributes[skill]))",
"maxDistance": 50
},
{
"name": "modeRule",
"type": "comparisonRule",
"measurements": [
"flatten(teams[*].players.playerAttributes[mode])"
],
"operation": "="
},
{
"name": "countRule1",
"type": "comparisonRule",
"measurements": [
"count(teams[*].players)"
],
"operation": "="
},
{
"name": "countRule2",
"type": "comparisonRule",
"measurements": [
"count(teams[blue].players)"
],
"referenceValue": "count(teams[red].players)",
"operation": "="
}
],
"expansions": [
{
"target": "rules[skillRule].maxDistance",
"steps": [
{
"waitTimeSeconds": 5,
"value": 100
},
{
"waitTimeSeconds": 10,
"value": 200
}
]
},
{
"target": "teams[*].minPlayers",
"steps": [
{
"waitTimeSeconds": 5,
"value": 2
},
{
"waitTimeSeconds": 10,
"value": 1
}
]
}
]
}

3. 规则集架构

3.1 规则集概述

PGOS支持使用JSON脚本描述匹配规则集。 规则集脚本的结构

字段描述
version规则集脚本的版本,必须为"v1.0"
playerAttributes可用于规则中的玩家属性
teams可用于规则中的队伍定义
rules使用玩家属性和队伍数据的多重匹配约束条件
expansions使用玩家属性和队伍数据的多重匹配约束条件

e.g

{
"playerAttributes":[
...
],
"teams":[
...
],
"rules":[
...
],
"expansions":[
...
],
}

3.2 玩家属性

这包含了多组玩家的描述信息,使PGOS服务能够检索这些数据。

脚本结构

字段类型描述是否必须备注
namestring属性名字Yes长度为32的字符串。取值范围:a~z, A~Z, 0~9, _
typestring属性类型Yes"number”, “string”
defaultstring / number属性默认值No必须与属性类型相匹配
keystring在Player Data中s定义的keyNoPGOS 玩家数据中的 player-data 键值
bitmapbool是否把数字视为 bitmapNoBitmap 仅能用于数值类型的属性
partyAggregationstring一个匹配票票据中多个玩家属性值聚合策略No默认为"each"。可选值包括"each", "avg", "min", "max", "any", "and", "or"
提示
  • 如果 key 字段为空,则表示该属性取自匹配请求的 match_attributes 字段中同名的项。
  • 如果 key 字段不为空,则表示数据来自玩家数据中具有相同键的项。
  • 当规则集产生新的战斗会话时,规则集脚本中描述的所有玩家属性都将填充到 ServerPlayerDesc::match_attributes 中。请阅读此文档了解如何在您的游戏服务器上处理战斗会话 放置通知。
  • 如果以下规则中将使用数字属性进行位运算,请将bitmap设置为true。在任何其他场景中,请将其保留为false。
备注

partyAggregation 参数用于属性中合并多人游戏请求中的玩家属性值。例如,“partyAggregation”=“max”表示多人游戏匹配请求中所有成员的属性值均视为最高值。

  • each:单独对待每个玩家。
  • avg:组合玩家并选择他们属性的平均值。
  • min:组合玩家并选择他们属性的最小值。
  • max:组合玩家并选择他们属性的最大值。
  • any:组合玩家并随机选择其中一项属性。
  • and:对值执行按位与运算,仅适用于位图属性。
  • or:对值执行bitwise或运算,仅适用于bitmap属性。建议在玩家属性中定义“partyAggregation”。虽然为了向后兼容,也可以在规则中设置,但在属性中设置是更好的方法。这有助于 PGOS 根据属性对比赛票据进行排序。

e.g

    "playerAttributes": [
{
"name": "age", // Attribute from match_attributes which key is "age"
"type": "number",
"default": 10,
"partyAggregation": "avg"
},
{
"name": "skill", // Attribute from match_attributes which key is "skill"
"type": "number"
},
{
"name": "kda", // Attribute from Player properties which key is "kda"
"key":"kda",
"type": "number",
"default": 10
},
{
"name": "mode", // Attribute from match_attributes which key is "mode"
"type": "number",
"bitmap": true,
"partyAggregation": "and"
}
],

3.3 队伍

脚本结构

字段描述是否必需备注
name队伍名字Yes长度为32的字符串。取值范围 a~z,A~Z,0~9
minPlayers最小玩家数Yes1-40之间的整数
maxPlayers最大玩家数Yes一个介于1-40之间的整数;maxPlayers必须大于或等于minPlayers
minQuantity最小队伍数量No1-999之间的整数;默认值为1
maxQuantity最大队伍数量No1-999之间的整数;默认值为1;maxQuantity必须大于或等于minQuantity

匹配系统会尝试根据maxPlayers指定的数量来聚集玩家。如果匹配池中没有足够的玩家,系统会按照minPlayers的数量进行妥协。 可变队伍数量是一项高级功能。当匹配系统找到满足minQuantity的方案时,它会继续为该方案添加更多玩家并组建更多队伍。如果匹配池中有足够的玩家,匹配系统将返回一个达到maxQuantity要求的方案。 minPlayersmaxPlayers可以设置为相同的值,这样就会形成固定人数的队伍。minQuantitymaxQuantity也可以设置为相同的值,这样就会形成固定数量的队伍。

提示

maxQuantity设置为>1时,序号将会以下划线连接到队伍名称后,从"001"到"999"。 例如

"teams":[
{
"name":"squad",
"minPlayers":1,
"maxPlayers":1,
"minQuantity":4,
"maxQuantity":4
}
]

然后在匹配结果中,会有四支队伍:squad_001squad_002squad_003squad_004

e.g

// 5vs5 fair play
"teams":[
{
"name":"Darkness",
"minPlayers":5,
"maxPlayers":5
},
{
"name":"Light",
"minPlayers":5,
"maxPlayers":5
}
]

// 1vs1vs1vs1vs1 solo
"teams":[
{
"name":"soloTeam",
"minPlayers":1,
"maxPlayers":1
}
]

// 4v4v4v... battle royale
"teams":[
{
"name":"squad",
"minPlayers":4,
"maxPlayers":4,
"minQuantity":10,
"maxQuantity":25
}
]
提示当同时使用"可变玩家数"和"可变队伍数量"这两个功能时,匹配系统会尝试按照以下两个倾向来匹配玩家:
  • 尽可能匹配到 maxPlayers 所要求的玩家数量
  • 尽可能匹配到 maxQuantity 所要求的队伍数量 例如:
"teams":[
{
"name":"squad",
"minPlayers":1,
"maxPlayers":4,
"minQuantity":1,
"maxQuantity":4
}
]

在匹配池中有4名玩家时,1v1v1v12v24人组队都是符合上述要求的合法匹配结果。

目前的匹配系统倾向于优先满足minQuantitymaxPlayers参数。当创建了最少数量的队伍后,系统会尝试将队伍数量增加一个,同时仍然尝试满足该队伍的maxPlayers要求。匹配系统会持续循环这个过程,直到匹配池中没有足够的玩家组成最后一个新增的队伍,或者队伍总数达到maxQuantity限制。

因此默认情况下会得到4人组队的最终结果。如果想要得到1v1v1v1的结果,开发者可以使用下面的"规则扩展"功能,通过逐步放宽minQuantity值来处理1~4名玩家各自分配为一个队伍的情况,具体示例如下:

"teams":[
{
"name":"squad",
"minPlayers":1,
"maxPlayers":4,
"minQuantity":4,
"maxQuantity":4
}
],
"expansions": [
{
"target": "teams[*].minQuantity",
"steps": [
{
"waitTimeSeconds": 5,
"value": 3
}
]
},
{
"target": "teams[*].minQuantity",
"steps": [
{
"waitTimeSeconds": 10,
"value": 2
}
]
},
{
"target": "teams[*].minQuantity",
"steps": [
{
"waitTimeSeconds": 15,
"value": 1
}
]
}
]

3.4 规则

3.4.1 脚本结构

字段描述是否必需备注
name规则名字Yes长度为32的字符串。取值范围 a~z,A~Z,0~9,_
description规则描述No长度为128的字符串
type规则类型Yes有效值为"distanceRule"、"comparisonRule"和"latencyRule"
注意

规则集中的规则数量不应超过10条。

3.4.2 规则表达式

语法规范 以下语句说明如何识别队伍及其中的成员。

// Meaning:
// Darkness team
// Example of results:
// [[Darkness]]
teams[Darkness]

// Meaning:
// All teams
// Example of results:
// [[Darkness] [Light]]
teams[*]

// Meaning:
// Players in Darkness team
// Example of results:
// [[player-1 player-2]]
teams[Darkness].players

// Meaning:
// All players group by team
// Example of results:
// [[player-1 player-2] [player-3 player-4]]
teams[*].players

以下语句展示了如何获取玩家属性数据。

// Meaning:
// Playerid of players in Darkness Team
// Example of results:
// [[player-1 player-2]]
teams[Darkness].players[playerid]

// Meaning:
// List of attribute named skill in Darkness Team
// Example of results:
// ["solo" "solo" "solo"] or [1 1 1]
teams[Darkness].players.playerAttributes[skill]

// Meaning:
// Attribute named skill of all players(Group by team)
// Example of results:
// [["solo" "solo" "solo"] ["solo" "solo" "solo"]] or [[1 1 1] [1 1 1]]
teams[*].players.playerAttributes[skill]

3.4.3 表达式的功能

功能名字输入含义输出
flattenList将嵌套列表集合转换为包含所有元素的单个列表List
avgList获取列表中所有数字的平均值Number
minList获取列表中所有数字的最小值Number
maxList获取列表中所有数字的最大值Number
sumList获取列表中所有数字的总和Number
countList获取列表中所有元素的数量Number
andList对列表中的数字执行bitwise与运算。Number

请注意,当 avg 始终作用于一维列表时,当输入为嵌套列表时,它将进行递归。

提示

处理嵌套列表

// One dimensional list condition
ListA = [[1, 2, 3]]
avg(ListA) = [2]

// Nested list condition
ListB = [[1,2,3], [3,4,5]]
avg(ListB) = [2, 4]

如果您有像上述案例中的ListB这样的嵌套列表,并且想要计算所有元素的平均值,您应该先使用flatten将嵌套列表展开成一维列表。

// Symbolic explanation
ListA = [[1, 2, 3]]

ListB = [[3, 4, 5]]

ListC = [ListA, ListB]

flatten(ListC) = [[1, 2, 3, 3, 4, 5]]

// Meaning:
// List of attribute named kda of all players
// Type of results:
// List<number>

// If
team[A].players.playerAttributes[skill] = [[1, 2, 3]]
team[B].players.playerAttributes[skill] = [[3, 4, 5]]

// Then
teams[*].players.playerAttributes[skill] = [[1,2,3], [3,4,5]]
flatten(teams[*].players.playerAttributes[skill]) = [[1, 2, 3, 3, 4, 5]]

// When combined with "avg", the difference of using "flatten" is:
avg(teams[*].players.playerAttributes[skill]) = [[2, 4]]
avg(flatten(teams[*].players.playerAttributes[skill])) = avg([1, 2, 3, 3, 4, 5]) = [3]

3.4.4 规则类型

类型 1. 距离规则

属性名字描述是否必需值的限制
name规则名字Yes长度为32的字符串。取值范围为a~z、A~Z、0~9、_。在同一规则集中唯一
type规则类型YesdistanceRule
description规则描述No长度为 256的字符串
measurements测量值,用于与参考值比较距离Yes计算结果以 List\<number> 或 List\<List\<number>> 形式表示,支持多个数值表达式,精确到小数点后2位
referenceValueComparison valueYes数字或计算结果为数字的表达式,精确到小数点后两位;可用作扩展目标
minDistance最小距离差至少填写 minDistance 或 maxDistance 中的一个measurements中计算的每个数字与referenceValue进行比较的最小差值。取值范围为0-99999之间的数字,精确到小数点后两位。可作为扩展目标使用
maxDistance最大距离差至少填写 minDistance 或 maxDistance 中的一个measurements中计算的每个数字与referenceValue进行比较的最大差值。取值范围为0-99999之间的数字,精确到小数点后两位。可用作扩展目标
partyAggregation如何聚合多玩家请求No有效选项包括每个(each)、最小值(min)、最大值(max)、平均值(avg)或任意一个(any)作为请求的玩家参数。默认值为每个(each)
// Meaning:
// The distance between average value of the "skill" of each team player and the average value of the "skill" of all players is not less than 5, not more than 10
"rules": [
{
"name": "distanceRuleExample",
"type": "distanceRule",
"measurements": [ "avg(teams[*].players.skill)" ],
"referenceValue": "avg(flatten(teams[*].players.playerAttributes[skill]))",
"minDistance":5,
"maxDistance":10
}]

类型 2. 比较规则

属性名字描述是否必需值的限制
name规则名字Yes长度为32的字符串。取值范围为a~z、A~Z、0~9、_,在同一规则集中必须唯一
description规则描述No长度为32的字符串。取值范围为a~z、A~Z、0~9、_,在同一规则集中必须唯一
type规则类型YescomparisonRule
measurements规则表达式Yes计算结果为 List<?> 类型的表达式,可以是 List\<number> 或 List\<string>。目前仅支持1个表达式。
如果定义了 referenceValue,则将 List\<?> 中的每个元素与 referenceValue 进行比较;
如果未定义referenceValue,则比较List\<?>中的每个元素。在这种情况下,操作符只能取值"="或"!="
referenceValue与规则表达式进行比较的值No计算结果与测量元素类型(如数字或字符串)相同的表达式。可用作扩展目标
operation比较符号Yes有效值:"="、"!="、"<"、"<="、">"、">=" (这些符号可用于比较数字或字符串)。可作为扩展目标
// Meaning:
// Players must all choose "solo" mode
"rules": [ {
"name": "modeRule",
"type": "comparisonRule",
"measurements": [
"flatten(teams[*].players.playerAttributes[mode])"
],
"referenceValue": "solo",
"operation": "="
}]

// Meaning:
// Players of team red must all be "attacker" side
"rules": [ {
"name": "side_binding_red",
"type": "comparisonRule",
"measurements": [
"flatten(teams[red].players.playerAttributes[side])"
],
"referenceValue": "attacker",
"operation": "="
}]

// Meaning:
// Players of each team must pick the same side
"rules": [ {
"name": "side_binding",
"type": "comparisonRule",
"measurements": [
"teams[*].players.playerAttributes[side]"
],
"operation": "="
} ]

类型 3. 延迟规则

属性名字描述是否必需值的限制
name规则名字Yes长度为32的字符串。取值范围为a~z、A~Z、0~9、_,在同一规则集中必须唯一
description规则描述No长度为256的字符串
type规则类型YeslatencyRule
maxLatency最大延迟Yes单位为毫秒;
取值范围为0~999999;
可用作扩展目标
partyAggregation多人请求处理方式No有效选项包括每个(each)、最小值(min)、最大值(max)、平均值(avg)或任意一个(any)作为请求的玩家参数。默认值为每个
// Meaning:
// The maximum delay from the player to the region does not exceed 150ms
"rules": [{
"name": "laytency_rule_example",
"type": "latencyRule",
"maxLatency": 150
}]

3.5 扩展规则

匹配规则支持对某些字段的约束条件进行扩展,以实现"时间衰减"匹配。

3.5.1 扩展规则的结构

属性名字描述是否必需值的限制
target要放宽的目标属性Yes可以是以下形式:

teams[red].minPlayers
teams[*].maxPlayers
rules[mySkillRule].maxDistance
rules[myLatencyRule].maxLatency
steps所有步骤的跳过时间Yes步骤数量不应超过10
steps/waitTimeSeconds自玩家开始匹配以来所经过的绝对时间Yes最大等待时间(waitTimeSeconds)不应超过对局配置中定义的超时限制
steps/value目标值Yes一个队伍的最小玩家数不能少于一人。
距离规则中的最大距离不能小于最小距离。

e.g

// Meaning:
// After waiting 5s for no result, modify the value of minDistance to 4
// Continue to wait for 5 seconds without results, modify the value of maxDistance to 15
// Continue to wait for 10 seconds without results, modify the value of maxDistance to 20
"rules": [
{
"name": "distanceRuleExample",
"type": "distanceRule",
"measurements": [
"avg(teams[*].players.playerAttributes[skill])"
],
"referenceValue": "avg(flatten(teams[*].players.playerAttributes[skill]))",
"minDistance":5,
"maxDistance":10,
}
]
"expansions": [
{
"target": "rules[distanceRuleExample].minDistance",
"steps": [{
"waitTimeSeconds": 5,
"value": 4
}]
},
{
"target": "rules[distanceRuleExample].maxDistance",
"steps": [{
"waitTimeSeconds": 5,
"value": 15
},{
"waitTimeSeconds": 10,
"value": 20
}
]