Discord 机器人
AssettoServer Hub 内置了一个 Discord 机器人,具有以下功能:
- 将 Steam 账户关联到 Discord 账户
- 将 Discord 身份组映射为 AssettoServer 用户组(示例用例:基于 Discord 身份组的白名单)
- 将 AssettoServer 用户组映射为 Discord 身份组(示例用例:根据计时排行榜分配身份组)
- 在 Discord 中发布服务器状态
设置
- 访问 Discord Developer Portal 并创建一个新应用程序。你输入的名称将成为机器人的初始用户名。
- 在左侧点击
Bot。 - 点击
Add Bot并确认。 - 取消勾选
Public Bot。 - 确保勾选了
Server Members Intent。
机器人页面应如下所示:

- 在左侧点击
OAuth2并选择URL Generator。 - 在
Scopes下,确保勾选了bot。 - 在
Bot Permissions下,确保勾选了Send Messages和Manage Roles。
页面应如下所示:

- 复制页面底部生成的 URL,并将其粘贴到浏览器中。
- 为你的 Discord 服务器授权该机器人。
- 返回 Developer Portal 的
Bot页面。 - 复制你的机器人令牌并粘贴到
configuration.yml中,如下所示:DiscordBotToken: "your token here"
**搞定!**下次启动 AssettoServer Hub 时,它将会连接到 Discord。
关联 Steam 账户
建议为关联 Steam 账户创建一个新的只读频道。
在该频道中使用 /steam-link post 命令。机器人将创建一个用于关联/解除关联 Steam 账户的帖子:

点击按钮后,用户可以输入自己的 Steam 个人资料 URL:


输入 Steam 个人资料 URL 后:

管理已关联的账户
管理员可以使用以下命令管理已关联的 Steam 账户:
/steam-link find-discord- 根据 SteamID 查找对应的 Discord 用户/steam-link find-steam- 根据 Discord 用户查找对应的 SteamID/steam-link unlink- 解除 SteamID 与 Discord 用户的关联
审计日志
AssettoServer Hub 可以将一些事件(关联 Steam 账户、创建/删除用户组等)发布到指定频道。使用 /audit-log set 命令可启用此功能。
Discord 用户组
Discord 身份组可以关联到 AssettoServer 用户组。可用于白名单、预留槽位等。
添加用户组
使用 /user-group add 命令创建用户组:
下一步,为该用户组选择 Discord 身份组:

之后,用户组将被创建:

现在,你可以在服务器配置中使用该组了。
有关用户组的更多一般信息,请参见此页面。
移除用户组
要移除某个组,只需使用 /user-group remove 命令。
用户组映射
现有的 AssettoServer 用户组可以映射到 Discord 身份组。例如,可以配合 PatreonTimingPlugin,根据计时排行榜分配身份组。
根据计时排行榜分配身份组
首先,在 configuration.yml 中添加一个新的计时用户组:
TimingUserGroups:
- Name: timing_top3
PostFilter: CarRank <= 3
这将创建一个名为 timing_top3 的用户组,其中包含任意车辆排行榜时间排名前 3 的所有玩家。
接下来,使用 /user-group map 命令将该用户组映射到 Discord 身份组。例如 /user-group map timing_top3 <your role>:

现在,所有已关联 Steam 账户且拥有前 3 排行榜成绩的用户都将获得该身份组。
自定义计时筛选器(高级)
创建计时身份组的条件可通过 SQL WHERE 子句完全自定义。以下查询用于确定计时用户组:
WITH ranks AS (SELECT tle.player_id,
c.model AS CarModel,
tle.created_at AS CreatedAt,
t.name AS Track,
ts.name AS Stage,
MIN(tle.lap_time) AS LapTime,
RANK() OVER (
PARTITION BY t.track_id, ts.timing_stage_id, tle.car_id
ORDER BY tle.lap_time
) AS CarRank,
RANK() OVER (
PARTITION BY t.track_id, ts.timing_stage_id
ORDER BY tle.lap_time
) AS Rank
FROM timing_leaderboard_entries tle
JOIN cars c on c.car_id = tle.car_id
JOIN timing_leaderboards tl on tl.timing_leaderboard_id = tle.timing_leaderboard_id
JOIN timing_stages ts on ts.timing_stage_id = tle.timing_stage_id
JOIN tracks t on ts.track_id = t.track_id
WHERE tle.valid = true
--#preFilter
GROUP BY t.name, ts.name, tle.car_id, tle.player_id
ORDER BY t.name, ts.name, MIN(tle.lap_time))
SELECT DISTINCT r.player_id
FROM ranks r
--#postFilter
使用的数据库是 SQLite。
PreFilter 和 PostFilter 可用于自定义生成的用户组。例如,以下配置只会为当月设置的圈速创建用户组:
TimingUserGroups:
- Name: timing_top5_month
PreFilter: tle.created_at > date('now', 'start of month')
PostFilter: CarRank <= 5
根据计时积分排行榜分配身份组
首先,在 configuration.yml 中添加一个新的计时积分用户组:
TimingPointsUserGroups:
- Name: timing_points_top10
PostFilter: Rank <= 10
- Name: timing_points_traffic_1000
PreFilter: Leaderboard = 'Traffic'
PostFilter: Points >= 1000
这将创建两个用户组:
timing_points_top10包含所有排行榜中排名前 10 的玩家。timing_points_traffic_1000包含Traffic排行榜上积分超过 1000 的所有玩家。
根据竞速挑战排行榜分配身份组
首先,在 configuration.yml 中添加一个新的竞速挑战用户组:
RaceChallengeUserGroups:
- Name: race_top5
Leaderboard: Default
Filter: Rank <= 5
- Name: race_1200_rating
Leaderboard: Traffic
Filter: Rating > 1200
这将创建两个用户组:
race_top5包含Default排行榜上排名前 5 的玩家。race_1200_rating包含Traffic排行榜上评分高于 1200 的所有玩家。
根据超车排行榜分配身份组
你也可以根据超车排行榜分配用户组。两个示例:
OvertakeUserGroups:
- Name: overtake_top100
PostFilter: Rank <= 100
- Name: overtake_500k
PostFilter: Score >= 500000
这将创建两个用户组:
overtake_top100包含排名前 100 的玩家overtake_500k包含至少 500,000 分的所有玩家
接下来,使用 /user-group map 命令将该用户组映射到 Discord 身份组。例如 /user-group map overtake_top100 <your role>。
现在,所有已关联 Steam 账户且拥有前 100 排行榜成绩的用户都将获得该身份组。
自定义超车筛选器(高级)
筛选方式与上面的计时排行榜筛选类似。你可以使用 PreFilter 在生成排名之前筛选成绩,例如只统计当月的成绩。
然后可以使用 PostFilter 按分数、排名等进行筛选。
可用作筛选条件的所有列名:Name、Leaderboard、PlayerId、CarModel、Score、Duration、CreatedAt、DiscordId、Rank
根据安全评分分配身份组
PatreonSafetyRatingPlugin 可以为每个等级创建一个用户组,例如:
SafetyRatingRanks:
- Color: '#00FF00'
MinimumRating: 4
Name: A
UserGroupName: safety_a
- Color: null
MinimumRating: 1
Name: B
- Color: '#FF0000'
MinimumRating: 0
Name: C
这将为每个拥有 A 评级的驾驶员创建一个名为 safety_a 的用户组。你现在可以使用 /user-group map safety_a <your role> 为所 有 A 评级驾驶员分配身份组。
移除映射
可以使用 /user-group unmap 命令移除映射。
服务器状态
AssettoServer Hub 可以为你的游戏服务器创建如下所示的服务器状态消息:

为此,请在 configuration.yml 中添加一个新的部分,例如:
DiscordServerStatus:
# Name that will be used for creating the embed
srp-eu:
# Embed title
Title: Europe - Germany
# Embed thumbnail
ThumbnailUrl: https://flagcdn.com/w160/eu.png
# Embed template - read below for more info
Template: default
# Embed color
Color: "#003399"
# List of game servers to query
Servers:
# Server name
- Name: EU 1 - No Traffic
# Server address in format ip:httpPort
Address: 65.108.176.35:8081
- Name: EU 2 - Traffic
Address: 65.108.176.35:8082
- Name: EU 3 - Traffic - Slow Cars
Address: 65.108.176.35:8083
- Name: EU 4 - Traffic
Address: 65.108.176.35:8085
- Name: EU PTB - Traffic
Address: 65.108.176.35:8084
可以在频道中使用 /server-status <name> 命令发布服务器状态消息,例如 /server-status srp-eu。
自定义模板(高级)
嵌入消息可以使用 Scriban 模板进行 自定义。
AssettoServer Hub 内置了以下默认模板:
{{ for server in servers }}
**{{ server.alias }}**
{{ if server.online -}}
:green_circle: Online · Players: `{{ server.clients | string.pad_left 2 }}/{{ server.max_clients | string.pad_left 2 }}` · Time: `{{ server.time }}` · **[Join]({{ server.invite }})**
{{- else -}}
:red_circle: Offline
{{- end }}
{{ end }}
你可以通过在 configuration.yml 中添加 DiscordServerStatusTemplates 部分来添加自定义模板。示例:
DiscordServerStatusTemplates:
emoji: |
{{ for server in servers }}
**{{ server.alias }}**
{{
if server.online
fill = server.clients / server.max_clients
if fill < 0.5
":green_circle:"
else if fill < 0.75
":yellow_circle:"
else
":orange_circle:"
end
" Online"
else
":red_circle: Offline"
end
timeSplit = server.time | string.split ":"
hours = timeSplit[0] | string.to_int
minutes = timeSplit[1] | string.to_int
if minutes >= 45
hours += 1
end
hours = hours % 12
if hours == 0
hours = 12
end
if minutes > 15 && minutes < 45
minutes = 30
else
minutes = ""
end
clockEmoji = ":clock" + hours + minutes + ":"
}} · :busts_in_silhouette: `{{ server.clients | string.pad_left 2 }}/{{ server.max_clients | string.pad_left 2 }}` · {{ clockEmoji }} `{{ server.time }}` · **[Join]({{ server.invite }})**
{{ end }}
此模板会根据服务器上的玩家数量改变绿点的颜色,并用时钟表情符号显示正确的时间。
然后,你可以在 DiscordServerStatus 配置中设置 Template: emoji 来使用此模板。
模板的输出效果:

排行榜
计时积分排行榜
使用 /timing-points-leaderboard 命令在当前频道创建排行榜。

自定义模板(高级)
嵌入消息可以使用 Scriban 模板进行自定义。
AssettoServer Hub 内置了以下默认模板:
{{
func to_emoji(rank)
case rank
when 1
" :first_place:"
when 2
" :second_place:"
when 3
" :third_place:"
end
end
func get_mention(entry)
if entry.discord_id > 0
" — <@"
entry.discord_id
">"
end
end
for entry in entries -}}
**{{ for.index + 1 }}\. {{ entry.name }}{{ get_mention entry }}{{ to_emoji for.index + 1 }}**
> {{ entry.points | math.format "#,#" }} points
{{ end }}
你可以通过在 configuration.yml 中添加以下内容来添加自定义模板:
DiscordTimingPointsLeaderboardTemplates:
TestTemplate: |
text of your template
can be multiple lines
/timing-points-leaderboard 命令包含一个名为 template 的可选参数。你可以用它来指定自己的自定义模板(上例中的 TestTemplate)。
计时路段排行榜
使用 /timing-stage-leaderboard 命令在当前频道创建排行榜。

自定义模板(高级)
嵌入消息可以使用 Scriban 模板进行自定义。
AssettoServer Hub 内置了以下默认模板:
{{
func to_emoji(rank)
case rank
when 1
" :first_place:"
when 2
" :second_place:"
when 3
" :third_place:"
end
end
func get_mention(entry)
if entry.discord_id > 0
" — <@"
entry.discord_id
">"
end
end
func format_duration(duration)
d = timespan.from_milliseconds duration
d.minutes | math.format '0'
":"
d.seconds | math.format '00'
"."
d.milliseconds | math.format '000'
end
for entry in entries -}}
**{{ for.index + 1 }}\. {{ format_duration entry.lap_time }} — {{ entry.name }}{{ get_mention entry }} {{ to_emoji for.index + 1 }}**
> <t:{{ entry.created_at | date.to_string '%s' }}> — {{ entry.car_display_name }}
{{ end }}
你可以通过在 configuration.yml 中添加以下内 容来添加自定义模板:
DiscordTimingStageLeaderboardTemplates:
TestTemplate: |
text of your template
can be multiple lines
/timing-stage-leaderboard 命令包含一个名为 template 的可选参数。你可以用它来指定自己的自定义模板(上例中的 TestTemplate)。
竞速挑战排行榜
使用 /race-challenge-leaderboard 命令在当前频道创建排行榜。

自定义模板(高级)
嵌入消息可以使用 Scriban 模板进行自定义。
AssettoServer Hub 内置了以下默认模板:
{{
func to_emoji(rank)
case rank
when 1
" :first_place:"
when 2
" :second_place:"
when 3
" :third_place:"
end
end
func get_mention(entry)
if entry.discord_id > 0
" — <@"
entry.discord_id
">"
end
end
for entry in entries -}}
**{{ for.index + 1 }}\. {{ entry.name }}{{ get_mention entry }}{{ to_emoji for.index + 1 }}**
> {{ entry.rating | math.format "#,#" }} points
{{ end }}
你可以通过在 configuration.yml 中添加以下内容来添加自定义模板:
DiscordRaceChallengeLeaderboardTemplates:
TestTemplate: |
text of your template
can be multiple lines
/race-challenge-leaderboard 命令包含一个名为 template 的可选参数。你可以用它来指定自己的自定义模板(上例中的 TestTemplate)。
超车排行榜
使用 /overtake-leaderboard 命令在当前频道创建排行榜。

自定义模板(高级)
嵌入消息可以使用 Scriban 模板进行自定义。
AssettoServer Hub 内置了以下默认模板:
{{
func to_emoji(rank)
case rank
when 1
" :first_place:"
when 2
" :second_place:"
when 3
" :third_place:"
end
end
func get_mention(entry)
if entry.discord_id > 0
" — <@"
entry.discord_id
">"
end
end
func format_duration(duration)
d = timespan.from_milliseconds duration
d.hours | math.format '0'
":"
d.minutes | math.format '00'
":"
d.seconds | math.format '00'
"."
d.milliseconds / 100 | math.round
end
for entry in entries -}}
**{{ for.index + 1 }}\. {{ entry.name }}{{ get_mention entry }}{{ to_emoji for.index + 1 }}**
> {{ entry.score | math.format "#,#" }} points — {{ format_duration entry.duration }}
> <t:{{ entry.created_at | date.to_string '%s' }}> — {{ entry.car_display_name }}
{{ end }}
你可以通过在 configuration.yml 中添加以下内容来添加自定义模板:
DiscordOvertakeLeaderboardTemplates:
TestTemplate: |
text of your template
can be multiple lines
/overtake-leaderboard 命令包含一个名为 template 的可选参数。你可以用它来指定自己的自定义模板(上例中的 TestTemplate)。
RCON(远程控制台)
你可以使用 /rcon 命令在已连接的服务器上执行命令。

