From e7ee97074bc439bffafc7675fa22dd972789ebaf Mon Sep 17 00:00:00 2001 From: neoarz Date: Sun, 28 Sep 2025 22:48:10 -0400 Subject: [PATCH] refactor(fun): cogs into one group Combined all fun commands into a single 'fun' GroupCog with subcommands, replacing individual cogs for coinflip, eightball, minesweeper, randomfact, and rockpaperscissors. Updated bot.py to load the fun cog as a package and adjusted help.py to reflect the new command structure. This improves organization and discoverability of fun commands. --- bot.py | 42 ++++++++++++++++---------- cogs/fun/__init__.py | 55 +++++++++++++++++++++++++++++++++++ cogs/fun/coinflip.py | 20 ++++--------- cogs/fun/eightball.py | 24 +++------------ cogs/fun/minesweeper.py | 23 ++++----------- cogs/fun/randomfact.py | 15 +++------- cogs/fun/rockpaperscissors.py | 14 +++------ cogs/general/help.py | 14 +++++---- 8 files changed, 114 insertions(+), 93 deletions(-) create mode 100644 cogs/fun/__init__.py diff --git a/bot.py b/bot.py index d75f222..9f1f3d5 100644 --- a/bot.py +++ b/bot.py @@ -86,21 +86,33 @@ class DiscordBot(commands.Bot): for folder in os.listdir(cogs_path): folder_path = os.path.join(cogs_path, folder) if os.path.isdir(folder_path) and not folder.startswith('__'): - for file in os.listdir(folder_path): - if file.endswith(".py") and not file.startswith('__'): - extension = file[:-3] - full_name = f"{folder}.{extension}".lower() - if extension.lower() in disabled_cogs or full_name in disabled_cogs: - self.logger.info(f"Skipped disabled extension '{full_name}'") - continue - try: - await self.load_extension(f"cogs.{folder}.{extension}") - self.logger.info(f"Loaded extension '{folder}.{extension}'") - except Exception as e: - exception = f"{type(e).__name__}: {e}" - self.logger.error( - f"Failed to load extension {folder}.{extension}\n{exception}" - ) + init_file = os.path.join(folder_path, "__init__.py") + if os.path.exists(init_file): + try: + await self.load_extension(f"cogs.{folder}") + if folder != "fun": + self.logger.info(f"Loaded extension '{folder}'") + except Exception as e: + exception = f"{type(e).__name__}: {e}" + self.logger.error( + f"Failed to load extension {folder}\n{exception}" + ) + else: + for file in os.listdir(folder_path): + if file.endswith(".py") and not file.startswith('__'): + extension = file[:-3] + full_name = f"{folder}.{extension}".lower() + if extension.lower() in disabled_cogs or full_name in disabled_cogs: + self.logger.info(f"Skipped disabled extension '{full_name}'") + continue + try: + await self.load_extension(f"cogs.{folder}.{extension}") + self.logger.info(f"Loaded extension '{folder}.{extension}'") + except Exception as e: + exception = f"{type(e).__name__}: {e}" + self.logger.error( + f"Failed to load extension {folder}.{extension}\n{exception}" + ) for file in os.listdir(cogs_path): if file.endswith(".py") and not file.startswith('__'): diff --git a/cogs/fun/__init__.py b/cogs/fun/__init__.py new file mode 100644 index 0000000..8cb0e7c --- /dev/null +++ b/cogs/fun/__init__.py @@ -0,0 +1,55 @@ +import discord +from discord.ext import commands +from discord.ext.commands import Context + +from .coinflip import coinflip_command +from .eightball import eightball_command +from .minesweeper import minesweeper_command +from .randomfact import randomfact_command +from .rockpaperscissors import rps_command + +class Fun(commands.GroupCog, name="fun"): + def __init__(self, bot) -> None: + self.bot = bot + super().__init__() + + @commands.hybrid_command( + name="coinflip", + description="Make a coin flip, but give your bet before." + ) + async def coinflip(self, context): + return await coinflip_command()(self, context) + + @commands.hybrid_command( + name="8ball", + description="Ask any question to the bot.", + ) + async def eight_ball(self, context, *, question: str): + return await eightball_command()(self, context, question=question) + + @commands.hybrid_command( + name="minesweeper", + description="Play a buttoned minesweeper mini-game." + ) + async def minesweeper(self, context): + return await minesweeper_command()(self, context) + + @commands.hybrid_command(name="randomfact", description="Get a random fact.") + async def randomfact(self, context): + return await randomfact_command()(self, context) + + @commands.hybrid_command( + name="rps", description="Play the rock paper scissors game against the bot." + ) + async def rock_paper_scissors(self, context): + return await rps_command()(self, context) + +async def setup(bot) -> None: + cog = Fun(bot) + await bot.add_cog(cog) + + bot.logger.info("Loaded extension 'fun.coinflip'") + bot.logger.info("Loaded extension 'fun.8ball'") + bot.logger.info("Loaded extension 'fun.minesweeper'") + bot.logger.info("Loaded extension 'fun.randomfact'") + bot.logger.info("Loaded extension 'fun.rps'") diff --git a/cogs/fun/coinflip.py b/cogs/fun/coinflip.py index 0827a3a..2f68de6 100644 --- a/cogs/fun/coinflip.py +++ b/cogs/fun/coinflip.py @@ -1,7 +1,6 @@ import random import discord from discord.ext import commands -from discord.ext.commands import Context class Choice(discord.ui.View): def __init__(self) -> None: @@ -22,18 +21,12 @@ class Choice(discord.ui.View): self.value = "tails" self.stop() -class CoinFlip(commands.Cog, name="coinflip"): - def __init__(self, bot) -> None: - self.bot = bot - +def coinflip_command(): @commands.hybrid_command( - name="coinflip", description="Make a coin flip, but give your bet before." + name="coinflip", + description="Make a coin flip, but give your bet before." ) - async def coinflip(self, context: Context) -> None: - """ - Make a coin flip, but give your bet before. - :param context: The hybrid command context. - """ + async def coinflip(self, context): buttons = Choice() embed = discord.Embed( title="Coinflip", @@ -59,6 +52,5 @@ class CoinFlip(commands.Cog, name="coinflip"): ) embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") await message.edit(embed=embed, view=None, content=None) - -async def setup(bot) -> None: - await bot.add_cog(CoinFlip(bot)) \ No newline at end of file + + return coinflip diff --git a/cogs/fun/eightball.py b/cogs/fun/eightball.py index 330ade1..0afd508 100644 --- a/cogs/fun/eightball.py +++ b/cogs/fun/eightball.py @@ -1,26 +1,12 @@ import random -import discord -from discord import app_commands from discord.ext import commands -from discord.ext.commands import Context - - -class EightBall(commands.Cog, name="8ball"): - def __init__(self, bot) -> None: - self.bot = bot +def eightball_command(): @commands.hybrid_command( name="8ball", description="Ask any question to the bot.", ) - @app_commands.describe(question="The question you want to ask.") - async def eight_ball(self, context: Context, *, question: str) -> None: - """ - Ask any question to the bot. - - :param context: The hybrid command context. - :param question: The question that should be asked by the user. - """ + async def eight_ball(self, context, *, question: str): answers = [ "It is certain.", "It is decidedly so.", @@ -51,7 +37,5 @@ class EightBall(commands.Cog, name="8ball"): embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_footer(text=f"The question was: {question}") await context.send(embed=embed) - - -async def setup(bot) -> None: - await bot.add_cog(EightBall(bot)) \ No newline at end of file + + return eight_ball diff --git a/cogs/fun/minesweeper.py b/cogs/fun/minesweeper.py index e81f86c..70c0de9 100644 --- a/cogs/fun/minesweeper.py +++ b/cogs/fun/minesweeper.py @@ -2,8 +2,6 @@ import random from itertools import repeat import discord from discord.ext import commands -from discord.ext.commands import Context - class RowButton(discord.ui.Button): def __init__(self, ctx, label, custom_id, bombs, board): @@ -66,7 +64,6 @@ class RowButton(discord.ui.Button): await interaction.edit_original_response(view=view) - class MsView(discord.ui.View): def __init__(self, ctx, options, bombs, board): super().__init__() @@ -155,21 +152,13 @@ class MsView(discord.ui.View): self.GetBoardPos(pos) ] = bombemo - -class Minesweeper(commands.Cog, name="minesweeper"): - def __init__(self, bot) -> None: - self.bot = bot - +def minesweeper_command(): @commands.hybrid_command( name="minesweeper", description="Play a buttoned minesweeper mini-game." ) - async def minesweeper(self, context: Context) -> None: - """ - Play a buttoned minesweeper mini-game. - :param context: The hybrid command context. - """ - board = [["឵឵ "] * 5 for _ in range(5)] # Unicode block character, usually doesnt show up in Discord or github, search up invisible character on google + async def minesweeper(self, context): + board = [["឵឵ "] * 5 for _ in range(5)] bombs = 0 bombpositions = [] for x in repeat(None, random.randint(4, 11)): @@ -197,7 +186,5 @@ class Minesweeper(commands.Cog, name="minesweeper"): view = MsView(context, ExtractBlocks(), bombpositions, board) message = await context.send(embed=embed, view=view) view.message = message - - -async def setup(bot) -> None: - await bot.add_cog(Minesweeper(bot)) + + return minesweeper diff --git a/cogs/fun/randomfact.py b/cogs/fun/randomfact.py index fb211ca..013b389 100644 --- a/cogs/fun/randomfact.py +++ b/cogs/fun/randomfact.py @@ -1,15 +1,10 @@ import aiohttp import discord from discord.ext import commands -from discord.ext.commands import Context - - -class RandomFact(commands.Cog, name="randomfact"): - def __init__(self, bot) -> None: - self.bot = bot +def randomfact_command(): @commands.hybrid_command(name="randomfact", description="Get a random fact.") - async def randomfact(self, context: Context) -> None: + async def randomfact(self, context): async with aiohttp.ClientSession() as session: async with session.get( "https://uselessfacts.jsph.pl/random.json?language=en" @@ -30,7 +25,5 @@ class RandomFact(commands.Cog, name="randomfact"): ) embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") await context.send(embed=embed) - - -async def setup(bot) -> None: - await bot.add_cog(RandomFact(bot)) \ No newline at end of file + + return randomfact diff --git a/cogs/fun/rockpaperscissors.py b/cogs/fun/rockpaperscissors.py index 9d369b5..b9bb943 100644 --- a/cogs/fun/rockpaperscissors.py +++ b/cogs/fun/rockpaperscissors.py @@ -1,7 +1,6 @@ import random import discord from discord.ext import commands -from discord.ext.commands import Context class RockPaperScissors(discord.ui.Select): def __init__(self) -> None: @@ -39,7 +38,6 @@ class RockPaperScissors(discord.ui.Select): winner = (3 + user_choice_index - bot_choice_index) % 3 - # Get the user mention user_mention = interaction.user.mention if winner == 0: @@ -61,14 +59,11 @@ class RockPaperScissorsView(discord.ui.View): super().__init__() self.add_item(RockPaperScissors()) -class RPS(commands.Cog, name="rps"): - def __init__(self, bot) -> None: - self.bot = bot - +def rps_command(): @commands.hybrid_command( name="rps", description="Play the rock paper scissors game against the bot." ) - async def rock_paper_scissors(self, context: Context) -> None: + async def rock_paper_scissors(self, context): view = RockPaperScissorsView() embed = discord.Embed( title="Rock Paper Scissors", @@ -77,6 +72,5 @@ class RPS(commands.Cog, name="rps"): ) embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") await context.send(embed=embed, view=view) - -async def setup(bot) -> None: - await bot.add_cog(RPS(bot)) \ No newline at end of file + + return rock_paper_scissors diff --git a/cogs/general/help.py b/cogs/general/help.py index 536462f..1a687d0 100644 --- a/cogs/general/help.py +++ b/cogs/general/help.py @@ -47,11 +47,7 @@ class Help(commands.Cog, name="help"): # "context_menus": "general", # Fun Commands - "randomfact": "fun", - "coinflip": "fun", - "rps": "fun", - "8ball": "fun", - "minesweeper": "fun", + "fun": "fun", # Moderation Commands "kick": "moderation", @@ -183,6 +179,14 @@ class Help(commands.Cog, name="help"): description = app_command.description.partition("\n")[0] if getattr(app_command, "description", None) else "No description available" commands_in_category.append((app_command.name, description)) seen_names.add(app_command.name) + + if hasattr(app_command, 'commands') and category == "fun": + for subcommand in app_command.commands: + if subcommand.name in seen_names: + continue + sub_desc = subcommand.description.partition("\n")[0] if getattr(subcommand, "description", None) else "No description available" + commands_in_category.append((f"{app_command.name} {subcommand.name}", sub_desc)) + seen_names.add(f"{app_command.name} {subcommand.name}") if not commands_in_category: embed = discord.Embed(