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

discord.py:如何通过命令让服务器所有者自定义单服XP获取量?

实现服务器自定义单条消息XP获取量

1. 调整JSON数据结构

在原有服务器用户数据的基础上,新增message_xp字段存储当前服务器的单条消息XP值(默认4),更新后的JSON示例:

{
  "757383943116030074": {
    "message_xp": 4,
    "123456789012345678": {
      "experience": 0,
      "level": 1
    }
  }
}

2. 更新update_data函数

确保新服务器初始化时自动添加默认XP值,同时兼容已有服务器的旧数据:

async def update_data(users, user, server):
    server_id = str(server.id)
    if server_id not in users:
        users[server_id] = {
            "message_xp": 4,  # 默认单条消息XP
            str(user.id): {
                "experience": 0,
                "level": 1
            }
        }
    else:
        # 给已有服务器补加message_xp字段(兼容旧数据)
        if "message_xp" not in users[server_id]:
            users[server_id]["message_xp"] = 4
        # 初始化用户数据
        if str(user.id) not in users[server_id]:
            users[server_id][str(user.id)] = {
                "experience": 0,
                "level": 1
            }

3. 添加修改XP的专属命令

创建仅服务器管理员/所有者可使用的命令,用来修改当前服务器的单条消息XP值:

@bot.command(aliases=['setxp', 'setmessagexp'])
@commands.has_permissions(administrator=True)  # 限制仅管理员可用
async def set_message_xp(ctx, xp_amount: int):
    if xp_amount < 1:
        await ctx.send("XP值不能小于1!")
        return
    
    with open('level.json', 'r', encoding='utf-8') as f:
        users = json.load(f)
    
    server_id = str(ctx.guild.id)
    # 确保服务器数据存在
    if server_id not in users:
        users[server_id] = {"message_xp": 4}
    
    users[server_id]["message_xp"] = xp_amount
    
    with open('level.json', 'w', encoding='utf-8') as f:
        json.dump(users, f, indent=2)
    
    await ctx.send(f"已设置当前服务器单条消息获取XP为 **{xp_amount}**!")

4. 修改on_message事件的XP获取逻辑

把原来固定的4改成读取当前服务器的自定义XP值:

@bot.event
async def on_message(message):
    if not message.author.bot:
        # 冷却逻辑保持不变
        if message.author.id in message_cooldown:
            current_time = time.time()
            last_message_time = message_cooldown[message.author.id]
            if current_time - last_message_time < 1:
                return

        with open('level.json', 'r', encoding='utf-8') as f:
            users = json.load(f)
        await update_data(users, message.author, message.guild)
        
        # 读取当前服务器的自定义XP值
        server_xp = users[str(message.guild.id)]["message_xp"]
        await add_experience(users, message.author, server_xp, message.guild)
        
        await level_up(users, message.author, message.channel, message.guild)

        message_cooldown[message.author.id] = time.time()

        with open('level.json', 'w', encoding='utf-8') as f:
            json.dump(users, f, indent=2)
    await bot.process_commands(message)

5. 修复排行榜命令的过滤逻辑

在排行榜中过滤掉message_xp配置项,避免被当成用户数据处理:

@bot.tree.command(name="leaderboard", description="查看服务器等级排行榜前10名")
async def hello(ctx: discord.Interaction):
    embed = discord.Embed(title=f"{ctx.guild.name} 等级排行榜", color=discord.Colour.blurple())
    with open('level.json', 'r', encoding='utf-8') as file:
        data = json.load(file)
    # 过滤掉message_xp字段,只保留用户数据
    user_data = {k:v for k,v in data[str(ctx.guild.id)].items() if k != "message_xp"}
    sorted_data = sorted(user_data.items(), key = lambda item:item[1]['experience'], reverse=True)
    for pos, (id, bal) in enumerate(sorted_data):
        member = ctx.guild.get_member(int(id))
        embed.add_field(name=f"{pos+1} - {member.display_name} (@{member.name})", value=f"**Level {bal['level']}**\n{bal['experience']} XP", inline=False)
        embed.set_author(name=f"{ctx.user.name}", icon_url = ctx.user.avatar.url)
        if pos+1 > 9:
            break 
    await ctx.response.send_message(embed=embed)

完整修改后的代码

import json
import time
import discord
from discord.ext import commands

message_cooldown = {}
bot = commands.Bot(command_prefix="你的前缀", intents=discord.Intents.all())  # 替换为你的命令前缀

@bot.event
async def on_message(message):
    if not message.author.bot:
        if message.author.id in message_cooldown:
            current_time = time.time()
            last_message_time = message_cooldown[message.author.id]
            if current_time - last_message_time < 1:
                return

        with open('level.json', 'r', encoding='utf-8') as f:
            users = json.load(f)
        await update_data(users, message.author, message.guild)
        
        server_xp = users[str(message.guild.id)]["message_xp"]
        await add_experience(users, message.author, server_xp, message.guild)
        
        await level_up(users, message.author, message.channel, message.guild)

        message_cooldown[message.author.id] = time.time()

        with open('level.json', 'w', encoding='utf-8') as f:
            json.dump(users, f, indent=2)
    await bot.process_commands(message)

async def update_data(users, user, server):
    server_id = str(server.id)
    if server_id not in users:
        users[server_id] = {
            "message_xp": 4,
            str(user.id): {
                "experience": 0,
                "level": 1
            }
        }
    else:
        if "message_xp" not in users[server_id]:
            users[server_id]["message_xp"] = 4
        if str(user.id) not in users[server_id]:
            users[server_id][str(user.id)] = {
                "experience": 0,
                "level": 1
            }

async def add_experience(users, user, exp, server):
    users[str(user.guild.id)][str(user.id)]['experience'] += exp

async def level_up(users, user, channel, server):
    experience = users[str(user.guild.id)][str(user.id)]['experience']
    lvl_start = users[str(user.guild.id)][str(user.id)]['level']
    lvl_end = int(experience ** (1/4))
    if str(user.guild.id) != '757383943116030074':
        if lvl_start < lvl_end:
            await channel.send(':fire: {} 升级到 **Level {}!**'.format(user.mention, lvl_end))
            users[str(user.guild.id)][str(user.id)]['level'] = lvl_end

@bot.command(aliases = ['rank','lvl'])
async def level(ctx,member: discord.Member = None):
    if not member:
        user = ctx.message.author
        with open('level.json','r', encoding='utf-8') as f:
            users = json.load(f)
        lvl = users[str(ctx.guild.id)][str(user.id)]['level']
        exp = users[str(ctx.guild.id)][str(user.id)]['experience']

        embed = discord.Embed(title = 'Level {}'.format(lvl), description = f"{exp} XP " ,color = discord.Color.green())
        embed.set_author(name = ctx.author, icon_url = ctx.author.avatar.url)
        await ctx.send(embed = embed)
    else:
        with open('level.json','r', encoding='utf-8') as f:
            users = json.load(f)
        lvl = users[str(ctx.guild.id)][str(member.id)]['level']
        exp = users[str(ctx.guild.id)][str(member.id)]['experience']
        embed = discord.Embed(title = 'Level {}'.format(lvl), description = f"{exp} XP" ,color = discord.Color.green())
        embed.set_author(name = member, icon_url = member.avatar.url)

        await ctx.send(embed = embed)

@bot.tree.command(name="leaderboard", description="查看服务器等级排行榜前10名")
async def hello(ctx: discord.Interaction):
    embed = discord.Embed(title=f"{ctx.guild.name} 等级排行榜", color=discord.Colour.blurple())
    with open('level.json', 'r', encoding='utf-8') as file:
        data = json.load(file)
    user_data = {k:v for k,v in data[str(ctx.guild.id)].items() if k != "message_xp"}
    sorted_data = sorted(user_data.items(), key = lambda item:item[1]['experience'], reverse=True)
    for pos, (id, bal) in enumerate(sorted_data):
        member = ctx.guild.get_member(int(id))
        embed.add_field(name=f"{pos+1} - {member.display_name} (@{member.name})", value=f"**Level {bal['level']}**\n{bal['experience']} XP", inline=False)
        embed.set_author(name=f"{ctx.user.name}", icon_url = ctx.user.avatar.url)
        if pos+1 > 9:
            break 
    await ctx.response.send_message(embed=embed)

@bot.command(aliases=['setxp', 'setmessagexp'])
@commands.has_permissions(administrator=True)
async def set_message_xp(ctx, xp_amount: int):
    if xp_amount < 1:
        await ctx.send("XP值不能小于1!")
        return
    
    with open('level.json', 'r', encoding='utf-8') as f:
        users = json.load(f)
    
    server_id = str(ctx.guild.id)
    if server_id not in users:
        users[server_id] = {"message_xp": 4}
    
    users[server_id]["message_xp"] = xp_amount
    
    with open('level.json', 'w', encoding='utf-8') as f:
        json.dump(users, f, indent=2)
    
    await ctx.send(f"已设置当前服务器单条消息获取XP为 **{xp_amount}**!")

bot.run("你的Bot Token")  # 替换为你的Bot令牌

注意事项

  • 替换代码中的你的前缀和你的Bot Token为实际值
  • 首次运行后,旧服务器数据会自动补加message_xp字段,无需手动修改JSON
  • 使用命令时,服务器管理员输入!setxp 7即可将单条消息XP改为7(命令前缀需与代码中一致)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:59:55