How to save command cooldown?


How to save command cooldown?



The code below adds a cooldown for command, but when bot restarts, the cooldown resets. So how can I make the bot remember from previous usage? If the cooldown limit is 5 times per day and if the member used 3 times and if bot restarts it should start from where it was left for all members.


token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
prefix = "?"

import discord
from discord.ext import commands
import pickle, os

bot = commands.Bot(command_prefix=prefix)

@bot.event
async def on_ready():
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')

cooldown_info_path = "cd.pkl" # the file to store the data
if os.path.exists(cooldown_info_path): # on the initial run where "cd.pkl" file hadn't been created yet

with open(cooldown_info_path, 'rb') as f:
d = pickle.load(f)
for name, func in bot.commands.items():
if name in d: # if the Command name has a CooldownMapping stored in file, override _bucket
bot.commands[name]._buckets = d[name]


class Bot(commands.Bot):
def run(self, *args, cooldown_info_path="cd.pkl", **kwargs):
import os, pickle

if os.path.exists(cooldown_info_path): # on the initial run where "cd.pkl" file hadn't been created yet
with open(cooldown_info_path, 'rb') as f:
d = pickle.load(f)
for name, func in self.commands.items():
if name in d: # if the Command name has a CooldownMapping stored in file, override _bucket
self.commands[name]._buckets = d[name]
super().run(*args, **kwargs)
with open(cooldown_info_path, 'wb') as f:
# dumps a dict of command name to CooldownMapping mapping
pickle.dump({name: func._buckets for name, func in self.commands.items()}, f)


bot = Bot(...)
# everything else as usual

@bot.command(pass_context=True)
@commands.cooldown(1, 3600, commands.BucketType.user)
async def hello(ctx):
msg = "Hello... {0.author.mention}".format(ctx.message)
await bot.say(msg)


bot.run(token)

with open(cooldown_info_path, 'wb') as f:
# dumps a dict of command name to CooldownMapping mapping
pickle.dump({name: func._buckets for name, func in bot.commands.items()}, f)





You'd have to save the state of ping._buckets, and then load that state back into ping._buckets in your on_ready event. I'd try pickleing the object first, and if that doesn't work you'll have to dig into the code to understand how it's put together. It looks like all the relevant code is split between core.py and cooldowns.py.
– Patrick Haugh
Jun 30 at 23:13


ping._buckets


ping._buckets


on_ready


pickle


core.py


cooldowns.py




1 Answer
1



Similar to what Patrick Haugh suggested, the cooldown mapping is stored in Command._buckets. You can pickle the bucket before the bot starts and save it after the bot finishes.


Command._buckets



Add the following before and after bot.run(...).


bot.run(...)


import pickle, os
cooldown_info_path = "cd.pkl" # the file to store the data
if os.path.exists(cooldown_info_path): # on the initial run where "cd.pkl" file hadn't been created yet

with open(cooldown_info_path, 'rb') as f:
d = pickle.load(f)
for name, func in bot.commands.items():
if name in d: # if the Command name has a CooldownMapping stored in file, override _bucket
bot.commands[name]._buckets = d[name]

bot.run('TOKEN')

with open(cooldown_info_path, 'wb') as f:
# dumps a dict of command name to CooldownMapping mapping
pickle.dump({name: func._buckets for name, func in bot.commands.items()}, f)



Alternatively, you can place the aforementioned code in the method run(...) of a subclass of Bot. Doing so makes a seemingly transparent addition of an additional functionality:


run(...)


Bot


class Bot(commands.Bot):
def run(self, *args, cooldown_info_path="cd.pkl", **kwargs):
import os, pickle

if os.path.exists(cooldown_info_path): # on the initial run where "cd.pkl" file hadn't been created yet
with open(cooldown_info_path, 'rb') as f:
d = pickle.load(f)
for name, func in self.commands.items():
if name in d: # if the Command name has a CooldownMapping stored in file, override _bucket
self.commands[name]._buckets = d[name]
super().run(*args, **kwargs)
with open(cooldown_info_path, 'wb') as f:
# dumps a dict of command name to CooldownMapping mapping
pickle.dump({name: func._buckets for name, func in self.commands.items()}, f)


bot = Bot(...)
# everything else as usual



You hadn't mentioned which database you're using nor how you're connecting to the database so my answer addressed storing to a file.



In case you're still confused, this is how it should be set up:


token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
prefix = "?"

from discord.ext import commands


class Bot(commands.Bot):
def run(self, *args, cooldown_info_path="cd.pkl", **kwargs):
import os, pickle

if os.path.exists(cooldown_info_path): # on the initial run where "cd.pkl" file hadn't been created yet
with open(cooldown_info_path, 'rb') as f:
d = pickle.load(f)
for name, func in self.commands.items():
if name in d: # if the Command name has a CooldownMapping stored in file, override _bucket
self.commands[name]._buckets = d[name]
try:
super().run(*args, **kwargs)
finally:
with open(cooldown_info_path, 'wb') as f:
# dumps a dict of command name to CooldownMapping mapping
pickle.dump({name: func._buckets for name, func in self.commands.items()}, f)


bot = Bot(prefix)
# everything else as usual

@bot.event
async def on_ready():
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')

@bot.command(pass_context=True)
@commands.cooldown(1, 3600, commands.BucketType.user)
async def hello(ctx):
msg = "Hello... {0.author.mention}".format(ctx.message)
await bot.say(msg)


bot.run(token)






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages