如何为Discord.py的on_message事件添加XP发放冷却计时器?
嘿,我懂你为啥用@commands.cooldown没效果啦——那个装饰器是专门给用@bot.command()定义的命令函数设计的,直接贴在on_message事件或者普通的user_add_xp函数上根本不生效。咱们换个思路,手动实现冷却逻辑就搞定了!
解决方案:手动维护用户冷却时间
咱们可以用一个字典来记录每个用户最后一次获得XP的时间,每次收到消息时先检查时间差是否超过两分钟,再决定要不要发放XP。
首先,先导入需要的模块,定义冷却时间和存储冷却的字典:
import datetime from discord.ext import commands import os import json bot = commands.Bot(command_prefix="你的命令前缀") # 存储每个用户最后获得XP的时间,键是用户ID(字符串),值是datetime对象 xp_cooldowns = {} # 冷却时间设为120秒(两分钟) XP_COOLDOWN_SECONDS = 120
然后修改on_message事件,加入冷却判断逻辑:
@bot.event async def on_message(message): # 忽略机器人自己发的消息,避免无限循环 if message.author.bot: await bot.process_commands(message) return user_id = str(message.author.id) # 转成字符串,和JSON的键保持一致 now = datetime.datetime.now() # 检查用户是否在冷却中 if user_id in xp_cooldowns: time_since_last_xp = (now - xp_cooldowns[user_id]).total_seconds() if time_since_last_xp < XP_COOLDOWN_SECONDS: # 还没到冷却时间,直接处理命令,不发XP await bot.process_commands(message) return # 冷却时间到了,更新最后获得XP的时间,然后加XP xp_cooldowns[user_id] = now user_add_xp(user_id, 2) # 别忘了处理命令 await bot.process_commands(message)
另外,我顺便优化了你的user_add_xp函数,解决了JSON键必须是字符串的问题(原来的代码里用整数ID当键,存到JSON里会自动转成字符串,下次读取时就会出现KeyError):
def user_add_xp(user_id, xp): # 初始化用户数据字典 users = {} # 如果用户数据文件存在就读取 if os.path.isfile('users.json'): with open('users.json', 'r') as fp: users = json.load(fp) # 如果用户不存在,创建新的条目 if user_id not in users: users[user_id] = {'xp': 0} # 添加XP users[user_id]['xp'] += xp # 写回文件 with open('users.json', 'w') as fp: json.dump(users, fp, sort_keys=True, indent=4)
补充说明
- 这个方案里的冷却字典
xp_cooldowns是存在内存里的,如果机器人重启,冷却记录会清空,但一般来说影响不大,用户重启后重新计时就行。如果需要持久化冷却时间,也可以把冷却时间一起存到users.json里,每次读取时加载。 - 一定要把用户ID转成字符串,因为JSON不支持整数类型的键,不然存进去再读出来就会出现键类型不匹配的问题。
内容的提问来源于stack exchange,提问作者MajorTanya
相关产品推荐
相关产品推荐

