discord)) ->setType(Option::INTEGER) ->setName('sides') ->setDescription('sides on the die') ->setAutoComplete(true); // the command "roll" return CommandBuilder::new() ->setType(Command::CHAT_INPUT) ->setName(static::NAME) ->setDescription('rolls an n-sided die') ->addOption($sides) ->create($repository); } /** * Register a global slash command. * * @param string|null $reason Reason for registering the command. * @param bool $update Whether to update the command if it already exists. * * @return static */ public function register(GlobalCommandRepository|GuildCommandRepository $repository, ?string $reason = null, bool $update = false): static { // If the the command was created successfully you don't need to create it again if (! $update && $repository->get('name', static::NAME)) { return $this; } $this->buildCommand($repository)->save($reason); return $this; } /** * Attempt to delete the command. * * @param string|null $reason Reason for deleting the command. * * @return static */ public function delete(?string $reason = null): static { $repository = $this->discord->application->commands; $command = $repository->get('name', static::NAME); if ($command) { $repository->delete($command, $reason); } return $this; } /** * Add listener(s) for the command and possible subcommands. * * @return static */ public function listen(): static { $registeredCommand = $this->discord->listenCommand(DiceRollHandler::NAME, $this->execute(...), $this->autocomplete(...)); // you may register different handlers for each subcommand here # foreach(['subcommand1', 'subcommand2', /*...*/] as $subcommand){ # $registeredCommand->addSubCommand($subcommand, $this->execute(...), $this->autocomplete(...)); # } return $this; } /** * The command callback. * * @param ApplicationCommand $interaction The interaction object. */ public function execute(ApplicationCommand $interaction, Collection $params): void { $sides = ($interaction->data->options->get('name', 'sides')?->value ?? 20); // sanity check if (! in_array($sides, [4, 6, 8, 10, 12, 20], true)) { $sides = 20; } $message = sprintf('%s rolled %s with a %s-sided die', $interaction->user, random_int(1, $sides), $sides); // respond to the command with an interaction message $interaction->respondWithMessage((new MessageBuilder)->setContent($message)); } /** * The autocomplete callback. * * Must return array to trigger a response. * * @param ApplicationCommandAutocomplete $interaction The interaction object. * * @return array|null An array of Choice objects or null to not respond. */ public function autocomplete(ApplicationCommandAutocomplete $interaction): array|null { // respond if the desired option is focused /** @var ?RequestOption */ $option = $interaction->data->options->get('name', 'sides'); if ($option && $option->focused) { // the dataset, e.g. fetched from a database (25 results max) $dataset = [4, 6, 8, 10, 12, 20]; $choices = []; foreach ($dataset as $sides) { $choices[] = new Choice($this->discord, ['name' => sprintf('%s-sided', $sides), 'value' => $sides]); } return $choices; } return null; } } /** * Invoke the discord client * * MESSAGE_CONTENT, GUILD_MEMBERS and GUILD_PRESENCES are privileged * * @see https://dis.gd/mcfaq */ $dc = new Discord([ // https://discord.com/developers/applications/>/bot 'token' => 'YOUR_DISCORD_BOT_TOKEN', 'intents' => (Intents::getDefaultIntents() | Intents::MESSAGE_CONTENT), ]); /** * When the bot is ready * * IMPORTANT: Avoid calling freshen() multiple times to prevent rate limiting */ $dc->on('init', function (Discord $discord): void { echo "Bot is ready!\n"; // invoke the command handler $commandHandler = new DiceRollHandler($discord); // Can be GuildCommandRepository for guild-specific commands $repository = $discord->application->commands; // Freshen the repository prior to registering to avoid overwriting other commands //$repository->freshen()->then(fn ($repository) => $commandHandler->register(repository: $repository, reason: 'Initial command registration', update: false); //); // add a listener for the command $commandHandler->listen(); }); $dc->run();