如何在Discord.Net中为事件或命令实现冷却机制?
实现Discord机器人关键词GIF的冷却功能
方案1:用Discord.py内置冷却装饰器(快速实现全局限制)
如果你的机器人基于discord.py开发,直接用框架自带的commands.cooldown装饰器就能搞定,比如限制单个用户10秒内只能触发一次GIF回复:
from discord.ext import commands from discord.ext.commands import CommandOnCooldown @commands.cooldown(1, 10, commands.BucketType.user) # 1次/10秒,按用户维度限制 async def on_message(message): # 跳过机器人自己发的消息,避免循环触发 if message.author.bot: return try: # 关键词检测逻辑 keywords = {"fox": "https://example.com/fox.gif", "dog": "https://example.com/dog.gif"} found_gifs = [] for keyword, gif_url in keywords.items(): if keyword in message.content.lower(): found_gifs.append(gif_url) if found_gifs: await message.channel.send("\n".join(found_gifs)) except CommandOnCooldown as e: # 冷却中触发时给用户提示 await message.channel.send(f"别急!再等{e.retry_after:.1f}秒就能再发GIF啦~")
这个方案不用自己维护冷却状态,框架会自动处理,还能捕获冷却异常给用户反馈。
方案2:自定义冷却逻辑(支持关键词级精细控制)
如果需要给每个关键词单独设冷却(比如“fox”15秒冷却,“dog”10秒冷却),可以自己用字典记录触发时间:
from datetime import datetime, timedelta # 存储冷却状态:键为(用户ID, 关键词),值为最后触发时间 cooldown_records = {} # 给不同关键词设置不同冷却时间 KEYWORD_COOLDOWNS = {"fox": 15, "dog": 10} async def on_message(message): if message.author.bot: return keywords = {"fox": "https://example.com/fox.gif", "dog": "https://example.com/dog.gif"} found_gifs = [] user_id = message.author.id for keyword, gif_url in keywords.items(): if keyword not in message.content.lower(): continue now = datetime.now() cooldown_key = (user_id, keyword) last_trigger_time = cooldown_records.get(cooldown_key) # 检查是否在冷却期内 if last_trigger_time and now - last_trigger_time < timedelta(seconds=KEYWORD_COOLDOWNS[keyword]): remaining_time = (last_trigger_time + timedelta(seconds=KEYWORD_COOLDOWNS[keyword]) - now).total_seconds() await message.channel.send(f"关键词「{keyword}」还在冷却,请再等{remaining_time:.1f}秒~") continue # 冷却通过,更新记录并添加GIF cooldown_records[cooldown_key] = now found_gifs.append(gif_url) if found_gifs: await message.channel.send("\n".join(found_gifs))
方案3:双重冷却(同时限制用户和频道)
要是想既防单个用户刷屏,又避免整个频道被GIF填满,可以同时维护用户和频道的冷却状态:
from datetime import datetime, timedelta user_cooldown = {} # (用户ID, 关键词): 最后触发时间 channel_cooldown = {} # (频道ID, 关键词): 最后触发时间 USER_LIMIT = 10 # 用户对单个关键词的冷却时间(秒) CHANNEL_LIMIT = 5 # 频道对单个关键词的冷却时间(秒) async def on_message(message): if message.author.bot: return keywords = {"fox": "https://example.com/fox.gif", "dog": "https://example.com/dog.gif"} found_gifs = [] user_id = message.author.id channel_id = message.channel.id for keyword, gif_url in keywords.items(): if keyword not in message.content.lower(): continue now = datetime.now() # 检查用户冷却 user_key = (user_id, keyword) if user_cooldown.get(user_key) and now - user_cooldown[user_key] < timedelta(seconds=USER_LIMIT): remaining = (user_cooldown[user_key] + timedelta(seconds=USER_LIMIT) - now).total_seconds() await message.channel.send(f"你刷「{keyword}」太频繁啦,再等{remaining:.1f}秒~") continue # 检查频道冷却 channel_key = (channel_id, keyword) if channel_cooldown.get(channel_key) and now - channel_cooldown[channel_key] < timedelta(seconds=CHANNEL_LIMIT): remaining = (channel_cooldown[channel_key] + timedelta(seconds=CHANNEL_LIMIT) - now).total_seconds() await message.channel.send(f"频道里「{keyword}」触发太频繁,再等{remaining:.1f}秒~") continue # 更新冷却记录 user_cooldown[user_key] = now channel_cooldown[channel_key] = now found_gifs.append(gif_url) if found_gifs: await message.channel.send("\n".join(found_gifs))
额外提示
- 要是机器人重启后不想丢失冷却记录,可以把冷却数据存到JSON文件或者数据库里,启动时加载,更新时保存。
- 冷却时间可以根据实际使用情况调整,平衡用户体验和防刷屏效果。
内容的提问来源于stack exchange,提问作者NotNameless
相关产品推荐
相关产品推荐

