From b8b8484466a9c22e58ea75a4b46e7cdba2356cbb Mon Sep 17 00:00:00 2001 From: bibin Date: Sun, 27 Dec 2020 22:47:10 +0100 Subject: [PATCH 1/6] Style: move commands up Commands should be declared before loading further extensions --- src/bot.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bot.py b/src/bot.py index 60c1a4d..c6c01bb 100644 --- a/src/bot.py +++ b/src/bot.py @@ -24,10 +24,6 @@ if TOKEN is None: bot = commands.Bot(command_prefix=commands.when_mentioned_or('$b ')) -default_extensions = ['developer'] - -for extension in default_extensions: - bot.load_extension(f'cogs.{extension}') @bot.command() @commands.is_owner() @@ -35,16 +31,22 @@ async def load(ctx, extension): bot.load_extension(f'cogs.{extension}') print(f'cogs.{extension} loaded') + @bot.command() @commands.is_owner() async def unload(ctx, extension): bot.unload_extension(f'cogs.{extension}') print(f'cogs.{extension} unloaded') + @bot.command() @commands.is_owner() async def reload(ctx, extension): bot.reload_extension(f'cogs.{extension}') print(f'cogs.{extension} reloaded') + +for extension in ['developer']: + bot.load_extension(f'cogs.{extension}') + bot.run(TOKEN) From 841a6586fef7f269c73ebac8bfe54ed2d7b140fc Mon Sep 17 00:00:00 2001 From: bibin Date: Sat, 2 Jan 2021 19:39:25 +0100 Subject: [PATCH 2/6] feat: extension loading commands are now hidden --- src/bot.py | 6 +++--- src/cogs/basic_game.py | 0 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/cogs/basic_game.py diff --git a/src/bot.py b/src/bot.py index c6c01bb..37eed11 100644 --- a/src/bot.py +++ b/src/bot.py @@ -25,21 +25,21 @@ if TOKEN is None: bot = commands.Bot(command_prefix=commands.when_mentioned_or('$b ')) -@bot.command() +@bot.command(hidden=True) @commands.is_owner() async def load(ctx, extension): bot.load_extension(f'cogs.{extension}') print(f'cogs.{extension} loaded') -@bot.command() +@bot.command(hidden=True) @commands.is_owner() async def unload(ctx, extension): bot.unload_extension(f'cogs.{extension}') print(f'cogs.{extension} unloaded') -@bot.command() +@bot.command(hidden=True) @commands.is_owner() async def reload(ctx, extension): bot.reload_extension(f'cogs.{extension}') diff --git a/src/cogs/basic_game.py b/src/cogs/basic_game.py new file mode 100644 index 0000000..e69de29 From 1d8ed8f2ea09a1d6222cc6e6b7f3757020763304 Mon Sep 17 00:00:00 2001 From: bibin Date: Sun, 3 Jan 2021 01:56:30 +0100 Subject: [PATCH 3/6] Initial: add basic_game module --- src/cogs/basic_game.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/cogs/basic_game.py b/src/cogs/basic_game.py index e69de29..41864af 100644 --- a/src/cogs/basic_game.py +++ b/src/cogs/basic_game.py @@ -0,0 +1,19 @@ +"""A base module for integrating text games into a discord cog""" + +# import discord +from discord.ext import commands + + +class Cog(commands.Cog): + """A base game cog that has a collection of basic game commands and checkers""" + pass + + +class Session: + """A base class for holding channel specific information and setting up a game""" + pass + + +class Display: + """A base class for displaying game in discord""" + pass From 4714fe512774c1cfc583cbb6e638eef15cad6ae0 Mon Sep 17 00:00:00 2001 From: bibin Date: Mon, 4 Jan 2021 01:14:14 +0100 Subject: [PATCH 4/6] Feat: Add constructor for basic_game Cog Initializes bot like a regular Cog Initializes an empty session dictionary Initializes the class of the session with a possible default value Changes the group command name to the Cog's name to avoid name clashes in commands --- src/cogs/basic_game.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cogs/basic_game.py b/src/cogs/basic_game.py index 41864af..30a52fd 100644 --- a/src/cogs/basic_game.py +++ b/src/cogs/basic_game.py @@ -6,7 +6,13 @@ from discord.ext import commands class Cog(commands.Cog): """A base game cog that has a collection of basic game commands and checkers""" - pass + + def __init__(self, bot, session_cls=None): + self.bot = bot + self.sessions = {} + self.session_cls = Session if session_cls is None else session_cls + self.group = next(c for c in self.get_commands() if c.name == 'group') + self.group.name = self.qualified_name.lower() class Session: From 823238ee376ed0d9fd0b53adef96c3493a7a9a87 Mon Sep 17 00:00:00 2001 From: bibin Date: Mon, 4 Jan 2021 01:28:07 +0100 Subject: [PATCH 5/6] Feat: Add setup command with check and error The `setup` command creates a game instance for a channel. It also has a check to see if one is already setup and a error handler to deal in that case. I don't think that the check functions can be methods so the 'hack' is to use `ctx.cog` instead of `self` to get the cog instance. There is also a function to check for the inverted condition preventing double defining every check. --- src/cogs/basic_game.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/cogs/basic_game.py b/src/cogs/basic_game.py index 30a52fd..426a52d 100644 --- a/src/cogs/basic_game.py +++ b/src/cogs/basic_game.py @@ -4,6 +4,17 @@ from discord.ext import commands +# checks + + +def is_not(check): + return lambda ctx: not check(ctx) + + +def is_setup(ctx): + return ctx.channel in ctx.cog.sessions + + class Cog(commands.Cog): """A base game cog that has a collection of basic game commands and checkers""" @@ -14,6 +25,20 @@ class Cog(commands.Cog): self.group = next(c for c in self.get_commands() if c.name == 'group') self.group.name = self.qualified_name.lower() + @commands.group(invoke_without_command=True) + async def group(self, ctx): + await ctx.send("try info") + + @group.command() + @commands.check(is_not(is_setup)) + async def setup(self, ctx): + """Creates a game instance for this channel""" + self.sessions[ctx.channel] = self.session_cls() + + @setup.error + async def setup_handler(self, ctx, error): + await ctx.send(f"A game of is already setup in this channel") + class Session: """A base class for holding channel specific information and setting up a game""" From 2216b70e3414365d1299eddaf2527f49f19b7543 Mon Sep 17 00:00:00 2001 From: bibin Date: Mon, 4 Jan 2021 02:32:45 +0100 Subject: [PATCH 6/6] Feat: Add emoji confirming/error reactions If the commands throws an error then the bot marks the command message with a cross emoji reaction otherwise it adds a check mark. (Also resolved some overshadowing warning of extension) --- src/bot.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/bot.py b/src/bot.py index 37eed11..6bad9a9 100644 --- a/src/bot.py +++ b/src/bot.py @@ -10,6 +10,8 @@ __author__ = 'Bibin Muttappillil' # standard library imports import os from dotenv import load_dotenv +import sys +import traceback # discord imports from discord.ext import commands @@ -25,25 +27,37 @@ if TOKEN is None: bot = commands.Bot(command_prefix=commands.when_mentioned_or('$b ')) -@bot.command(hidden=True) -@commands.is_owner() -async def load(ctx, extension): - bot.load_extension(f'cogs.{extension}') - print(f'cogs.{extension} loaded') +@bot.event +async def on_command_error(ctx, error): + print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) + traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr) + await ctx.message.add_reaction('❌') + + +@bot.event +async def on_command_completion(ctx): + await ctx.message.add_reaction('✅') @bot.command(hidden=True) @commands.is_owner() -async def unload(ctx, extension): - bot.unload_extension(f'cogs.{extension}') - print(f'cogs.{extension} unloaded') +async def load(ctx, ext): + bot.load_extension(f'cogs.{ext}') + print(f'cogs.{ext} loaded') @bot.command(hidden=True) @commands.is_owner() -async def reload(ctx, extension): - bot.reload_extension(f'cogs.{extension}') - print(f'cogs.{extension} reloaded') +async def unload(ctx, ext): + bot.unload_extension(f'cogs.{ext}') + print(f'cogs.{ext} unloaded') + + +@bot.command(hidden=True) +@commands.is_owner() +async def reload(ctx, ext): + bot.reload_extension(f'cogs.{ext}') + print(f'cogs.{ext} reloaded') for extension in ['developer']: