From 74301c5d2d1a160441b3e99ab8b557dbf8c6e434 Mon Sep 17 00:00:00 2001 From: Vic256 Date: Sat, 9 Jul 2022 00:40:24 +0200 Subject: [PATCH 1/6] feat: implements voice state management --- lib/src/api/guilds/guild_member.dart | 7 +- lib/src/api/managers/member_manager.dart | 26 ++-- lib/src/api/managers/voice_manager.dart | 77 ++++++++++ lib/src/constants.dart | 2 + lib/src/internal/entities/event_manager.dart | 13 +- .../websockets/packets/guild_create.dart | 20 ++- .../websockets/packets/guild_member_add.dart | 9 +- .../packets/guild_member_update.dart | 13 +- .../packets/voice_state_update.dart | 135 ++++++++++++++++++ .../websockets/websocket_dispatcher.dart | 2 + 10 files changed, 285 insertions(+), 19 deletions(-) create mode 100644 lib/src/api/managers/voice_manager.dart create mode 100644 lib/src/internal/websockets/packets/voice_state_update.dart diff --git a/lib/src/api/guilds/guild_member.dart b/lib/src/api/guilds/guild_member.dart index 46bfbb05..e9c9c7cc 100644 --- a/lib/src/api/guilds/guild_member.dart +++ b/lib/src/api/guilds/guild_member.dart @@ -2,6 +2,7 @@ import 'package:http/http.dart'; import 'package:mineral/api.dart'; import 'package:mineral/core.dart'; import 'package:mineral/src/api/guilds/guild_role_manager.dart'; +import 'package:mineral/src/api/managers/voice_manager.dart'; class GuildMember { User user; @@ -13,7 +14,7 @@ class GuildMember { bool isPending; DateTime? timeoutDuration; MemberRoleManager roles; - Voice voice; + late VoiceManager voice; late Guild guild; GuildMember({ @@ -97,7 +98,7 @@ class GuildMember { ..roles = roles; } - factory GuildMember.from({ required user, required GuildRoleManager roles, dynamic member, required Snowflake guildId }) { + factory GuildMember.from({ required user, required GuildRoleManager roles, dynamic member, required Snowflake guildId, required VoiceManager voice }) { MemberRoleManager memberRoleManager = MemberRoleManager(manager: roles, memberId: user.id); for (var element in (member['roles'] as List)) { Role? role = roles.cache.get(element); @@ -116,7 +117,7 @@ class GuildMember { isPending: member['pending'] == true, timeoutDuration: member['communication_disabled_until'] != null ? DateTime.parse(member['communication_disabled_until']) : null, roles: memberRoleManager, - voice: Voice.from(payload: member), + voice: voice, ); } } diff --git a/lib/src/api/managers/member_manager.dart b/lib/src/api/managers/member_manager.dart index ca6e3464..e013a468 100644 --- a/lib/src/api/managers/member_manager.dart +++ b/lib/src/api/managers/member_manager.dart @@ -4,6 +4,7 @@ import 'package:http/http.dart'; import 'package:mineral/api.dart'; import 'package:mineral/core.dart'; import 'package:mineral/src/api/managers/cache_manager.dart'; +import 'package:mineral/src/api/managers/voice_manager.dart'; class MemberManager implements CacheManager { @override @@ -17,19 +18,26 @@ class MemberManager implements CacheManager { @override Future> sync () async { Http http = ioc.singleton(ioc.services.http); - cache.clear(); Response response = await http.get(url: "/guilds/$guildId/members"); - dynamic payload = jsonDecode(response.body); + if(response.statusCode == 200) { + dynamic payload = jsonDecode(response.body); + final Map voiceStateCache = cache.map((key, value) => MapEntry(key, value.voice)); - for(dynamic element in payload) { - GuildMember guildMember = GuildMember.from( - user: User.from(element['user']), - roles: guild.roles, - guildId: guild.id - ); + cache.clear(); - cache.putIfAbsent(guildMember.user.id, () => guildMember); + for(dynamic element in payload) { + VoiceManager? voiceManager = voiceStateCache.get(element['user']['id']); + + GuildMember guildMember = GuildMember.from( + user: User.from(element['user']), + roles: guild.roles, + guildId: guild.id, + voice: voiceManager ?? VoiceManager(isMute: element['mute'], isDeaf: element['deaf'], isSelfMute: false, isSelfDeaf: false, hasVideo: false, hasStream: false, channel: null) + ); + + cache.putIfAbsent(guildMember.user.id, () => guildMember); + } } return cache; diff --git a/lib/src/api/managers/voice_manager.dart b/lib/src/api/managers/voice_manager.dart new file mode 100644 index 00000000..8f9c2885 --- /dev/null +++ b/lib/src/api/managers/voice_manager.dart @@ -0,0 +1,77 @@ +import 'package:http/http.dart'; +import 'package:mineral/api.dart'; +import 'package:mineral/core.dart'; + +class VoiceManager { + late final GuildMember member; + bool isDeaf; + bool isMute; + bool isSelfMute; + bool isSelfDeaf; + bool hasVideo; + bool? hasStream; + VoiceChannel? channel; + + VoiceManager({ + required this.isMute, + required this.isDeaf, + required this.isSelfMute, + required this.isSelfDeaf, + required this.hasVideo, + required this.hasStream, + required this.channel + }); + + Future setMute(bool value) async { + final Http http = ioc.singleton(ioc.services.http); + final Response response = await http.patch( + url: '/guilds/${member.guild.id}/${member.user.id}', + payload: {'mute': value} + ); + + if (response.statusCode == 200) { + isMute = value; + } + } + + Future setDeaf(bool value) async { + final Http http = ioc.singleton(ioc.services.http); + final Response response = await http.patch( + url: '/guilds/${member.guild.id}/${member.user.id}', + payload: {'deaf': value} + ); + + if (response.statusCode == 200) { + isDeaf = value; + } + } + + Future move(Snowflake channelId) async { + final Http http = ioc.singleton(ioc.services.http); + final Response response = await http.patch( + url: '/guilds/${member.guild.id}/${member.user.id}', + payload: {'channel_id': channelId} + ); + + if (response.statusCode == 200) { + final VoiceChannel? channel = member.guild.channels.cache.get(channelId); + if (channel != null) { + this.channel = channel; + } + } + } + + factory VoiceManager.from(dynamic payload, VoiceChannel? channel) { + return VoiceManager( + isMute: payload['mute'], + isDeaf: payload['deaf'], + isSelfMute: payload['self_mute'], + isSelfDeaf: payload['self_deaf'], + hasVideo: payload['self_video'], + hasStream: payload['self_stream'], + channel: channel + ); + } + + +} \ No newline at end of file diff --git a/lib/src/constants.dart b/lib/src/constants.dart index 8c951400..eafa93af 100644 --- a/lib/src/constants.dart +++ b/lib/src/constants.dart @@ -53,6 +53,8 @@ enum PacketType { memberJoinRequest('GUILD_JOIN_REQUEST_UPDATE'), + voiceStateUpdate('VOICE_STATE_UPDATE'), + resumed('RESUMED'); final String _value; diff --git a/lib/src/internal/entities/event_manager.dart b/lib/src/internal/entities/event_manager.dart index b93e1e62..2156d380 100644 --- a/lib/src/internal/entities/event_manager.dart +++ b/lib/src/internal/entities/event_manager.dart @@ -92,7 +92,18 @@ enum Events { commandCreate('create::commandInteraction', { 'interaction': CommandInteraction }), buttonCreate('create::buttonInteraction', { 'interaction': ButtonInteraction }), modalCreate('create::modalInteraction', { 'interaction': ModalInteraction }), - selectMenuCreate('create::selectMenuInteraction', { 'interaction': SelectMenuInteraction }); + selectMenuCreate('create::selectMenuInteraction', { 'interaction': SelectMenuInteraction }), + + voiceConnect('connect::voice', { 'member': GuildMember }), + voiceDisconnect('disconnect::voice', { 'member': GuildMember }), + memberMuted('mute::voice', { 'member': GuildMember }), + memberUnMuted('unmute::voice', { 'member': GuildMember }), + memberDeaf('deaf::voice', { 'member': GuildMember }), + memberUnDeaf('undeaf::voice', { 'member': GuildMember }), + memberSelfMuted('self::mute::voice', { 'member': GuildMember }), + memberSelfUnMuted('self::unmute::voice', { 'member': GuildMember }), + memberSelfDeaf('self::deaf::voice', { 'member': GuildMember }), + memberSelfUnDeaf('self::undeaf::voice', { 'member': GuildMember }); final String event; final Map params; diff --git a/lib/src/internal/websockets/packets/guild_create.dart b/lib/src/internal/websockets/packets/guild_create.dart index 3faedd74..236acf37 100644 --- a/lib/src/internal/websockets/packets/guild_create.dart +++ b/lib/src/internal/websockets/packets/guild_create.dart @@ -11,6 +11,7 @@ import 'package:mineral/src/api/managers/emoji_manager.dart'; import 'package:mineral/src/api/managers/guild_scheduled_event_manager.dart'; import 'package:mineral/src/api/managers/member_manager.dart'; import 'package:mineral/src/api/managers/moderation_rule_manager.dart'; +import 'package:mineral/src/api/managers/voice_manager.dart'; import 'package:mineral/src/api/managers/webhook_manager.dart'; import 'package:mineral/src/internal/entities/command_manager.dart'; import 'package:mineral/src/internal/entities/event_manager.dart'; @@ -32,6 +33,13 @@ class GuildCreate implements WebsocketPacket { Role role = Role.from(roleManager: roleManager, payload: item); roleManager.cache.putIfAbsent(role.id, () => role); } + + Map voices = {}; + for(dynamic voiceMember in websocketResponse.payload['voice_states']) { + final VoiceManager voiceManager = VoiceManager.from(voiceMember, null); + voices.putIfAbsent(voiceMember['user_id'], () => voiceManager); + voices.putIfAbsent(voiceMember['channel_id'], () => voiceManager); + } MemberManager memberManager = MemberManager(guildId: websocketResponse.payload['id']); for (dynamic member in websocketResponse.payload['members']) { @@ -41,7 +49,10 @@ class GuildCreate implements WebsocketPacket { roles: roleManager, user: user, member: member, - guildId: websocketResponse.payload['id'] + guildId: websocketResponse.payload['id'], + voice: voices.containsKey(user.id) + ? voices.get(user.id)! + : VoiceManager(isMute: member['mute'], isDeaf: member['deaf'], isSelfMute: false, isSelfDeaf: false, hasVideo: false, hasStream: false, channel: null) ); memberManager.cache.putIfAbsent(guildMember.user.id, () => guildMember); @@ -100,7 +111,6 @@ class GuildCreate implements WebsocketPacket { guild.members.cache.forEach((Snowflake id, GuildMember member) { member.guild = guild; member.voice.member = member; - member.voice.channel = guild.channels.cache.get(member.voice.channelId); }); // Assign guild channels @@ -110,6 +120,12 @@ class GuildCreate implements WebsocketPacket { channel.guild = guild; channel.parent = channel.parentId != null ? guild.channels.cache.get(channel.parentId) : null; channel.webhooks.guild = guild; + + print(id); + print(voices.containsKey(id)); + if(voices.containsKey(id)) { + voices.get(id)!.channel = channel as VoiceChannel; + } }); moderationManager.guild = guild; diff --git a/lib/src/internal/websockets/packets/guild_member_add.dart b/lib/src/internal/websockets/packets/guild_member_add.dart index 6a094dd5..4502ac1a 100644 --- a/lib/src/internal/websockets/packets/guild_member_add.dart +++ b/lib/src/internal/websockets/packets/guild_member_add.dart @@ -1,5 +1,6 @@ import 'package:mineral/api.dart'; import 'package:mineral/core.dart'; +import 'package:mineral/src/api/managers/voice_manager.dart'; import 'package:mineral/src/internal/entities/event_manager.dart'; import 'package:mineral/src/internal/websockets/websocket_packet.dart'; import 'package:mineral/src/internal/websockets/websocket_response.dart'; @@ -19,7 +20,13 @@ class GuildMemberAdd implements WebsocketPacket { if(guild != null) { User user = User.from(payload['user']); - GuildMember member = GuildMember.from(user: user, roles: guild.roles, member: payload, guildId: guild.id); + GuildMember member = GuildMember.from( + user: user, + roles: guild.roles, + member: payload, + guildId: guild.id, + voice: VoiceManager(isMute: payload['mute'], isDeaf: payload['deaf'], isSelfMute: false, isSelfDeaf: false, hasVideo: false, hasStream: false, channel: null) + ); member.guild = guild; guild.members.cache.putIfAbsent(member.user.id, () => member); diff --git a/lib/src/internal/websockets/packets/guild_member_update.dart b/lib/src/internal/websockets/packets/guild_member_update.dart index 2c92b8e5..1c3b168d 100644 --- a/lib/src/internal/websockets/packets/guild_member_update.dart +++ b/lib/src/internal/websockets/packets/guild_member_update.dart @@ -1,5 +1,6 @@ import 'package:mineral/api.dart'; import 'package:mineral/core.dart'; +import 'package:mineral/src/api/managers/voice_manager.dart'; import 'package:mineral/src/internal/entities/event_manager.dart'; import 'package:mineral/src/internal/websockets/websocket_packet.dart'; import 'package:mineral/src/internal/websockets/websocket_response.dart'; @@ -20,11 +21,17 @@ class GuildMemberUpdate implements WebsocketPacket { GuildMember? before = guild.members.cache.get(payload['user']['id']); User user = User.from(payload['user']); - GuildMember after = GuildMember.from(user: user, roles: guild.roles, guildId: guild.id, member: payload); + GuildMember after = GuildMember.from( + user: user, + roles: guild.roles, + member: payload, + guildId: guild.id, + voice: VoiceManager(isMute: payload['mute'], isDeaf: payload['deaf'], isSelfMute: false, isSelfDeaf: false, hasVideo: false, hasStream: false, channel: null) + ); after.guild = guild; - after.voice.member = after; - after.voice.channel = guild.channels.cache.get(after.voice.channelId); + //after.voice.member = after; + //after.voice.channel = guild.channels.cache.get(after.voice.channelId); manager.emit( event: Events.memberUpdate, diff --git a/lib/src/internal/websockets/packets/voice_state_update.dart b/lib/src/internal/websockets/packets/voice_state_update.dart new file mode 100644 index 00000000..de125c72 --- /dev/null +++ b/lib/src/internal/websockets/packets/voice_state_update.dart @@ -0,0 +1,135 @@ +import 'dart:convert'; + +import 'package:mineral/api.dart'; +import 'package:mineral/core.dart'; +import 'package:mineral/src/api/managers/voice_manager.dart'; +import 'package:mineral/src/internal/entities/event_manager.dart'; +import 'package:mineral/src/internal/event_emitter.dart'; +import 'package:mineral/src/internal/websockets/websocket_packet.dart'; +import 'package:mineral/src/internal/websockets/websocket_response.dart'; + +class VoiceStateUpdate implements WebsocketPacket { + @override + PacketType packetType = PacketType.voiceStateUpdate; + + @override + Future handle(WebsocketResponse websocketResponse) async { + EventManager manager = ioc.singleton(ioc.services.event); + MineralClient client = ioc.singleton(ioc.services.client); + + dynamic payload = websocketResponse.payload; + + Guild? guild = client.guilds.cache.get(payload['guild_id']); + GuildMember? member = guild?.members.cache.get(payload['user_id']); + VoiceChannel? voiceChannel = guild?.channels.cache.get(payload['channel_id']); + if (guild != null && member != null) { + VoiceManager before = member.voice; + VoiceManager after = VoiceManager.from(payload, voiceChannel); + + member.voice = after; + + //User move + if(before.channel != null && after.channel != null && before.channel != after.channel) { + print('USER MOVE'); + manager.emit( + event: Events.voiceDisconnect, + params: [member] + ); + manager.emit( + event: Events.voiceConnect, + params: [member] + ); + } + + //User connect + if(before.channel == null && after.channel != null) { + print('USER CONNECT'); + manager.emit( + event: Events.voiceConnect, + params: [member] + ); + } + + //User leave + if(before.channel != null && after.channel == null) { + print('USER LEAVE'); + manager.emit( + event: Events.voiceDisconnect, + params: [member] + ); + } + + //User muted + if(!before.isMute && after.isMute) { + print('USER MUTE'); + manager.emit( + event: Events.memberMuted, + params: [member] + ); + } + + //User unmute + if(before.isMute && !after.isMute) { + print('USER UNMUTE'); + manager.emit( + event: Events.memberUnMuted, + params: [member] + ); + } + + //User undeaf + if(before.isDeaf && !after.isDeaf) { + print('USER UNDEAF'); + manager.emit( + event: Events.memberUnDeaf, + params: [member] + ); + } + + //User deaf + if(!before.isDeaf && after.isDeaf) { + print('USER DEAF'); + manager.emit( + event: Events.memberDeaf, + params: [member] + ); + } + + //User selfUnMute + if(before.isSelfMute && !after.isSelfMute) { + print('USER UNSELFMUTE'); + manager.emit( + event: Events.memberSelfUnMuted, + params: [member] + ); + } + + //User selfMute + if(!before.isSelfMute && after.isSelfMute) { + print('USER SELFMUTE'); + manager.emit( + event: Events.memberSelfMuted, + params: [member] + ); + } + + //User selfUnDeaf + if(before.isSelfDeaf && !after.isSelfDeaf) { + print('USER UNSELFDEAF'); + manager.emit( + event: Events.memberSelfUnDeaf, + params: [member] + ); + } + + //User selfDeaf + if(!before.isSelfDeaf && after.isSelfDeaf) { + print('USER SELFDEAF'); + manager.emit( + event: Events.memberSelfDeaf, + params: [member] + ); + } + } + } +} diff --git a/lib/src/internal/websockets/websocket_dispatcher.dart b/lib/src/internal/websockets/websocket_dispatcher.dart index 089159e1..452e5020 100644 --- a/lib/src/internal/websockets/websocket_dispatcher.dart +++ b/lib/src/internal/websockets/websocket_dispatcher.dart @@ -24,6 +24,7 @@ import 'package:mineral/src/internal/websockets/packets/message_update.dart'; import 'package:mineral/src/internal/websockets/packets/presence_update.dart'; import 'package:mineral/src/internal/websockets/packets/ready.dart'; import 'package:mineral/src/internal/websockets/packets/resumed.dart'; +import 'package:mineral/src/internal/websockets/packets/voice_state_update.dart'; import 'package:mineral/src/internal/websockets/packets/webhook_update.dart'; import 'package:mineral/src/internal/websockets/websocket_packet.dart'; import 'package:mineral/src/internal/websockets/websocket_response.dart'; @@ -59,6 +60,7 @@ class WebsocketDispatcher { register(PacketType.guildScheduledEventUserRemove, GuildScheduledEventUserRemove()); register(PacketType.webhookUpdate, WebhookUpdate()); register(PacketType.guildIntegrationsUpdate, GuildIntegrationsUpdate()); + register(PacketType.voiceStateUpdate, VoiceStateUpdate()); } void register (PacketType type, WebsocketPacket packet) { From 123e8642ef923a1cca2472295df861e0d48346de Mon Sep 17 00:00:00 2001 From: Vic256 Date: Sat, 9 Jul 2022 01:05:07 +0200 Subject: [PATCH 2/6] feat: implement global voice update event --- lib/src/internal/entities/event_manager.dart | 2 ++ .../packets/voice_state_update.dart | 31 ++++++++----------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/src/internal/entities/event_manager.dart b/lib/src/internal/entities/event_manager.dart index 2156d380..16b9f9a7 100644 --- a/lib/src/internal/entities/event_manager.dart +++ b/lib/src/internal/entities/event_manager.dart @@ -1,6 +1,7 @@ import 'dart:mirrors'; import 'package:mineral/api.dart'; +import 'package:mineral/src/api/managers/voice_manager.dart'; import 'package:mineral/src/internal/entities/store_manager.dart'; class EventManager { @@ -94,6 +95,7 @@ enum Events { modalCreate('create::modalInteraction', { 'interaction': ModalInteraction }), selectMenuCreate('create::selectMenuInteraction', { 'interaction': SelectMenuInteraction }), + voiceStateUpdate('update::voice', { 'before': VoiceManager, 'after': VoiceManager }), voiceConnect('connect::voice', { 'member': GuildMember }), voiceDisconnect('disconnect::voice', { 'member': GuildMember }), memberMuted('mute::voice', { 'member': GuildMember }), diff --git a/lib/src/internal/websockets/packets/voice_state_update.dart b/lib/src/internal/websockets/packets/voice_state_update.dart index de125c72..d19c1f60 100644 --- a/lib/src/internal/websockets/packets/voice_state_update.dart +++ b/lib/src/internal/websockets/packets/voice_state_update.dart @@ -28,40 +28,42 @@ class VoiceStateUpdate implements WebsocketPacket { member.voice = after; + manager.emit( + event: Events.voiceStateUpdate, + params: [before, after] + ); + //User move if(before.channel != null && after.channel != null && before.channel != after.channel) { - print('USER MOVE'); manager.emit( - event: Events.voiceDisconnect, - params: [member] + event: Events.voiceDisconnect, + params: [before] ); + manager.emit( - event: Events.voiceConnect, - params: [member] + event: Events.voiceConnect, + params: [member, before.channel, after.channel] ); } //User connect if(before.channel == null && after.channel != null) { - print('USER CONNECT'); manager.emit( - event: Events.voiceConnect, - params: [member] + event: Events.voiceConnect, + params: [member, before.channel, after.channel] ); } //User leave if(before.channel != null && after.channel == null) { - print('USER LEAVE'); manager.emit( event: Events.voiceDisconnect, - params: [member] + params: [before] ); } //User muted if(!before.isMute && after.isMute) { - print('USER MUTE'); manager.emit( event: Events.memberMuted, params: [member] @@ -70,7 +72,6 @@ class VoiceStateUpdate implements WebsocketPacket { //User unmute if(before.isMute && !after.isMute) { - print('USER UNMUTE'); manager.emit( event: Events.memberUnMuted, params: [member] @@ -79,7 +80,6 @@ class VoiceStateUpdate implements WebsocketPacket { //User undeaf if(before.isDeaf && !after.isDeaf) { - print('USER UNDEAF'); manager.emit( event: Events.memberUnDeaf, params: [member] @@ -88,7 +88,6 @@ class VoiceStateUpdate implements WebsocketPacket { //User deaf if(!before.isDeaf && after.isDeaf) { - print('USER DEAF'); manager.emit( event: Events.memberDeaf, params: [member] @@ -97,7 +96,6 @@ class VoiceStateUpdate implements WebsocketPacket { //User selfUnMute if(before.isSelfMute && !after.isSelfMute) { - print('USER UNSELFMUTE'); manager.emit( event: Events.memberSelfUnMuted, params: [member] @@ -106,7 +104,6 @@ class VoiceStateUpdate implements WebsocketPacket { //User selfMute if(!before.isSelfMute && after.isSelfMute) { - print('USER SELFMUTE'); manager.emit( event: Events.memberSelfMuted, params: [member] @@ -115,7 +112,6 @@ class VoiceStateUpdate implements WebsocketPacket { //User selfUnDeaf if(before.isSelfDeaf && !after.isSelfDeaf) { - print('USER UNSELFDEAF'); manager.emit( event: Events.memberSelfUnDeaf, params: [member] @@ -124,7 +120,6 @@ class VoiceStateUpdate implements WebsocketPacket { //User selfDeaf if(!before.isSelfDeaf && after.isSelfDeaf) { - print('USER SELFDEAF'); manager.emit( event: Events.memberSelfDeaf, params: [member] From de8cb88ce51cab9afc364d336e335625da5b10f8 Mon Sep 17 00:00:00 2001 From: Vic256 Date: Sat, 9 Jul 2022 01:40:52 +0200 Subject: [PATCH 3/6] feat: implement custom_id on voice connect --- lib/src/internal/entities/event_manager.dart | 4 +-- .../websockets/packets/guild_create.dart | 2 -- .../packets/voice_state_update.dart | 34 +++++++++---------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/lib/src/internal/entities/event_manager.dart b/lib/src/internal/entities/event_manager.dart index 16b9f9a7..05784fc5 100644 --- a/lib/src/internal/entities/event_manager.dart +++ b/lib/src/internal/entities/event_manager.dart @@ -96,8 +96,8 @@ enum Events { selectMenuCreate('create::selectMenuInteraction', { 'interaction': SelectMenuInteraction }), voiceStateUpdate('update::voice', { 'before': VoiceManager, 'after': VoiceManager }), - voiceConnect('connect::voice', { 'member': GuildMember }), - voiceDisconnect('disconnect::voice', { 'member': GuildMember }), + voiceConnect('connect::voice', { 'member': GuildMember, 'before': 'VoiceChannel?', 'after': VoiceChannel }), + voiceDisconnect('disconnect::voice', { 'member': GuildMember, 'channel': VoiceChannel }), memberMuted('mute::voice', { 'member': GuildMember }), memberUnMuted('unmute::voice', { 'member': GuildMember }), memberDeaf('deaf::voice', { 'member': GuildMember }), diff --git a/lib/src/internal/websockets/packets/guild_create.dart b/lib/src/internal/websockets/packets/guild_create.dart index 236acf37..1418a520 100644 --- a/lib/src/internal/websockets/packets/guild_create.dart +++ b/lib/src/internal/websockets/packets/guild_create.dart @@ -121,8 +121,6 @@ class GuildCreate implements WebsocketPacket { channel.parent = channel.parentId != null ? guild.channels.cache.get(channel.parentId) : null; channel.webhooks.guild = guild; - print(id); - print(voices.containsKey(id)); if(voices.containsKey(id)) { voices.get(id)!.channel = channel as VoiceChannel; } diff --git a/lib/src/internal/websockets/packets/voice_state_update.dart b/lib/src/internal/websockets/packets/voice_state_update.dart index d19c1f60..090365fa 100644 --- a/lib/src/internal/websockets/packets/voice_state_update.dart +++ b/lib/src/internal/websockets/packets/voice_state_update.dart @@ -35,31 +35,18 @@ class VoiceStateUpdate implements WebsocketPacket { //User move if(before.channel != null && after.channel != null && before.channel != after.channel) { - manager.emit( - event: Events.voiceDisconnect, - params: [before] - ); - - manager.emit( - event: Events.voiceConnect, - params: [member, before.channel, after.channel] - ); + _emitEvent(manager, Events.voiceDisconnect, [member, before.channel], before.channel!.id); + _emitEvent(manager, Events.voiceConnect, [member, before.channel, after.channel], after.channel!.id); } //User connect if(before.channel == null && after.channel != null) { - manager.emit( - event: Events.voiceConnect, - params: [member, before.channel, after.channel] - ); + _emitEvent(manager, Events.voiceConnect, [member, before.channel, after.channel], after.channel!.id); } //User leave if(before.channel != null && after.channel == null) { - manager.emit( - event: Events.voiceDisconnect, - params: [before] - ); + _emitEvent(manager, Events.voiceDisconnect, [member, before.channel], before.channel!.id); } //User muted @@ -127,4 +114,17 @@ class VoiceStateUpdate implements WebsocketPacket { } } } + + _emitEvent(EventManager manager, Events event, dynamic params, Snowflake customId) { + manager.emit( + event: event, + params: params, + ); + + manager.emit( + event: event, + params: params, + customId: customId + ); + } } From ebe09cb40952d6a932cc416dd2989c6641a8d794 Mon Sep 17 00:00:00 2001 From: Vic256 Date: Sun, 10 Jul 2022 21:49:34 +0200 Subject: [PATCH 4/6] fix: change url and discord return status code --- lib/src/api/managers/voice_manager.dart | 8 ++++---- .../internal/websockets/packets/guild_member_update.dart | 7 ++++++- .../internal/websockets/packets/voice_state_update.dart | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/src/api/managers/voice_manager.dart b/lib/src/api/managers/voice_manager.dart index 8f9c2885..9a82ce03 100644 --- a/lib/src/api/managers/voice_manager.dart +++ b/lib/src/api/managers/voice_manager.dart @@ -25,11 +25,11 @@ class VoiceManager { Future setMute(bool value) async { final Http http = ioc.singleton(ioc.services.http); final Response response = await http.patch( - url: '/guilds/${member.guild.id}/${member.user.id}', + url: '/guilds/${member.guild.id}/members/${member.user.id}', payload: {'mute': value} ); - if (response.statusCode == 200) { + if (response.statusCode == 204 || response.statusCode == 200) { isMute = value; } } @@ -37,11 +37,11 @@ class VoiceManager { Future setDeaf(bool value) async { final Http http = ioc.singleton(ioc.services.http); final Response response = await http.patch( - url: '/guilds/${member.guild.id}/${member.user.id}', + url: '/guilds/${member.guild.id}/members/${member.user.id}', payload: {'deaf': value} ); - if (response.statusCode == 200) { + if (response.statusCode == 204 || response.statusCode == 200) { isDeaf = value; } } diff --git a/lib/src/internal/websockets/packets/guild_member_update.dart b/lib/src/internal/websockets/packets/guild_member_update.dart index 1c3b168d..b47b76b9 100644 --- a/lib/src/internal/websockets/packets/guild_member_update.dart +++ b/lib/src/internal/websockets/packets/guild_member_update.dart @@ -20,16 +20,21 @@ class GuildMemberUpdate implements WebsocketPacket { if (guild != null) { GuildMember? before = guild.members.cache.get(payload['user']['id']); + VoiceManager voice = before != null + ? before.voice + : VoiceManager(isMute: payload['mute'], isDeaf: payload['deaf'], isSelfMute: false, isSelfDeaf: false, hasVideo: false, hasStream: false, channel: null); + User user = User.from(payload['user']); GuildMember after = GuildMember.from( user: user, roles: guild.roles, member: payload, guildId: guild.id, - voice: VoiceManager(isMute: payload['mute'], isDeaf: payload['deaf'], isSelfMute: false, isSelfDeaf: false, hasVideo: false, hasStream: false, channel: null) + voice: voice ); after.guild = guild; + after.voice.member = after; //after.voice.member = after; //after.voice.channel = guild.channels.cache.get(after.voice.channelId); diff --git a/lib/src/internal/websockets/packets/voice_state_update.dart b/lib/src/internal/websockets/packets/voice_state_update.dart index 090365fa..ec0d5ca0 100644 --- a/lib/src/internal/websockets/packets/voice_state_update.dart +++ b/lib/src/internal/websockets/packets/voice_state_update.dart @@ -27,6 +27,7 @@ class VoiceStateUpdate implements WebsocketPacket { VoiceManager after = VoiceManager.from(payload, voiceChannel); member.voice = after; + after.member = member; manager.emit( event: Events.voiceStateUpdate, From 3ef8ed442a1a89701ec7aada569b129306d6fd4e Mon Sep 17 00:00:00 2001 From: Vic256 Date: Sun, 10 Jul 2022 22:48:46 +0200 Subject: [PATCH 5/6] refactor: change indentation --- lib/src/internal/websockets/packets/guild_create.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/src/internal/websockets/packets/guild_create.dart b/lib/src/internal/websockets/packets/guild_create.dart index 1418a520..c8c34c9a 100644 --- a/lib/src/internal/websockets/packets/guild_create.dart +++ b/lib/src/internal/websockets/packets/guild_create.dart @@ -52,7 +52,15 @@ class GuildCreate implements WebsocketPacket { guildId: websocketResponse.payload['id'], voice: voices.containsKey(user.id) ? voices.get(user.id)! - : VoiceManager(isMute: member['mute'], isDeaf: member['deaf'], isSelfMute: false, isSelfDeaf: false, hasVideo: false, hasStream: false, channel: null) + : VoiceManager( + isMute: member['mute'], + isDeaf: member['deaf'], + isSelfMute: false, + isSelfDeaf: false, + hasVideo: false, + hasStream: false, + channel: null + ) ); memberManager.cache.putIfAbsent(guildMember.user.id, () => guildMember); From ccae289228c93ff55b34cf5085e32efcafede8a2 Mon Sep 17 00:00:00 2001 From: Vic256 Date: Sun, 10 Jul 2022 22:57:10 +0200 Subject: [PATCH 6/6] fix: change member update url on move --- lib/src/api/managers/voice_manager.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/api/managers/voice_manager.dart b/lib/src/api/managers/voice_manager.dart index 9a82ce03..243cded4 100644 --- a/lib/src/api/managers/voice_manager.dart +++ b/lib/src/api/managers/voice_manager.dart @@ -49,11 +49,11 @@ class VoiceManager { Future move(Snowflake channelId) async { final Http http = ioc.singleton(ioc.services.http); final Response response = await http.patch( - url: '/guilds/${member.guild.id}/${member.user.id}', + url: '/guilds/${member.guild.id}/members/${member.user.id}', payload: {'channel_id': channelId} ); - if (response.statusCode == 200) { + if (response.statusCode == 204 || response.statusCode == 200) { final VoiceChannel? channel = member.guild.channels.cache.get(channelId); if (channel != null) { this.channel = channel;