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
相关产品推荐
相关产品推荐

