Skip to content

Commit

Permalink
Update to nyxx 6.0.0 (#126)
Browse files Browse the repository at this point in the history
* Remove deprecated analyzer rule

* Use named parameters in GuildCheck connstructor

* Release 5.0.0

* Fix component timeout being negative, value lookups using unparsed components and display selected options in disabled multiselect builder

* Release 5.0.1

* Don't throw if plugin is disposed partway through command execution.

* Release 5.0.2

* Migrate to nyxx 6.0.0

* Clean up nyxx 6.0.0 code; update documentation

* Update example to nyxx 3.0.0

* Bump nyxx to 6.0.0-dev.3

* Release 6.0.0-dev.1

---------

Co-authored-by: Szymon Uglis <[email protected]>
  • Loading branch information
abitofevrything and l7ssha authored Sep 17, 2023
1 parent 7cd7305 commit f48814e
Show file tree
Hide file tree
Showing 48 changed files with 1,662 additions and 1,652 deletions.
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
## 6.0.0-dev.1
__Breaking changes__
- Update nyxx to version 6.0.0. See the changelog at https://pub.dev/packages/nyxx for more details.

## 5.0.2
__Bug fixes__
- Fix disposing the plugin partway through command execution causing errors.

## 5.0.1
__Bug fixes__
- Fix component timeouts triggering instantly.
- Fix component wrappers causing null assertions to trigger.

## 5.0.0
__Breaking changes__
- Removed all deprecated APIs.
- APIs which used to take `Type` objects now take `RuntimeType`s for the relevant type.
- APIs which used to take the `customId` of a component now take a `ComponentId`.
- Context types have been reorganized. See the docs for `IContextData`, `ICommandContext` and `IInteractiveContext` for more.
- Converter & check APIs now take `IContextData` objects instead of `IContext` objects.
- Checks now use named parameters instead of positional ones in their constructors.
- `IInteractiveContext.respond` (formerly `IContext.respond`) now takes a `ResponseLevel` object instead of `private` and `hidden`.
- The `interactions` field on `CommandsPlugin` is now nullable to avoid a `late` modifier. Use `IContextData.interactions` instead for a non nullable field.

__New features__
- Contexts are now managed by a `ContextManager` which allows users to create their own contexts.
- Added support for modal helpers. See `IInteractionInteractiveContext.getModal` for more.
- Added new errors: `ConverterFailedException`, `InteractionTimeoutException`, `UncaughtCommandsException` and `UnhandledInteractionException`.
- Events & listeners are now handled by an `EventManager` and `ComponentId`s.
- Prefix callbacks can now be asynchronous and return any `Pattern`.
- Added `autoAcknowledgeDuration` for more control over auto-acknowledge.
- Added parsing utilities on `AutocompleteContext` for parsing arguments.
- Contexts in a command are now chained, so interaction expiry and inconsistent formatting of responses to commands are no longer an issue. See `IInteractiveContext.delegate` for more.
- Added many helpers for handling message components:
- `awaitButtonPress`, `awaitSelection` and `awaitMultiSelection` for using fully custom components with nyxx_commands;
- `getButtonPress`, `getButtonSelection` and `getConfirmation` for handling buttons;
- `getSelection` and `getMultiSelection` for handling multiselect menus.
- Added `SimpleConverter` to simplify creating custom converters.
- The prefix callback can now be set to null to disable message commands. This will change the default command type to `slashOnly` unless `CommandsOptions.inferDefaultCommandType` is set to `false`.
- Added `skipPattern` to `StringView`, similar to `skipString`.

__Bug fixes__
- Fixed a bug that prevented `part` files from being compiled.
- Fixed a bug that prevented enum parameters from being compiled.
- Fixed nested command `fullName`s not being correct.

__Miscellaneous__
- Optimized the compilation script to generate less code and use a more reliable subtype checking method.
- Instructions for compilation can now be found at the package README.
- Bump `nyxx` to 5.0.0 and `nyxx_interactions` to 4.6.0.

## 5.0.0-dev.3
__Bug fixes__
- Fixed a bug which caused `IInteractiveContext.respond` to error after auto-acknowledge.
Expand Down
3 changes: 1 addition & 2 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ analyzer:
exclude: [build/**, "*.g.dart"]
language:
strict-raw-types: true
strong-mode:
implicit-casts: false
strict-casts: false
121 changes: 50 additions & 71 deletions example/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// - Set the environment variable `GUILD` to the ID of the Discord guild (server) you want the
// commands to be registered to

// nyxx is needed to create the client & use nyxx classes like IMessage or IGuild
// nyxx is needed to create the client & use nyxx classes like Message or Guild
import 'package:nyxx/nyxx.dart';
// nyxx_commands is needed to use the commands plugin
import 'package:nyxx_commands/nyxx_commands.dart';
Expand All @@ -20,40 +20,28 @@ import 'package:nyxx_commands/nyxx_commands.dart';
import 'dart:io';
import 'dart:math';

import 'package:nyxx_interactions/nyxx_interactions.dart';

void main() {
void main() async {
// ====================================== //
// ===== Initializing nyxx_commands ===== //
// ====================================== //

// Since v3.0.0, nyxx_commands can be used as a plugin with nyxx v3.0.0

// To use a plugin, we must first obtain an instance of INyxx:
// nyxx_commands doesn't yet support using INyxxRest, so we have to use INyxxWebsocket
INyxxWebsocket client = NyxxFactory.createNyxxWebsocket(
Platform.environment['TOKEN']!,
// nyxx_commands runs fine without the guild member intent, but it's useful to have it for
// IMember lookup
GatewayIntents.allUnprivileged | GatewayIntents.guildMembers,
);

// Next, we need to create our plugin. The plugin class used for nyxx_commands is `CommandsPlugin`
// and we need to store it in a variable to be able to access it for registering commands and
// converters.

CommandsPlugin commands = CommandsPlugin(
// The `prefix` parameter determines what prefix nyxx_commands will use for text commands.
//
// It isn't a simple string but a function that takes a single argument, an `IMessage`, and
// returns a `String` indicating what prefix to use for that message. This allows you to have
// different prefixes for different messages, for example you might want the bot to not require
// a prefix when in direct messages. In that case, you might provide a function like this:
// It isn't a simple string but a function that takes a single argument, a `MessageCreateEvent`,
// and returns a `String` indicating what prefix to use for that message. This allows you to
// have/ different prefixes for different messages, for example you might want the bot to not
// require a prefix when in direct messages. In that case, you might provide a function like
// this:
// ```dart
// prefix: (message) {
// if (message.startsWith('!')) {
// prefix: (event) {
// if (event.message.content.startsWith('!')) {
// return '!';
// } else if (message.guild == null) {
// } else if (event.guild == null) {
// return '';
// }
// }
Expand All @@ -64,12 +52,9 @@ void main() {

// The `guild` parameter determines what guild slash commands will be registered to by default.
//
// This is useful for testing since registering slash commands globally can take up to an hour,
// whereas registering commands for a single guild is instantaneous.
//
// If you aren't testing or want your commands to be registered globally, either omit this
// parameter or set it to `null`.
guild: Snowflake(Platform.environment['GUILD']!),
guild: Snowflake.parse(Platform.environment['GUILD']!),

// The `options` parameter allows you to specify additional configuration options for the
// plugin.
Expand All @@ -86,18 +71,13 @@ void main() {
),
);

// Next, we add the commands plugin to our client:
client.registerPlugin(commands);

// We also register a couple other plugins for convenience.
// These aren't needed for nyxx_commands to work.
client
..registerPlugin(Logging())
..registerPlugin(CliIntegration())
..registerPlugin(IgnoreExceptions());

// Finally, we tell the client to connect to Discord:
client.connect();
// Now we have our `CommandsPlugin`, we can connect to Discord, making sure to pass our `commands`
// instance to the client's options.
await Nyxx.connectGateway(
Platform.environment['TOKEN']!,
GatewayIntents.allUnprivileged | GatewayIntents.guildMembers,
options: GatewayClientOptions(plugins: [commands, logging, cliIntegration, ignoreExceptions]),
);

// ====================================== //
// ======= Registering a command ======== //
Expand Down Expand Up @@ -126,18 +106,18 @@ void main() {
// as an executable. If you just want to run nyxx_commands with `dart run`, this is optional and
// you can just pass a normal function to the constructor.
//
// The first parameter to this function must be a `IChatContext`. A `IChatContext` allows you to access
// The first parameter to this function must be a `ChatContext`. A `ChatContext` allows you to access
// various information about how the command was run: the user that executed it, the guild it
// was ran in and a few other useful pieces of information.
// `IChatContext` also has a couple of methods that make it easier to respond to commands.
//
// Since a ping command doesn't have any other arguments, we don't add any other parameters to
// the function.
id('ping', (IChatContext context) {
id('ping', (ChatContext context) {
// For a ping command, all we need to do is respond with `pong`.
// To do that, we can use the `IChatContext`'s `respond` method which responds to the command with
// a message.
context.respond(MessageBuilder.content('pong!'));
context.respond(MessageBuilder(content: 'pong!'));
}),
);

Expand Down Expand Up @@ -187,11 +167,11 @@ void main() {
ChatCommand(
'coin',
'Throw a coin',
id('throw-coin', (IChatContext context) {
id('throw-coin', (ChatContext context) {
bool heads = Random().nextBool();

context.respond(
MessageBuilder.content('The coin landed on its ${heads ? 'head' : 'tail'}!'));
MessageBuilder(content: 'The coin landed on its ${heads ? 'head' : 'tail'}!'));
}),
),
],
Expand All @@ -202,10 +182,10 @@ void main() {
throwGroup.addCommand(ChatCommand(
'die',
'Throw a die',
id('throw-die', (IChatContext context) {
id('throw-die', (ChatContext context) {
int number = Random().nextInt(6) + 1;

context.respond(MessageBuilder.content('The die landed on the $number!'));
context.respond(MessageBuilder(content: 'The die landed on the $number!'));
}),
));

Expand Down Expand Up @@ -240,8 +220,8 @@ void main() {
// As mentioned earlier, all we need to do to add an argument to our command is add it as a
// parameter to our execute function. In this case, we take an argument called `message` and of
// type `String`.
id('say', (IChatContext context, String message) {
context.respond(MessageBuilder.content(message));
id('say', (ChatContext context, String message) {
context.respond(MessageBuilder(content: message));
}),
);

Expand Down Expand Up @@ -285,7 +265,7 @@ void main() {
// class is used.
//
// nyxx_commands registers a few converters by default for commonly used types such as `int`s,
// `double`s, `IMember`s and others. We'll look into creating custom converters later, and for now
// `double`s, `Member`s and others. We'll look into creating custom converters later, and for now
// just use the built-in converters.

// Using converters is just as simple as using arguments: simply specify the argument name and
Expand All @@ -296,17 +276,17 @@ void main() {
ChatCommand nick = ChatCommand(
'nick',
"Change a user's nickname",
// Setting the type of the `target` parameter to `IMember` will make nyxx_commands convert user
// input to instances of `IMember`.
id('nick', (IChatContext context, IMember target, String newNick) async {
// Setting the type of the `target` parameter to `Member` will make nyxx_commands convert user
// input to instances of `Member`.
id('nick', (ChatContext context, Member target, String newNick) async {
try {
await target.edit(builder: MemberBuilder()..nick = newNick);
} on IHttpResponseError {
context.respond(MessageBuilder.content("Couldn't change nickname :/"));
await target.update(MemberUpdateBuilder(nick: newNick));
} on HttpResponseError {
context.respond(MessageBuilder(content: "Couldn't change nickname :/"));
return;
}

context.respond(MessageBuilder.content('Successfully changed nickname!'));
context.respond(MessageBuilder(content: 'Successfully changed nickname!'));
}),
);

Expand Down Expand Up @@ -336,7 +316,7 @@ void main() {
// You can also run the command from a text message, with `!nick *target* *new-nick*`. Unlike
// slash commands, there is no way to filter user input before it gets to our bot, so we might end
// up with an invalid input.
// If that is the case, the converter for `IMember` will be unable to convert the user input to a
// If that is the case, the converter for `Member` will be unable to convert the user input to a
// valid member, and the command will fail with an exception.
//
// Note that the bot must have the MANAGE_MEMBERS permission and have a higher role than the
Expand Down Expand Up @@ -373,7 +353,7 @@ void main() {
// The first parameter to the function is an instance of `StringView`. `StringView` allows you
// to manipulate and extract data from a `String`, but also allows the next converter to know
// where to start parsing its argument from.
// The second parameter is the current `IChatContext` in which the argument is being parsed.
// The second parameter is the current `ChatContext` in which the argument is being parsed.
(view, context) {
// In our case, we want to return a `Shape` based on the user's input. The `getQuotedWord()`
// will get the next quoted word from the input.
Expand All @@ -397,9 +377,9 @@ void main() {
// nyxx_interaction's `ArgChoiceBuilder`, allowing you to specify the choices that will be shown
// to the user when running this command from a slash command.
choices: [
ArgChoiceBuilder('Triangle', 'triangle'),
ArgChoiceBuilder('Square', 'square'),
ArgChoiceBuilder('Pentagon', 'pentagon'),
CommandOptionChoiceBuilder(name: 'Triangle', value: 'triangle'),
CommandOptionChoiceBuilder(name: 'Square', value: 'square'),
CommandOptionChoiceBuilder(name: 'Pentagon', value: 'pentagon'),
],
);

Expand Down Expand Up @@ -440,7 +420,7 @@ void main() {
ChatCommand favoriteShape = ChatCommand(
'favorite-shape',
'Outputs your favorite shape',
id('favorite-shape', (IChatContext context, Shape shape, Dimension dimension) {
id('favorite-shape', (ChatContext context, Shape shape, Dimension dimension) {
String favorite;

switch (shape) {
Expand All @@ -466,7 +446,7 @@ void main() {
}
}

context.respond(MessageBuilder.content('Your favorite shape is $favorite!'));
context.respond(MessageBuilder(content: 'Your favorite shape is $favorite!'));
}),
);

Expand Down Expand Up @@ -502,15 +482,14 @@ void main() {
// ```dart
// (IChatContext context, [String? a, String? b, String? c]) {}
// ```
// In this case, `b` having a value does not guarantee `a` has a value. As such, it is always
// better to provide a default for your optional parameters instead of making them nullable.
// In this case, `b` having a value does not guarantee `a` has a value.

// As an example for using optional arguments, let's create a command with an optional argument:
ChatCommand favoriteFruit = ChatCommand(
'favorite-fruit',
'Outputs your favorite fruit',
id('favorite-fruit', (IChatContext context, [String favorite = 'apple']) {
context.respond(MessageBuilder.content('Your favorite fruit is $favorite!'));
id('favorite-fruit', (ChatContext context, [String favorite = 'apple']) {
context.respond(MessageBuilder(content: 'Your favorite fruit is $favorite!'));
}),
);

Expand Down Expand Up @@ -540,8 +519,8 @@ void main() {
ChatCommand alphabet = ChatCommand(
'alphabet',
'Outputs the alphabet',
id('alphabet', (IChatContext context) {
context.respond(MessageBuilder.content('ABCDEFGHIJKLMNOPQRSTUVWXYZ'));
id('alphabet', (ChatContext context) {
context.respond(MessageBuilder(content: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'));
}),
// Since this command is spammy, we can use a cooldown to restrict its usage:
checks: [
Expand Down Expand Up @@ -583,10 +562,10 @@ void main() {
'better-say',
'A better version of the say command',
id('better-say', (
IChatContext context,
ChatContext context,
@UseConverter(nonEmptyStringConverter) String input,
) {
context.respond(MessageBuilder.content(input));
context.respond(MessageBuilder(content: input));
}),
);

Expand Down Expand Up @@ -616,7 +595,7 @@ enum Dimension {
// ---------- Global functions ---------- //
// -------------------------------------- //

String? filterInput(String input, IContextData context) {
String? filterInput(String input, ContextData context) {
if (input.isNotEmpty) {
return input;
}
Expand Down
Loading

0 comments on commit f48814e

Please sign in to comment.