From 0c1e3c0abf18abf287873ed4aa81217bb2d53078 Mon Sep 17 00:00:00 2001 From: Abitofevrything <54505189+abitofevrything@users.noreply.github.com> Date: Mon, 27 Dec 2021 17:35:26 +0100 Subject: [PATCH 1/8] Feature/specific shards (#266) * Update .gitignore * Implement specific sharding * Refactor propagateReady() method * Throw exception when invalid guild shard is accessed * Move logic to private method * Rename shards -> shardIds --- .gitignore | 1 + lib/src/client_options.dart | 6 ++- lib/src/core/guild/guild.dart | 6 ++- lib/src/internal/connection_manager.dart | 7 ++-- lib/src/internal/shard/shard.dart | 2 +- lib/src/internal/shard/shard_manager.dart | 47 +++++++++++++++++++---- 6 files changed, 54 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index b0ac6f9c0..04ab2398c 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ test-*.dart **/coverage/** coverage.json lcov.info +.vscode/ diff --git a/lib/src/client_options.dart b/lib/src/client_options.dart index a73f82088..7cad12336 100644 --- a/lib/src/client_options.dart +++ b/lib/src/client_options.dart @@ -41,6 +41,9 @@ class ClientOptions { /// The total number of shards. int? shardCount; + /// A list of shards to spawn on this instance of nyxx. + List? shardIds; + /// The number of messages to cache for each channel. int messageCacheSize; @@ -81,7 +84,8 @@ class ClientOptions { this.initialPresence, this.shutdownHook, this.shutdownShardHook, - this.dispatchRawShardEvent = false}); + this.dispatchRawShardEvent = false, + this.shardIds}); } /// When identifying to the gateway, you can specify an intents parameter which diff --git a/lib/src/core/guild/guild.dart b/lib/src/core/guild/guild.dart index c14dda666..0b820bfa8 100644 --- a/lib/src/core/guild/guild.dart +++ b/lib/src/core/guild/guild.dart @@ -1,4 +1,5 @@ import 'package:nyxx/src/core/guild/scheduled_event.dart'; +import 'package:nyxx/src/internal/exceptions/invalid_shard_exception.dart'; import 'package:nyxx/src/nyxx.dart'; import 'package:nyxx/src/core/channel/invite.dart'; import 'package:nyxx/src/core/snowflake.dart'; @@ -468,7 +469,10 @@ class Guild extends SnowflakeEntity implements IGuild { throw UnsupportedError("Cannot use this property with NyxxRest"); } - return (client as NyxxWebsocket).shardManager.shards.firstWhere((_shard) => _shard.guilds.contains(id)); + return (client as NyxxWebsocket).shardManager.shards.firstWhere( + (_shard) => _shard.guilds.contains(id), + orElse: throw InvalidShardException('Cannot find shard for this guild!'), + ); } /// Creates an instance of [Guild] diff --git a/lib/src/internal/connection_manager.dart b/lib/src/internal/connection_manager.dart index b09c0dab1..2dadd936f 100644 --- a/lib/src/internal/connection_manager.dart +++ b/lib/src/internal/connection_manager.dart @@ -63,13 +63,12 @@ class ConnectionManager { Future propagateReady() async { _shardsReady++; - if (client.ready || _shardsReady < (client.options.shardCount ?? 1)) { + if (client.ready || _shardsReady < client.shardManager.numShards) { return; } - if (!client.ready) { - (client.eventsWs as WebsocketEventController).onReadyController.add(ReadyEvent(client)); - } + (client.eventsWs as WebsocketEventController).onReadyController.add(ReadyEvent(client)); + client.ready = true; _logger.info("Connected and ready! Logged as `${client.self.tag}`"); } diff --git a/lib/src/internal/shard/shard.dart b/lib/src/internal/shard/shard.dart index a3a9069e0..715011176 100644 --- a/lib/src/internal/shard/shard.dart +++ b/lib/src/internal/shard/shard.dart @@ -322,7 +322,7 @@ class Shard implements IShard { "guild_subscriptions": manager.connectionManager.client.options.guildSubscriptions, "intents": manager.connectionManager.client.intents, if (manager.connectionManager.client.options.initialPresence != null) "presence": manager.connectionManager.client.options.initialPresence!.build(), - "shard": [id, manager.numShards] + "shard": [id, manager.totalNumShards] }; send(OPCodes.identify, identifyMsg); diff --git a/lib/src/internal/shard/shard_manager.dart b/lib/src/internal/shard/shard_manager.dart index f8766251a..2d070d214 100644 --- a/lib/src/internal/shard/shard_manager.dart +++ b/lib/src/internal/shard/shard_manager.dart @@ -47,6 +47,9 @@ abstract class IShardManager implements Disposable { /// Number of shards spawned int get numShards; + /// Total number of shards for this client + int get totalNumShards; + /// Sets presences on every shard void setPresence(PresenceBuilder presenceBuilder); } @@ -109,6 +112,10 @@ class ShardManager implements IShardManager { @override late final int numShards; + /// Total number of shards for this client + @override + late final int totalNumShards; + final Map _shards = {}; Duration get _identifyDelay { @@ -119,14 +126,36 @@ class ShardManager implements IShardManager { /// Starts shard manager ShardManager(this.connectionManager, this.maxConcurrency) { - numShards = connectionManager.client.options.shardCount != null ? connectionManager.client.options.shardCount! : connectionManager.recommendedShardsNum; + totalNumShards = connectionManager.client.options.shardCount ?? connectionManager.recommendedShardsNum; + numShards = connectionManager.client.options.shardIds?.length ?? totalNumShards; - if (numShards < 1) { + if (totalNumShards < 1) { throw UnrecoverableNyxxError("Number of shards cannot be lower than 1."); } + List toSpawn = _getShardsToSpawn(); + logger.fine("Starting shard manager. Number of shards to spawn: $numShards"); - _connect(numShards - 1); + _connect(toSpawn); + } + + List _getShardsToSpawn() { + if (connectionManager.client.options.shardIds != null) { + if (connectionManager.client.options.shardCount == null) { + throw UnrecoverableNyxxError('Cannot specify shards to spawn without specifying total number of shards'); + } + + for (final id in connectionManager.client.options.shardIds!) { + if (id < 0 || id >= totalNumShards) { + throw UnrecoverableNyxxError('Invalid shard ID: $id'); + } + } + + // Clone list to prevent original list from being modified with removeLast() + return List.of(connectionManager.client.options.shardIds!); + } else { + return List.generate(totalNumShards, (id) => id); + } } /// Sets presences on every shard @@ -137,16 +166,18 @@ class ShardManager implements IShardManager { } } - void _connect(int shardId) { - logger.fine("Setting up shard with id: $shardId"); - - if (shardId < 0) { + void _connect(List toSpawn) { + if (toSpawn.isEmpty) { return; } + int shardId = toSpawn.removeLast(); + + logger.fine("Setting up shard with id: $shardId"); + _shards[shardId] = Shard(shardId, this, connectionManager.gateway); - Future.delayed(_identifyDelay, () => _connect(shardId - 1)); + Future.delayed(_identifyDelay, () => _connect(toSpawn)); } @override From efe9f8ba8dc72cb673be2d6ed249e20587fa6671 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Mon, 27 Dec 2021 22:56:38 +0100 Subject: [PATCH 2/8] feature/boost-progress-bar - implementation (#268) --- lib/src/core/guild/guild.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/src/core/guild/guild.dart b/lib/src/core/guild/guild.dart index 0b820bfa8..00bfe9181 100644 --- a/lib/src/core/guild/guild.dart +++ b/lib/src/core/guild/guild.dart @@ -148,6 +148,9 @@ abstract class IGuild implements SnowflakeEntity { /// Returns this guilds shard IShard get shard; + /// Whether the guild has the boost progress bar enabled + bool get boostProgressBarEnabled; + /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. String? iconURL({String format = "webp", int size = 128}); @@ -428,6 +431,9 @@ class Guild extends SnowflakeEntity implements IGuild { @override late final Iterable stickers; + @override + late final bool boostProgressBarEnabled; + /// Returns url to this guild. @override String get url => "https://discordapp.com/channels/${id.toString()}"; @@ -493,6 +499,7 @@ class Guild extends SnowflakeEntity implements IGuild { premiumTier = PremiumTier.from(raw["premium_tier"] as int); premiumSubscriptionCount = raw["premium_subscription_count"] as int?; preferredLocale = raw["preferred_locale"] as String; + boostProgressBarEnabled = raw['premium_progress_bar_enabled'] as bool; owner = UserCacheable(client, Snowflake(raw["owner_id"])); From 4ad3735aa485a850dc0d113306f39a2d527d2453 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Mon, 27 Dec 2021 22:57:08 +0100 Subject: [PATCH 3/8] [feature] timeouts - implementation (#267) * feature/timeouts - implementation * feature/timeouts - analyzer and formatter fixes * feature/timeouts - deprecate old edit member parameters --- lib/nyxx.dart | 1 + lib/src/core/user/member.dart | 25 ++++++++++++-- lib/src/internal/http_endpoints.dart | 34 +++++++++++++------- lib/src/plugin/plugins/ignore_exception.dart | 1 - lib/src/utils/builders/member_builder.dart | 31 ++++++++++++++++++ test/unit/builders_test.dart | 32 ++++++++++++++++++ 6 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 lib/src/utils/builders/member_builder.dart diff --git a/lib/nyxx.dart b/lib/nyxx.dart index dfab87bec..b9275bdf4 100644 --- a/lib/nyxx.dart +++ b/lib/nyxx.dart @@ -156,6 +156,7 @@ export 'src/utils/builders/embed_footer_builder.dart' show EmbedFooterBuilder; export 'src/utils/builders/guild_builder.dart' show GuildBuilder, RoleBuilder; export 'src/utils/builders/channel_builder.dart'; export 'src/utils/builders/message_builder.dart' show MessageBuilder, MessageDecoration; +export 'src/utils/builders/member_builder.dart' show MemberBuilder; export 'src/utils/builders/permissions_builder.dart' show PermissionOverrideBuilder, PermissionsBuilder; export 'src/utils/builders/presence_builder.dart' show PresenceBuilder, ActivityBuilder; export 'src/utils/builders/reply_builder.dart' show ReplyBuilder; diff --git a/lib/src/core/user/member.dart b/lib/src/core/user/member.dart index 7c2a2e0bd..308d004b6 100644 --- a/lib/src/core/user/member.dart +++ b/lib/src/core/user/member.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:nyxx/nyxx.dart'; import 'package:nyxx/src/nyxx.dart'; import 'package:nyxx/src/core/snowflake.dart'; import 'package:nyxx/src/core/snowflake_entity.dart'; @@ -58,6 +59,12 @@ abstract class IMember implements SnowflakeEntity, Mentionable { /// Returns total permissions of user. Future get effectivePermissions; + /// When the user's timeout will expire and the user will be able to communicate in the guild again, null or a time in the past if the user is not timed out + DateTime? get timeoutUntil; + + /// True if user is timed out + bool get isTimedOut; + /// Returns url to member avatar String? avatarURL({String format = "webp"}); @@ -136,6 +143,12 @@ class Member extends SnowflakeEntity implements IMember { @override String get mention => "<@$id>"; + @override + bool get isTimedOut => timeoutUntil != null && timeoutUntil!.isAfter(DateTime.now()); + + @override + late final DateTime? timeoutUntil; + /// Returns total permissions of user. @override Future get effectivePermissions async { @@ -168,6 +181,7 @@ class Member extends SnowflakeEntity implements IMember { guild = GuildCacheable(client, guildId); boostingSince = DateTime.tryParse(raw["premium_since"] as String? ?? ""); avatarHash = raw["avatar"] as String?; + timeoutUntil = raw['communication_disabled_until'] != null ? DateTime.parse(raw['communication_disabled_until'] as String) : null; roles = [for (var id in raw["roles"]) RoleCacheable(client, Snowflake(id), guild)]; @@ -224,8 +238,15 @@ class Member extends SnowflakeEntity implements IMember { /// Edits members. Allows to move user in voice channel, mute or deaf, change nick, roles. @override Future edit( - {String? nick = "", List? roles, bool? mute, bool? deaf, Snowflake? channel = const Snowflake.zero(), String? auditReason}) => - client.httpEndpoints.editGuildMember(guild.id, id, nick: nick, roles: roles, mute: mute, deaf: deaf, channel: channel, auditReason: auditReason); + {@Deprecated('Use "builder" parameter') String? nick = "", + @Deprecated('Use "builder" parameter') List? roles, + @Deprecated('Use "builder" parameter') bool? mute, + @Deprecated('Use "builder" parameter') bool? deaf, + @Deprecated('Use "builder" parameter') Snowflake? channel = const Snowflake.zero(), + MemberBuilder? builder, + String? auditReason}) => + client.httpEndpoints + .editGuildMember(guild.id, id, nick: nick, roles: roles, mute: mute, deaf: deaf, channel: channel, builder: builder, auditReason: auditReason); void updateMember(String? nickname, List roles, DateTime? boostingSince) { if (this.nickname != nickname) { diff --git a/lib/src/internal/http_endpoints.dart b/lib/src/internal/http_endpoints.dart index fbbaabcb3..66ffa5266 100644 --- a/lib/src/internal/http_endpoints.dart +++ b/lib/src/internal/http_endpoints.dart @@ -1,3 +1,4 @@ +import 'package:nyxx/nyxx.dart'; import 'package:nyxx/src/core/guild/scheduled_event.dart'; import 'package:nyxx/src/nyxx.dart'; import 'package:nyxx/src/core/channel/invite.dart'; @@ -174,7 +175,13 @@ abstract class IHttpEndpoints { /// "Edits" guild member. Allows to manipulate other guild users. Future editGuildMember(Snowflake guildId, Snowflake memberId, - {String? nick, List? roles, bool? mute, bool? deaf, Snowflake? channel = const Snowflake.zero(), String? auditReason}); + {@Deprecated('Use "builder" parameter') String? nick, + @Deprecated('Use "builder" parameter') List? roles, + @Deprecated('Use "builder" parameter') bool? mute, + @Deprecated('Use "builder" parameter') bool? deaf, + @Deprecated('Use "builder" parameter') Snowflake? channel = const Snowflake.zero(), + MemberBuilder? builder, + String? auditReason}); /// Removes role from user Future removeRoleFromUser(Snowflake guildId, Snowflake roleId, Snowflake userId, {String? auditReason}); @@ -844,16 +851,21 @@ class HttpEndpoints implements IHttpEndpoints { @override Future editGuildMember(Snowflake guildId, Snowflake memberId, - {String? nick = "", List? roles, bool? mute, bool? deaf, Snowflake? channel = const Snowflake.zero(), String? auditReason}) { - final body = { - if (nick != "") "nick": nick, - if (roles != null) "roles": roles.map((f) => f.id.toString()).toList(), - if (mute != null) "mute": mute, - if (deaf != null) "deaf": deaf, - if (channel == null || !channel.isZero) "channel_id": channel.toString() - }; - - return executeSafe(BasicRequest("/guilds/$guildId/members/$memberId", method: "PATCH", auditLog: auditReason, body: body)); + {String? nick = "", + List? roles, + bool? mute, + bool? deaf, + Snowflake? channel = const Snowflake.zero(), + MemberBuilder? builder, + String? auditReason}) { + final finalBuilder = builder ?? MemberBuilder() + ..nick = nick + ..roles = roles?.map((e) => e.id).toList() + ..mute = mute + ..deaf = deaf + ..channel = channel; + + return executeSafe(BasicRequest("/guilds/$guildId/members/$memberId", method: "PATCH", auditLog: auditReason, body: finalBuilder)); } @override diff --git a/lib/src/plugin/plugins/ignore_exception.dart b/lib/src/plugin/plugins/ignore_exception.dart index 62a77c721..f060da24c 100644 --- a/lib/src/plugin/plugins/ignore_exception.dart +++ b/lib/src/plugin/plugins/ignore_exception.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'dart:isolate'; import 'package:logging/logging.dart'; diff --git a/lib/src/utils/builders/member_builder.dart b/lib/src/utils/builders/member_builder.dart new file mode 100644 index 000000000..b7a9c7bf2 --- /dev/null +++ b/lib/src/utils/builders/member_builder.dart @@ -0,0 +1,31 @@ +import 'package:nyxx/nyxx.dart'; + +class MemberBuilder implements Builder { + /// Value to set user's nickname to + String? nick; + + /// Array of role ids the member is assigned + List? roles; + + /// Whether the user is muted in voice channels. + bool? mute; + + /// Whether the user is deafened in voice channels. + bool? deaf; + + /// Id of channel to move user to (if they are connected to voice) + Snowflake? channel = Snowflake.zero(); + + /// When the user's timeout will expire and the user will be able to communicate in the guild again (up to 28 days in the future), set to null to remove timeout + DateTime? timeoutUntil = DateTime.fromMillisecondsSinceEpoch(0); + + @override + RawApiMap build() => { + if (nick != null) 'nick': nick, + if (roles != null) 'roles': roles!.map((e) => e.toString()).toList(), + if (mute != null) 'mute': mute, + if (deaf != null) 'deaf': deaf, + if (channel != Snowflake.zero()) 'channel_id': channel, + if (timeoutUntil?.millisecondsSinceEpoch != 0) 'communication_disabled_until': timeoutUntil?.toIso8601String(), + }; +} diff --git a/test/unit/builders_test.dart b/test/unit/builders_test.dart index dc8dbd985..a0e71ea92 100644 --- a/test/unit/builders_test.dart +++ b/test/unit/builders_test.dart @@ -102,6 +102,38 @@ main() { expect(ofBuilder.calculatePermissionValue(), equals(1 << 11)); }); + group('MemberBuilder', () { + test('channel empty', () { + final builder = MemberBuilder() + ..channel = Snowflake.zero(); + + expect({}, builder.build()); + }); + + test('channel with value', () { + final builder = MemberBuilder() + ..channel = Snowflake(123); + + expect({'channel_id': '123'}, builder.build()); + }); + + test('timeout empty', () { + final now = DateTime.now(); + + final builder = MemberBuilder() + ..timeoutUntil = now; + + expect({'communication_disabled_until': now.toIso8601String()}, builder.build()); + }); + + test('roles serialization', () { + final builder = MemberBuilder() + ..roles = [Snowflake(1), Snowflake(2)]; + + expect({'roles': ['1', '2']}, builder.build()); + }); + }); + group('MessageBuilder', () { test('clear character', () { final builder = MessageBuilder.empty(); From ed5b41c8454fe0d936cbac3e96a872950a5fff29 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Tue, 28 Dec 2021 20:06:57 +0100 Subject: [PATCH 4/8] Release 3.1.0 --- CHANGELOG.md | 9 +++++++++ lib/src/internal/constants.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 016acf7bd..f0feaae8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 3.1.0 +__28.12.2021__ + +- Implement patches needed for external sharding feature (#266) +- Implement boost progress bar (#266) +- Implement timeouts (#267) + - deprecation of edit method parameters in favor of `MemberBuilder` class. In next major release all parameters except `builder` + and `auditReason` will be removed + ## 3.0.1 __21.12.2021__ diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index e451b7b4c..471c81a6d 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -33,7 +33,7 @@ class Constants { static const int apiVersion = 9; /// Version of Nyxx - static const String version = "3.0.1"; + static const String version = "3.1.0"; /// Url to Nyxx repo static const String repoUrl = "https://github.com/nyxx-discord/nyxx"; diff --git a/pubspec.yaml b/pubspec.yaml index 5e6d56768..01e2810a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: nyxx -version: 3.0.1 +version: 3.1.0 description: A Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. homepage: https://github.com/nyxx-discord/nyxx repository: https://github.com/nyxx-discord/nyxx From 4bcd1e00a868bef3e21168e3d8153d1cb3760d05 Mon Sep 17 00:00:00 2001 From: Abitofevrything <54505189+abitofevrything@users.noreply.github.com> Date: Tue, 28 Dec 2021 20:11:37 +0100 Subject: [PATCH 5/8] Correctly initialise onDmReceived and onSelfMention (#270) --- lib/src/internal/event_controller.dart | 10 +++++++--- lib/src/nyxx.dart | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/src/internal/event_controller.dart b/lib/src/internal/event_controller.dart index b0d56c434..638ee02ac 100644 --- a/lib/src/internal/event_controller.dart +++ b/lib/src/internal/event_controller.dart @@ -17,6 +17,7 @@ import 'package:nyxx/src/events/user_update_event.dart'; import 'package:nyxx/src/events/voice_server_update_event.dart'; import 'package:nyxx/src/events/voice_state_update_event.dart'; import 'package:nyxx/src/internal/interfaces/disposable.dart'; +import 'package:nyxx/src/nyxx.dart'; abstract class IRestEventController implements Disposable { /// Emitted when a successful HTTP response is received. @@ -357,7 +358,7 @@ class WebsocketEventController extends RestEventController implements IWebsocket /// Emitted when private message is received. @override - late final Stream onDmReceived; + late final Stream onDmReceived = onMessageReceived.where((event) => event.message.guild == null); /// Emitted when channel"s pins are updated. @override @@ -470,7 +471,8 @@ class WebsocketEventController extends RestEventController implements IWebsocket /// Emitted when bot is mentioned @override - late final Stream onSelfMention; + late final Stream onSelfMention = + onMessageReceived.where((event) => event.message.mentions.map((e) => e.id).contains(_client.self.id)); /// Emitted when invite is created @override @@ -524,8 +526,10 @@ class WebsocketEventController extends RestEventController implements IWebsocket @override late final Stream onGuildEventUpdate; + final INyxxWebsocket _client; + /// Makes a new `EventController`. - WebsocketEventController() : super() { + WebsocketEventController(this._client) : super() { onDisconnectController = StreamController.broadcast(); onDisconnect = onDisconnectController.stream; diff --git a/lib/src/nyxx.dart b/lib/src/nyxx.dart index 530969fec..940bf38e2 100644 --- a/lib/src/nyxx.dart +++ b/lib/src/nyxx.dart @@ -340,7 +340,7 @@ class NyxxWebsocket extends NyxxRest implements INyxxWebsocket { ignoreExceptions: ignoreExceptions, useDefaultLogger: useDefaultLogger, ) { - eventsWs = WebsocketEventController(); + eventsWs = WebsocketEventController(this); } @override From 5668ff4af8c80ad9b41c6ef63c67bfbed36ddaf7 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Tue, 28 Dec 2021 20:12:34 +0100 Subject: [PATCH 6/8] Update 3.1.0 changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0feaae8a..aecf0b2cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ __28.12.2021__ - Implement timeouts (#267) - deprecation of edit method parameters in favor of `MemberBuilder` class. In next major release all parameters except `builder` and `auditReason` will be removed +- Fix incorrectly initialised onDmReceived and onSelfMention streams (#270) ## 3.0.1 __21.12.2021__ From 601c64d979f3da3150052b2a535d20df5d84a920 Mon Sep 17 00:00:00 2001 From: Abitofevrything <54505189+abitofevrything@users.noreply.github.com> Date: Wed, 29 Dec 2021 12:18:08 +0100 Subject: [PATCH 7/8] Expose builder parameter in IMember (#272) --- lib/src/core/user/member.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/src/core/user/member.dart b/lib/src/core/user/member.dart index 308d004b6..e3c217d80 100644 --- a/lib/src/core/user/member.dart +++ b/lib/src/core/user/member.dart @@ -87,7 +87,13 @@ abstract class IMember implements SnowflakeEntity, Mentionable { /// Edits members. Allows to move user in voice channel, mute or deaf, change nick, roles. Future edit( - {String? nick = "", List? roles, bool? mute, bool? deaf, Snowflake? channel = const Snowflake.zero(), String? auditReason}); + {@Deprecated('Use "builder" parameter') String? nick = "", + @Deprecated('Use "builder" parameter') List? roles, + @Deprecated('Use "builder" parameter') bool? mute, + @Deprecated('Use "builder" parameter') bool? deaf, + @Deprecated('Use "builder" parameter') Snowflake? channel = const Snowflake.zero(), + MemberBuilder? builder, + String? auditReason}); } class Member extends SnowflakeEntity implements IMember { From d72336e8b8ec11f857d4eede3168d8d8d277e376 Mon Sep 17 00:00:00 2001 From: Abitofevrything <54505189+abitofevrything@users.noreply.github.com> Date: Wed, 29 Dec 2021 11:20:13 +0000 Subject: [PATCH 8/8] Hotfix 3.1.1 --- CHANGELOG.md | 5 +++++ lib/src/internal/constants.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aecf0b2cb..9f0d70d15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.1.1 +__29.12.2021__ + +- Correctly expose `builder` parameter in `IMember#edit` + ## 3.1.0 __28.12.2021__ diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index 471c81a6d..29d82f1c1 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -33,7 +33,7 @@ class Constants { static const int apiVersion = 9; /// Version of Nyxx - static const String version = "3.1.0"; + static const String version = "3.1.1"; /// Url to Nyxx repo static const String repoUrl = "https://github.com/nyxx-discord/nyxx"; diff --git a/pubspec.yaml b/pubspec.yaml index 01e2810a5..3c1474015 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: nyxx -version: 3.1.0 +version: 3.1.1 description: A Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. homepage: https://github.com/nyxx-discord/nyxx repository: https://github.com/nyxx-discord/nyxx