You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为discord.py机器人的经验升级系统添加排名功能并排查代码问题

现有代码可优化点
  • 重复IO操作:level_up函数已经接收了已经读取的users参数,无需再次读取users.json文件,额外增加磁盘IO开销
  • 无经验获取冷却:用户短时间内连续发送消息可以重复刷取经验,建议添加最短间隔限制,比如60秒内最多获取一次经验
  • 数据结构未按服务器隔离:如果你的机器人服务多个服务器,当前存储逻辑会把所有服务器用户的经验混存,排名也会跨服务器,不符合单服务器排名的需求
  • 命名不规范:level命令的Embed标题错误写为balance,变量名bank_amt和实际存储的等级值完全无关,易维护性差
  • 未过滤非当前服务器用户:查询排名时会统计所有在JSON中有记录的用户,包括已经退服的用户和其他服务器的用户
排名功能实现方案

我们新增两个命令:

  1. !lb/!排行榜:展示当前服务器经验等级前10的用户
  2. !rank/!排名:查询自己或者@指定用户的当前服务器排名

第一步:添加冷却变量和优化原有逻辑

在client = commands.Bot(command_prefix="!")下方新增冷却存储字典:

# 存储用户上次获得经验的时间,单位秒
cd_time = {}
# 经验获取冷却秒数
EXP_CD = 60

修改on_message事件,添加冷却判断,同时删掉level_up里多余的读文件操作:

@client.event
async def on_message(message):
    if not message.author.bot:
        await open_account_level(message.author)
        users = await get_level_data()
        # 冷却判断
        now = message.created_at.timestamp()
        last_get = cd_time.get(message.author.id, 0)
        if now - last_get >= EXP_CD:
            await add_experience(users, message.author, 5)
            await level_up(users, message.author, message)
            cd_time[message.author.id] = now
            with open('users.json', 'w') as f:
                json.dump(users, f)
    await client.process_commands(message)

# 优化后的level_up函数,删掉多余读文件逻辑
async def level_up(users, user, message):
    experience = users[f'{user.id}']['Exp']
    lvl_start = users[f'{user.id}']['Exp Level']
    lvl_end = int(experience ** (1 / 4))
    if lvl_start < lvl_end:
        await message.channel.send(f'{user.mention} has leveled up to level {lvl_end}')
        users[f'{user.id}']['Exp Level'] = lvl_end

第二步:新增排名相关命令

直接在代码末尾(TOKEN定义前)添加以下代码即可:

@client.command(aliases=["排行榜"])
async def lb(ctx, show_num: int = 10):
    # 最多只展示前20名,避免消息太长
    show_num = min(show_num, 20)
    users = await get_level_data()
    # 筛选当前服务器的有效用户数据
    guild_user_data = []
    for user_id, data in users.items():
        member = ctx.guild.get_member(int(user_id))
        if member:
            guild_user_data.append((-data["Exp Level"], -data["Exp"], member.name, data["Exp Level"], data["Exp"]))
    # 按等级降序、同等级经验降序排序
    guild_user_data.sort()
    # 生成展示Embed
    em = discord.Embed(title=f"{ctx.guild.name} 等级排行榜", color=discord.Color.green())
    desc = ""
    for idx, item in enumerate(guild_user_data[:show_num]):
        desc += f"{idx+1}. {item[2]} | 等级:{item[3]} | 经验:{item[4]}\n"
    em.description = desc
    await ctx.send(embed=em)

@client.command(aliases=["排名"])
async def rank(ctx, member: discord.Member = None):
    # 不指定用户时默认查询自己的排名
    if not member:
        member = ctx.author
    await open_account_level(member)
    users = await get_level_data()
    # 筛选当前服务器的有效用户数据
    guild_user_data = []
    for user_id, data in users.items():
        g_member = ctx.guild.get_member(int(user_id))
        if g_member:
            guild_user_data.append((-data["Exp Level"], -data["Exp"], int(user_id)))
    # 排序
    guild_user_data.sort()
    # 查找目标用户的排名
    rank_idx = None
    for idx, item in enumerate(guild_user_data):
        if item[2] == member.id:
            rank_idx = idx + 1
            break
    # 生成展示Embed
    user_data = users[str(member.id)]
    em = discord.Embed(title=f"{member.name} 的排名信息", color=discord.Color.blue())
    em.add_field(name="当前排名", value=f"{rank_idx}/{len(guild_user_data)}", inline=False)
    em.add_field(name="当前等级", value=user_data["Exp Level"], inline=True)
    em.add_field(name="当前经验", value=user_data["Exp"], inline=True)
    await ctx.send(embed=em)

如果你需要适配多服务器数据隔离,可以把JSON的存储结构调整为按服务器ID分组,对应修改读写逻辑即可实现多服务器数据互不干扰。

内容的提问来源于stack exchange,提问作者Teutonicknight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 08:54:00