5

I'm trying to make a command that makes the bot basically in sleep mode, this is meant to make the bot stop responding to commands (or on_messages if possible) Trying to use client.pause (Boolean) and it didn't give errors i don't know what it does exactly but nothing happens Below is where I am so far.

@client.command(pass_context=True)
async def sleep(ctx):
    client.pause = True

@client.command(pass_context=True)
async def awake(ctx):
    client.pause = False
  • Are you using any sort of database backend where you can save a variable for something like `is_asleep`? – Jab Feb 22 '19 at 17:58
  • No, I'm not using it –  Feb 22 '19 at 18:01
  • Nevermind, this would be a per instance variable, although I would suggest some way of persisting variables. – Jab Feb 22 '19 at 18:06

2 Answers2

2

You could use on_message to override the bot from invoking commands automatically, then build some logic for you to decide decide it doesn't want to take any commands anymore (aka sleep). But be sure you have the option as the bot owner to awaken it or you're SOL and will need to restart.

Something like the following should work.

The assumption in my code being you're using the rework and f-strings are acceptable, but the logic is here and very little needs to be changed I think for it to be compatible with the async version.

Basic control flow:

bot.py

from discord.ext import commands

class MyBot(commands.bot):
    def __init__(self, command_prefix = '!', description=None):
        super().__init__(command_prefix, description)
        #you could just say False here but if you
        #want to start the bot asleep here's a decent way to do it.
        self.asleep = kwargs.get('asleep', False)

async def is_owner(obj):
    owner = self.application_info().owner
    return obj.author == owner


async def on_message(self, message):
    ctx = await self.get_context(message)
    is_owner = client.is_owner(ctx):
    
    if is_owner or not self.asleep:
        self.invoke(ctx)

...

owner.py - or wherever you keep your "bot owner only" commands.

from discord.ext import commands

...

@commands.command()
async def sleep(self, ctx):
    self.bot.asleep = True
    await ctx.say(f"I am now asleep, I will only respond to {ctx.author}")


@commands.command()
async def awaken(self, ctx):
    self.bot.asleep = False
    await ctx.say("Ahhh, just woke up! Ready to take commands!")

...

launcher.py

import MyBot

...

bot = MyBot(...)
bot.load_extension("path/to/owner_py_file")

...

I came up with this based on how RDanny bot assign's it's Database to each context before a command is called. It's a very well written bot that the owner has put out the source code publicly for educational purposes.


Edit

to accommodate your current build

For your case, I assume you're just creating a bot using something like client = commands.bot(...) this is again pretty cookiecutter and won't allow you to leverage any power you'd gain from subclassing bot, but you could just implement the following and gain the same functionality as above:

client = commands.bot(...)
client.asleep = False

Then for the commands that you showed in the question:

@client.command(pass_context=True)
async def sleep(ctx):
    client.sleep = True

@client.command(pass_context=True)
async def awake(ctx):
    client.asleep = False

Then for the on_message override. Please reference: this answer to help explain why this works. or even the docs. hint hint

async def _is_owner(obj):
    owner = self.application_info().owner
    return obj.author == owner


@client.event()
async def on_message(message):
    ctx = await self.get_context(message)
    is_owner = _is_owner(ctx):
    
    if is_owner or not self.asleep:
        client.invoke(ctx)

If the above implementation fails to work for you then you can give the method described in the answer I linked just above:

@client.event
async def on_message(message):
    is_owner = _is_owner(ctx):
    
    if is_owner or not client.asleep:        
        await bot.process_commands(message)

Please note I don't know how you're module is structured but if this is being done within a class, and you define _is_owner(...) within that class, you will need to use is_owner = self._is_owner(...) although this could be defined elsewhere.

Community
  • 1
  • 1
Jab
  • 26,853
  • 21
  • 75
  • 114
  • Says kwargs is not defined, also I'm not using cogs so i may have messed up somewhere while converting from cogs –  Feb 22 '19 at 20:01
  • Is there a reason you're not using cogs? Also, if not then instead of `self.invoke` just return, Then put all your other "command" logic after that. – Jab Feb 22 '19 at 21:14
  • hmm. that does quite fix it, I'm not using cogs because i already started scripting my bot and wasn't using cogs and It's to much scripts so to turn them into cogs'll take a while –  Feb 22 '19 at 21:55
  • You’re making things even harder for yourself in the long run. Also, “that doesn’t quite fix it” isn’t giving me any information to help you. – Jab Feb 22 '19 at 22:19
  • It doesn't fix the error that kwargs isn't defined, Is there any way you can remake the scripot without the cogs? –  Feb 22 '19 at 22:24
  • I edited my answer. Also, If you're using super.init in Python 3, then you don't need the args/kwargs, I failed to remember this for a second. That was a Py2 thing. Just taking that out should fix it, unless there's an underlying issue elsewhere. Nevertheless, to just stick with what you're doing now; the code in my edit should suffice. – Jab Feb 23 '19 at 01:35
0

You can use the get_prefix function to change the bot command so that it won't respond to any public prefixes.

backup_prefixes=['.','!','s.','k!']
prefixes = ['.','!','s.','k!']
def get_prefix(bot, msg):
    return commands.when_mentioned_or(*prefixes)(bot, msg)

bot = commands.Bot(command_prefix=get_prefix)

@bot.event
async def on_ready():
    print(bot.user.name)


@bot.command(pass_context=True)
async def resume(con):
    for i in backup_prefixes:
        prefixes.append(i)


@bot.command(pass_context=True)
async def pause(con):
    prefixes.clear()
    # prefixes.append("an unknow prefix so it can't be invoked") #Ex: aslkdjflkj2k4lkj21312kj
    prefixes.append(',')

You can additionally add more if statements to make sure that only certain users can use the command to mute the bot so that it won't respond to other users.

KowaiiNeko
  • 327
  • 6
  • 17