Skip to content

Instantly share code, notes, and snippets.

@mikield
Last active December 25, 2024 19:14
Show Gist options
  • Save mikield/fe2fda55c3df1010cf003752682e6a10 to your computer and use it in GitHub Desktop.
Save mikield/fe2fda55c3df1010cf003752682e6a10 to your computer and use it in GitHub Desktop.
Extend DiscordCommandClient with Pipelines
<?php
namespace App\Extentions;
use Discord\CommandClient\Command;
use Discord\Discord;
use Discord\DiscordCommandClient;
use Discord\Helpers\Collection;
use Discord\Helpers\RegisteredCommand;
use Discord\Parts\Embed\Embed;
use Discord\Parts\Interactions\Interaction;
use Illuminate\Contracts\Container\Container;
use Illuminate\Pipeline\Pipeline;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use function Discord\contains;
class RoutedDiscordCommandClient extends DiscordCommandClient
{
private array $middlewares;
private array $commandMiddlewares;
private ?Container $container;
private array $slashCommandsMiddlewares;
public function __construct(array $options = [], array $middlewares = [], array $commandMiddlewares = [], array $slashCommandsMiddlewares = [], Container $container = null)
{
$this->commandClientOptions = $this->resolveCommandClientOptions($options);
$this->middlewares = $middlewares;
$this->slashCommandsMiddlewares = $slashCommandsMiddlewares;
$this->commandMiddlewares = $commandMiddlewares;
$this->container = $container;
$discordOptions = array_merge($this->commandClientOptions['discordOptions'], [
'token' => $this->commandClientOptions['token'],
]);
Discord::__construct($discordOptions);
$this->on('init', function () {
$this->commandClientOptions['prefix'] = str_replace('@mention', (string)$this->user, $this->commandClientOptions['prefix']);
$this->commandClientOptions['name'] = str_replace('<UsernamePlaceholder>', $this->username, $this->commandClientOptions['name']);
foreach ($this->commandClientOptions['prefixes'] as $key => $prefix) {
if (contains($prefix, ['@mention'])) {
$this->commandClientOptions['prefixes'][] = str_replace('@mention', "<@{$this->user->id}>", $prefix);
$this->commandClientOptions['prefixes'][] = str_replace('@mention', "<@!{$this->user->id}>", $prefix);
unset($this->commandClientOptions['prefixes'][$key]);
}
}
$this->on('message', function ($message) {
if ($message->author->id == $this->id) {
return;
}
if ($withoutPrefix = $this->checkForPrefix($message->content)) {
$args = str_getcsv($withoutPrefix, ' ');
$command = array_shift($args);
if (null !== $command && $this->commandClientOptions['caseInsensitiveCommands']) {
$command = strtolower($command);
}
if (array_key_exists($command, $this->commands)) {
$command = $this->commands[$command];
} elseif (array_key_exists($command, $this->aliases)) {
$command = $this->commands[$this->aliases[$command]];
} else {
// Command doesn't exist.
return;
}
/** @var Command $command */
$result = (new Pipeline($this->container))
->send($message)
->through(array_merge(
$this->middlewares,
$this->commandMiddlewares[$command->command] ?? []
))
->via('handle')
->then(function ($message) use ($command, $args) {
return $command->handle($message, $args);
});
if (is_string($result)) {
$message
->reply($result)
->then(null, $this->commandClientOptions['internalRejectedPromiseHandler'])
->done();
}
}
});
});
if ($this->commandClientOptions['defaultHelpCommand']) {
$this->registerCommand('help', function ($message, $args) {
$prefix = str_replace((string)$this->user, '@' . $this->username, $this->commandClientOptions['prefix']);
$fullCommandString = implode(' ', $args);
if (count($args) > 0) {
$command = $this;
while (count($args) > 0) {
$commandString = array_shift($args);
$newCommand = $command->getCommand($commandString);
if (null === $newCommand) {
return "The command {$commandString} does not exist.";
}
$command = $newCommand;
}
$help = $command->getHelp($prefix);
if (empty($help)) {
return;
}
$embed = new Embed($this);
$embed->setAuthor($this->commandClientOptions['name'], $this->client->user->avatar)
->setTitle($prefix . $fullCommandString . '\'s Help')
->setDescription(!empty($help['longDescription']) ? $help['longDescription'] : $help['description'])
->setFooter($this->commandClientOptions['name']);
if (!empty($help['usage'])) {
$embed->addFieldValues('Usage', '``' . $help['usage'] . '``', true);
}
if (!empty($this->aliases)) {
$aliasesString = '';
foreach ($this->aliases as $alias => $command) {
if ($command != $commandString) {
continue;
}
$aliasesString .= "{$alias}\r\n";
}
if (!empty($aliasesString)) {
$embed->addFieldValues('Aliases', $aliasesString, true);
}
}
if (!empty($help['subCommandsHelp'])) {
foreach ($help['subCommandsHelp'] as $subCommandHelp) {
$embed->addFieldValues($subCommandHelp['command'], $subCommandHelp['description'], true);
}
}
$message->channel
->sendEmbed($embed)
->then(null, $this->commandClientOptions['internalRejectedPromiseHandler'])
->done();
return;
}
$embed = new Embed($this);
$embed->setAuthor($this->commandClientOptions['name'], $this->client->avatar)
->setTitle($this->commandClientOptions['name'])
->setType(Embed::TYPE_RICH)
->setFooter($this->commandClientOptions['name']);
$commandsDescription = '';
$embedfields = [];
foreach ($this->commands as $command) {
$help = $command->getHelp($prefix);
if (empty($help)) {
continue;
}
$embedfields[] = [
'name' => $help['command'],
'value' => $help['description'],
'inline' => true,
];
$commandsDescription .= "\n\n`" . $help['command'] . "`\n" . $help['description'];
foreach ($help['subCommandsHelp'] as $subCommandHelp) {
$embedfields[] = [
'name' => $subCommandHelp['command'],
'value' => $subCommandHelp['description'],
'inline' => true,
];
$commandsDescription .= "\n\n`" . $subCommandHelp['command'] . "`\n" . $subCommandHelp['description'];
}
}
// Use embed fields in case commands count is below limit
if (count($embedfields) <= 25) {
foreach ($embedfields as $field) {
$embed->addField($field);
}
$commandsDescription = '';
}
$embed->setDescription(substr($this->commandClientOptions['description'] . $commandsDescription, 0, 2048));
$message->channel
->sendEmbed($embed)
->then(null, $this->commandClientOptions['internalRejectedPromiseHandler'])
->done();
}, [
'description' => 'Provides a list of commands available.',
'usage' => '[command]',
]);
}
}
/**
* Add listener for incoming application command from interaction.
*
* @param string|array $name
* @param callable|null $callback
* @param callable|null $autocomplete_callback
*
* @return RegisteredCommand
* @throws \LogicException
*
*/
public function listenCommand($name, ?callable $callback = null, ?callable $autocomplete_callback = null): RegisteredCommand
{
$commandName = is_array($name) ? implode('.', $name) : $name;
return parent::listenCommand($name, function (Interaction $interaction, Collection $params) use ($callback, $name) {
return (new Pipeline($this->container))
->send(new SlashCommandPipelineContext($interaction, $params))
->through(array_merge(
$this->slashCommandsMiddlewares,
$this->commandMiddlewares[is_array($name) ? implode('.', $name) : $name] ?? []
))
->via('handle')
->then(function (SlashCommandPipelineContext $context) use ($callback) {
return $callback($context->interaction, $context->params);
});
}, $autocomplete_callback);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment