hdhdhdhehd
This commit is contained in:
parent
f341ea0aa7
commit
e077a1fbba
122
command_context.py
Normal file
122
command_context.py
Normal file
@ -0,0 +1,122 @@
|
||||
"""
|
||||
Utility module for handling command contexts in Discord.py.
|
||||
|
||||
This module provides functions for setting up commands with different contexts,
|
||||
allowing them to work in DMs, private channels, guilds, or any combination.
|
||||
"""
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from enum import Enum, auto
|
||||
from typing import Optional, List, Dict, Any, Union, Callable, Awaitable
|
||||
|
||||
class AppCommandContext(Enum):
|
||||
"""
|
||||
Enum representing the allowed contexts for application commands.
|
||||
|
||||
This enum defines where commands can be used:
|
||||
- GUILD: Commands can only be used in guilds (servers)
|
||||
- GUILD_INSTALL: Commands can only be used in guilds where the app is installed
|
||||
- PRIVATE: Commands can only be used in private contexts (DMs and private channels)
|
||||
- ALL: Commands can be used in both guilds and private contexts
|
||||
"""
|
||||
GUILD = auto()
|
||||
GUILD_INSTALL = auto()
|
||||
PRIVATE = auto()
|
||||
ALL = auto()
|
||||
|
||||
def set_command_context(
|
||||
command: app_commands.Command,
|
||||
context: AppCommandContext = AppCommandContext.ALL
|
||||
) -> app_commands.Command:
|
||||
"""
|
||||
Set the context for a command, determining where it can be used.
|
||||
|
||||
Args:
|
||||
command: The command to modify
|
||||
context: The context to set for the command
|
||||
|
||||
Returns:
|
||||
The modified command
|
||||
"""
|
||||
# Set guild_only and dm_permission based on the context
|
||||
if context == AppCommandContext.GUILD or context == AppCommandContext.GUILD_INSTALL:
|
||||
command.guild_only = True
|
||||
# dm_permission is automatically set to False when guild_only is True
|
||||
elif context == AppCommandContext.PRIVATE:
|
||||
command.guild_only = False
|
||||
# We need to override the extras to set dm_permission to True and guild_permission to False
|
||||
command.extras["dm_permission"] = True
|
||||
command.extras["default_member_permissions"] = "0" # No permissions in guild
|
||||
elif context == AppCommandContext.ALL:
|
||||
command.guild_only = False
|
||||
command.extras["dm_permission"] = True
|
||||
# Allow default permissions in guilds
|
||||
|
||||
return command
|
||||
|
||||
def create_global_command(
|
||||
bot_tree: app_commands.CommandTree,
|
||||
name: str,
|
||||
description: str,
|
||||
callback: Callable[[discord.Interaction], Awaitable[None]],
|
||||
context: AppCommandContext = AppCommandContext.ALL,
|
||||
**kwargs
|
||||
) -> app_commands.Command:
|
||||
"""
|
||||
Create a command that can be used globally with the specified context.
|
||||
|
||||
Args:
|
||||
bot_tree: The command tree to add the command to
|
||||
name: The name of the command
|
||||
description: The description of the command
|
||||
callback: The function to call when the command is used
|
||||
context: The context to set for the command
|
||||
**kwargs: Additional arguments to pass to the command constructor
|
||||
|
||||
Returns:
|
||||
The created command
|
||||
"""
|
||||
# Create the command
|
||||
command = app_commands.Command(
|
||||
name=name,
|
||||
description=description,
|
||||
callback=callback,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# Set the context
|
||||
set_command_context(command, context)
|
||||
|
||||
# Add the command to the tree
|
||||
bot_tree.add_command(command)
|
||||
|
||||
return command
|
||||
|
||||
def sync_commands(
|
||||
bot_tree: app_commands.CommandTree,
|
||||
guild_specific: bool = True,
|
||||
global_commands: bool = True
|
||||
) -> Awaitable[List[app_commands.Command]]:
|
||||
"""
|
||||
Sync commands with Discord.
|
||||
|
||||
Args:
|
||||
bot_tree: The command tree to sync
|
||||
guild_specific: Whether to sync guild-specific commands
|
||||
global_commands: Whether to sync global commands
|
||||
|
||||
Returns:
|
||||
A coroutine that resolves to the list of synced commands
|
||||
"""
|
||||
if guild_specific and not global_commands:
|
||||
# Only sync guild-specific commands
|
||||
# This is handled by command_customization.register_all_guild_commands
|
||||
return None
|
||||
elif not guild_specific and global_commands:
|
||||
# Only sync global commands
|
||||
return bot_tree.sync()
|
||||
else:
|
||||
# Sync both guild-specific and global commands
|
||||
# This is the default behavior of bot_tree.sync()
|
||||
return bot_tree.sync()
|
120
command_sync_utils.py
Normal file
120
command_sync_utils.py
Normal file
@ -0,0 +1,120 @@
|
||||
"""
|
||||
Utility module for syncing commands with Discord.
|
||||
|
||||
This module provides functions for syncing both global and guild-specific commands,
|
||||
allowing for more flexibility in command registration and supporting commands in
|
||||
both guild and private contexts (DMs and private channels).
|
||||
"""
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
import logging
|
||||
import command_customization
|
||||
from typing import Dict, List, Optional, Union, Any
|
||||
from command_context import AppCommandContext
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
async def sync_global_and_guild_commands(
|
||||
bot: commands.Bot,
|
||||
global_only: bool = False,
|
||||
guild_only: bool = False
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Sync both global and guild-specific commands with Discord.
|
||||
|
||||
This function allows for more control over command syncing, enabling
|
||||
both global commands (that work in DMs) and guild-specific commands
|
||||
with customizations.
|
||||
|
||||
Args:
|
||||
bot: The bot instance
|
||||
global_only: If True, only sync global commands
|
||||
guild_only: If True, only sync guild-specific commands
|
||||
|
||||
Returns:
|
||||
A dictionary containing the results of the sync operations
|
||||
"""
|
||||
results = {
|
||||
"global": [],
|
||||
"guild": {}
|
||||
}
|
||||
|
||||
try:
|
||||
# Sync global commands if requested
|
||||
if not guild_only:
|
||||
log.info("Syncing global commands...")
|
||||
global_synced = await bot.tree.sync()
|
||||
results["global"] = global_synced
|
||||
log.info(f"Synced {len(global_synced)} global command(s)")
|
||||
|
||||
# List the synced commands
|
||||
global_commands = [cmd.name for cmd in global_synced]
|
||||
log.info(f"Global commands: {', '.join(global_commands)}")
|
||||
|
||||
# Sync guild-specific commands if requested
|
||||
if not global_only:
|
||||
log.info("Syncing guild-specific command customizations...")
|
||||
guild_syncs = await command_customization.register_all_guild_commands(bot)
|
||||
results["guild"] = guild_syncs
|
||||
|
||||
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
|
||||
log.info(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
|
||||
|
||||
except Exception as e:
|
||||
log.error(f"Failed to sync commands: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
return results
|
||||
|
||||
def register_global_command(
|
||||
bot: commands.Bot,
|
||||
name: str,
|
||||
description: str,
|
||||
callback: Any,
|
||||
context: AppCommandContext = AppCommandContext.ALL,
|
||||
**kwargs
|
||||
) -> app_commands.Command:
|
||||
"""
|
||||
Register a global command with the specified context.
|
||||
|
||||
Args:
|
||||
bot: The bot instance
|
||||
name: The name of the command
|
||||
description: The description of the command
|
||||
callback: The function to call when the command is used
|
||||
context: The context to set for the command
|
||||
**kwargs: Additional arguments to pass to the command constructor
|
||||
|
||||
Returns:
|
||||
The created command
|
||||
"""
|
||||
from command_context import create_global_command
|
||||
|
||||
return create_global_command(
|
||||
bot.tree,
|
||||
name=name,
|
||||
description=description,
|
||||
callback=callback,
|
||||
context=context,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def set_command_contexts(bot: commands.Bot, contexts: Dict[str, AppCommandContext]) -> None:
|
||||
"""
|
||||
Set the contexts for multiple commands.
|
||||
|
||||
Args:
|
||||
bot: The bot instance
|
||||
contexts: A dictionary mapping command names to contexts
|
||||
"""
|
||||
from command_context import set_command_context
|
||||
|
||||
for cmd in bot.tree.get_commands():
|
||||
if cmd.name in contexts:
|
||||
set_command_context(cmd, contexts[cmd.name])
|
||||
log.info(f"Set context for command '{cmd.name}' to {contexts[cmd.name]}")
|
97
example_global_commands.py
Normal file
97
example_global_commands.py
Normal file
@ -0,0 +1,97 @@
|
||||
"""
|
||||
Example module demonstrating how to create global commands that work in DMs and private channels.
|
||||
|
||||
This module shows how to use the AppCommandContext system to create commands
|
||||
that can be used in both guild and private contexts.
|
||||
"""
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
from command_context import AppCommandContext, create_global_command
|
||||
from typing import Optional
|
||||
|
||||
class GlobalCommandsCog(commands.Cog):
|
||||
"""A cog that demonstrates global commands that work in DMs and private channels."""
|
||||
|
||||
def __init__(self, bot: commands.Bot):
|
||||
self.bot = bot
|
||||
print("GlobalCommandsCog initialized!")
|
||||
|
||||
# Register global commands
|
||||
self.register_global_commands()
|
||||
|
||||
def register_global_commands(self):
|
||||
"""Register global commands that work in DMs and private channels."""
|
||||
|
||||
# Create a help command that works in DMs and private channels
|
||||
create_global_command(
|
||||
self.bot.tree,
|
||||
name="dmhelp",
|
||||
description="Get help with bot commands (works in DMs)",
|
||||
callback=self.dm_help_callback,
|
||||
context=AppCommandContext.ALL
|
||||
)
|
||||
|
||||
# Create a ping command that works in DMs and private channels
|
||||
create_global_command(
|
||||
self.bot.tree,
|
||||
name="dmping",
|
||||
description="Check if the bot is responsive (works in DMs)",
|
||||
callback=self.dm_ping_callback,
|
||||
context=AppCommandContext.ALL
|
||||
)
|
||||
|
||||
# Create a command that only works in private contexts
|
||||
create_global_command(
|
||||
self.bot.tree,
|
||||
name="privateonly",
|
||||
description="This command only works in DMs and private channels",
|
||||
callback=self.private_only_callback,
|
||||
context=AppCommandContext.PRIVATE
|
||||
)
|
||||
|
||||
print("GlobalCommandsCog: Registered global commands")
|
||||
|
||||
async def dm_help_callback(self, interaction: discord.Interaction):
|
||||
"""Callback for the /dmhelp command."""
|
||||
is_dm = isinstance(interaction.channel, discord.DMChannel)
|
||||
is_private = not interaction.guild
|
||||
|
||||
help_text = (
|
||||
"# Bot Help\n\n"
|
||||
"This help command works in both DMs and servers!\n\n"
|
||||
f"**Current context:** {'DM' if is_dm else 'Private Channel' if is_private else 'Server'}\n\n"
|
||||
"## Available Commands\n"
|
||||
"- `/dmhelp` - This help command\n"
|
||||
"- `/dmping` - Check if the bot is responsive\n"
|
||||
"- `/privateonly` - Only works in DMs and private channels\n"
|
||||
)
|
||||
|
||||
await interaction.response.send_message(help_text, ephemeral=True)
|
||||
|
||||
async def dm_ping_callback(self, interaction: discord.Interaction):
|
||||
"""Callback for the /dmping command."""
|
||||
is_dm = isinstance(interaction.channel, discord.DMChannel)
|
||||
is_private = not interaction.guild
|
||||
|
||||
await interaction.response.send_message(
|
||||
f"🏓 Pong! Bot is responsive.\n"
|
||||
f"**Current context:** {'DM' if is_dm else 'Private Channel' if is_private else 'Server'}",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
async def private_only_callback(self, interaction: discord.Interaction):
|
||||
"""Callback for the /privateonly command."""
|
||||
is_dm = isinstance(interaction.channel, discord.DMChannel)
|
||||
|
||||
await interaction.response.send_message(
|
||||
f"This command only works in private contexts.\n"
|
||||
f"**Current context:** {'DM' if is_dm else 'Private Channel'}",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
async def setup(bot: commands.Bot):
|
||||
"""Add the GlobalCommandsCog to the bot."""
|
||||
await bot.add_cog(GlobalCommandsCog(bot))
|
||||
print("GlobalCommandsCog setup complete.")
|
39
gurt_bot.py
39
gurt_bot.py
@ -28,8 +28,43 @@ async def on_ready():
|
||||
# Sync commands
|
||||
try:
|
||||
print("Starting command sync process...")
|
||||
synced = await bot.tree.sync()
|
||||
print(f"Synced {len(synced)} command(s)")
|
||||
|
||||
# Import our command sync utilities
|
||||
try:
|
||||
import command_sync_utils
|
||||
from command_context import AppCommandContext
|
||||
|
||||
# Sync both global and guild-specific commands
|
||||
print("Syncing both global and guild-specific commands...")
|
||||
sync_results = await command_sync_utils.sync_global_and_guild_commands(bot)
|
||||
|
||||
# Report results
|
||||
global_syncs = sync_results["global"]
|
||||
guild_syncs = sync_results["guild"]
|
||||
|
||||
print(f"Synced {len(global_syncs)} global command(s)")
|
||||
if guild_syncs:
|
||||
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
|
||||
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
|
||||
|
||||
# Set context for specific commands to allow them in private channels and DMs
|
||||
private_commands = [
|
||||
# Add command names that should work in private contexts here
|
||||
"gurtmood", # Allow mood command in DMs
|
||||
]
|
||||
|
||||
# Create a dictionary mapping command names to contexts
|
||||
command_contexts = {name: AppCommandContext.ALL for name in private_commands}
|
||||
|
||||
# Apply the contexts to the commands
|
||||
command_sync_utils.set_command_contexts(bot, command_contexts)
|
||||
|
||||
except ImportError:
|
||||
# Fall back to regular sync if the utility modules aren't available
|
||||
print("Command sync utilities not available, falling back to regular sync...")
|
||||
synced = await bot.tree.sync()
|
||||
print(f"Synced {len(synced)} command(s)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to sync commands: {e}")
|
||||
import traceback
|
||||
|
39
main.py
39
main.py
@ -230,19 +230,46 @@ async def on_ready():
|
||||
commands_before = [cmd.name for cmd in bot.tree.get_commands()]
|
||||
print(f"Commands before sync: {commands_before}")
|
||||
|
||||
# Skip global command sync to avoid duplication
|
||||
print("Skipping global command sync to avoid command duplication...")
|
||||
# Import our new command sync utilities
|
||||
import command_sync_utils
|
||||
from command_context import AppCommandContext
|
||||
|
||||
# Only sync guild-specific commands with customizations
|
||||
print("Syncing guild-specific command customizations...")
|
||||
guild_syncs = await command_customization.register_all_guild_commands(bot)
|
||||
# Sync both global and guild-specific commands
|
||||
print("Syncing both global and guild-specific commands...")
|
||||
sync_results = await command_sync_utils.sync_global_and_guild_commands(bot)
|
||||
|
||||
# Report results
|
||||
global_syncs = sync_results["global"]
|
||||
guild_syncs = sync_results["guild"]
|
||||
|
||||
print(f"Synced {len(global_syncs)} global command(s)")
|
||||
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
|
||||
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
|
||||
|
||||
# List commands after sync
|
||||
commands_after = [cmd.name for cmd in bot.tree.get_commands()]
|
||||
print(f"Commands registered in command tree: {commands_after}")
|
||||
print(f"Commands registered in command tree: {', '.join(commands_after)}")
|
||||
|
||||
# Set context for specific commands to allow them in private channels and DMs
|
||||
private_commands = [
|
||||
# Add command names that should work in private contexts here
|
||||
"dmhelp",
|
||||
"dmping",
|
||||
"privateonly",
|
||||
]
|
||||
|
||||
# Load the example global commands cog
|
||||
try:
|
||||
await bot.load_extension("example_global_commands")
|
||||
print("Loaded example_global_commands cog")
|
||||
except Exception as e:
|
||||
print(f"Failed to load example_global_commands cog: {e}")
|
||||
|
||||
# Create a dictionary mapping command names to contexts
|
||||
command_contexts = {name: AppCommandContext.ALL for name in private_commands}
|
||||
|
||||
# Apply the contexts to the commands
|
||||
command_sync_utils.set_command_contexts(bot, command_contexts)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to sync commands: {e}")
|
||||
|
@ -28,8 +28,43 @@ async def on_ready():
|
||||
# Sync commands
|
||||
try:
|
||||
print("Starting command sync process...")
|
||||
synced = await bot.tree.sync()
|
||||
print(f"Synced {len(synced)} command(s)")
|
||||
|
||||
# Import our command sync utilities
|
||||
try:
|
||||
import command_sync_utils
|
||||
from command_context import AppCommandContext
|
||||
|
||||
# Sync both global and guild-specific commands
|
||||
print("Syncing both global and guild-specific commands...")
|
||||
sync_results = await command_sync_utils.sync_global_and_guild_commands(bot)
|
||||
|
||||
# Report results
|
||||
global_syncs = sync_results["global"]
|
||||
guild_syncs = sync_results["guild"]
|
||||
|
||||
print(f"Synced {len(global_syncs)} global command(s)")
|
||||
if guild_syncs:
|
||||
total_guild_syncs = sum(len(cmds) for cmds in guild_syncs.values())
|
||||
print(f"Synced commands for {len(guild_syncs)} guilds with a total of {total_guild_syncs} customized commands")
|
||||
|
||||
# Set context for specific commands to allow them in private channels and DMs
|
||||
private_commands = [
|
||||
# Add command names that should work in private contexts here
|
||||
"wheatleymemory", # Allow memory command in DMs
|
||||
]
|
||||
|
||||
# Create a dictionary mapping command names to contexts
|
||||
command_contexts = {name: AppCommandContext.ALL for name in private_commands}
|
||||
|
||||
# Apply the contexts to the commands
|
||||
command_sync_utils.set_command_contexts(bot, command_contexts)
|
||||
|
||||
except ImportError:
|
||||
# Fall back to regular sync if the utility modules aren't available
|
||||
print("Command sync utilities not available, falling back to regular sync...")
|
||||
synced = await bot.tree.sync()
|
||||
print(f"Synced {len(synced)} command(s)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to sync commands: {e}")
|
||||
import traceback
|
||||
|
Loading…
x
Reference in New Issue
Block a user