
本文讲解如何在 Discord.py 机器人中正确识别用户“正在玩的游戏”(ActivityType.playing),避免被自定义状态(Custom Status)干扰,通过遍历 activities 列表并精准匹配活动类型实现可靠监听。
本文讲解如何在 discord.py 机器人中正确识别用户“正在玩的游戏”(activitytype.playing),避免被自定义状态(custom status)干扰,通过遍历 `activities` 列表并精准匹配活动类型实现可靠监听。
Discord 用户可同时拥有多种活动(如游戏、自定义状态、听 Spotify 等),这些活动统一存储在 member.activities(一个元组)中,而非仅由 member.activity 单一属性表示。原始代码中直接访问 after.activity 实际只取第一个活动(通常是自定义状态或最近设置的活动),导致误判——即使用户已启动 Minecraft,若其设置了“☕ Coding & chilling”自定义状态,after.activity 很可能返回该自定义状态而非游戏。
✅ 正确做法是:遍历 after.activities,逐个检查 activity.type,仅当类型为 discord.ActivityType.playing 时提取游戏名。这样可跳过自定义状态(ActivityType.custom)、流媒体(ActivityType.streaming)等干扰项,确保捕获真实的游戏行为。
以下是优化后的核心事件处理逻辑:
@client.event
async def on_presence_update(before, after):
# 遍历所有当前活动,寻找「正在玩」类型
for activity in after.activities:
if activity.type == discord.ActivityType.playing:
game_name = activity.name or "Unknown Game"
print(f"{before.name} is now playing {game_name}")
# 发送通知到系统频道(建议替换为指定频道ID以提升健壮性)
system_channel = client.guilds[0].system_channel
if system_channel is not None:
await system_channel.send(f"? {before.name} is now playing **{game_name}**")
break # 找到首个游戏即退出,避免重复触发⚠️ 注意事项:
- 必须启用 intents.presences = True(你已正确配置),否则 activities 始终为空;
- before.name 在跨服务器场景下不安全(应使用 before.display_name 或结合 guild.get_member() 获取准确昵称);
- client.guilds[0].system_channel 是硬编码,生产环境建议通过 guild.get_channel(CHANNEL_ID) 指定通知频道;
- 若需区分“首次启动游戏”(如仅在用户此前无任何 playing 活动时触发),可对比 before.activities 中是否已存在 playing 类型活动;
- 自定义状态(ActivityType.custom)的 activity.name 通常为 None 或空字符串,但其 activity.state 可能含文本——这正是它干扰 activity.name 的原因,而 playing 类型始终保证 name 有效。
总结:Discord 的活动模型是多态的,activity 属性仅为兼容旧版的快捷入口;现代开发务必使用 activities 迭代+类型判断范式。这一模式同样适用于监听听歌(ActivityType.listening)、直播(ActivityType.streaming)等场景,是构建专业级状态感知机器人的基础实践。


















