如何实现Discord机器人多服务器游戏状态独立运行
故障原因
你的代码存在5个核心问题,导致多服务器状态隔离完全失效:
- 没有删除全局
ingame标记,这个标记是所有服务器共享的,只要任意一个服务器开启游戏修改了这个值,其余服务器的启动请求都会被拦截,你写的服务器状态字典完全没有参与核心逻辑判断。 on_guild_join事件函数没有定义guild入参,机器人加入新服务器时根本拿不到对应的服务器实例,初始化状态字典的逻辑根本不会正常执行。- 字典键类型不统一:初始化的时候用
guild.name(字符串类型的服务器名)当键,命令判断的时候又用ctx.guild(Discord的Guild实例对象)当键,两种类型永远无法匹配,键存在性判断完全失效。 - 状态值逻辑写反:给不存在的服务器初始化状态时直接设为
True,和“游戏中”的状态值重合,初始无游戏的状态应该为False。 - 提示语的字符串占位符没有传入对应参数,发送消息时会直接报格式化错误。
修复方案
不要用全局变量存游戏状态,统一用服务器唯一ID作为字典键做状态隔离,参考实现如下:
import discord import random from discord.ext import commands client = commands.Bot(command_prefix="!") # 替换成你自己的命令前缀 # 用服务器ID作为键存储游戏状态,值为True代表对应服务器有正在进行的游戏,False代表无游戏 games_in_progress = {} # 存储游戏对应答案、所在频道,方便逻辑判断和提示引用 game_data = {} @client.event async def on_ready(): # 机器人启动时初始化所有已加入服务器的状态,避免重启后状态丢失 for guild in client.guilds: games_in_progress[guild.id] = False print(f"已登录为{client.user},共加载{len(client.guilds)}个服务器的状态") @client.event async def on_guild_join(guild): # 新加入服务器时初始化状态 games_in_progress[guild.id] = False print(f"已加入服务器{guild.name},已初始化游戏状态") @client.command() async def startgame(ctx, min_num:int=1, max_num:int=100): guild_id = ctx.guild.id # 先判断当前服务器有没有正在进行的游戏 if games_in_progress.get(guild_id, False): await ctx.send(f"当前服务器已有正在进行的游戏,请先结束{game_data[guild_id]['channel'].mention}的游戏再开启新局") return # 校验数字区间合法性 if min_num >= max_num: await ctx.send("数字区间不合法,最小值必须小于最大值") return # 生成随机答案,标记当前服务器进入游戏中状态 answer = random.randint(min_num, max_num) games_in_progress[guild_id] = True game_data[guild_id] = { "answer": answer, "min": min_num, "max": max_num, "channel": ctx.channel } await ctx.send(f"猜数字游戏已启动!请猜{min_num}到{max_num}之间的整数") @client.command() async def guess(ctx, num:int): guild_id = ctx.guild.id if not games_in_progress.get(guild_id, False): await ctx.send("当前服务器没有正在进行的猜数字游戏,请先使用startgame命令开局") return target = game_data[guild_id]["answer"] if num == target: await ctx.send(f"恭喜你猜对了!答案就是{target},本局游戏结束") # 猜对后重置状态 games_in_progress[guild_id] = False del game_data[guild_id] elif num < target: await ctx.send("猜小了,再试试更大的数字") else: await ctx.send("猜大了,再试试更小的数字")
注意事项
- 不要用服务器名作为状态键,服务器名称可以被管理员随意修改,会导致状态匹配失效,Discord提供的
guild.id是全局唯一且永久不变的,最适合做状态键。 - 所有游戏结束的分支(玩家猜对答案、超时自动结束、管理员手动终止)都必须重置对应服务器的
games_in_progress状态,否则服务器会一直被判定为有游戏在进行。
内容的提问来源于stack exchange,提问作者Moby772
相关产品推荐
相关产品推荐

