0
# Events and Gateway
1
2
Discord gateway events and event handling system for real-time bot functionality including comprehensive event types, custom event dispatching, event filtering, and gateway connection management for responsive Discord bot applications.
3
4
## Capabilities
5
6
### Event System
7
8
Core event handling infrastructure for Discord gateway events and custom bot events.
9
10
```python { .api }
11
@bot.event
12
async def on_ready():
13
"""
14
Called when the bot is ready and connected to Discord.
15
16
This event is called once when the bot successfully connects
17
and is ready to receive events and process commands.
18
"""
19
20
@bot.event
21
async def on_resumed():
22
"""
23
Called when a previously disconnected bot resumes its connection.
24
"""
25
26
@bot.event
27
async def on_connect():
28
"""
29
Called when the bot connects to Discord (before ready).
30
"""
31
32
@bot.event
33
async def on_disconnect():
34
"""
35
Called when the bot disconnects from Discord.
36
"""
37
38
@bot.event
39
async def on_shard_connect(shard_id: int):
40
"""
41
Called when a shard connects to Discord.
42
43
Parameters:
44
- shard_id: ID of the connected shard
45
"""
46
47
@bot.event
48
async def on_shard_disconnect(shard_id: int):
49
"""
50
Called when a shard disconnects from Discord.
51
52
Parameters:
53
- shard_id: ID of the disconnected shard
54
"""
55
56
@bot.event
57
async def on_shard_ready(shard_id: int):
58
"""
59
Called when a shard is ready.
60
61
Parameters:
62
- shard_id: ID of the ready shard
63
"""
64
65
@bot.event
66
async def on_shard_resumed(shard_id: int):
67
"""
68
Called when a shard resumes connection.
69
70
Parameters:
71
- shard_id: ID of the resumed shard
72
"""
73
74
def wait_for(
75
event: str,
76
*,
77
check: Optional[Callable[..., bool]] = None,
78
timeout: Optional[float] = None
79
) -> Any:
80
"""
81
Wait for a specific event to occur.
82
83
Parameters:
84
- event: Name of the event to wait for
85
- check: Optional function to check event conditions
86
- timeout: Maximum time to wait in seconds
87
88
Returns:
89
Event data when the event occurs
90
91
Raises:
92
asyncio.TimeoutError: If timeout is reached
93
"""
94
95
def dispatch(event: str, *args, **kwargs) -> None:
96
"""
97
Dispatch a custom event.
98
99
Parameters:
100
- event: Event name (without 'on_' prefix)
101
- args: Event arguments
102
- kwargs: Event keyword arguments
103
"""
104
```
105
106
### Message Events
107
108
Events related to message creation, editing, deletion, and reactions.
109
110
```python { .api }
111
@bot.event
112
async def on_message(message: Message):
113
"""
114
Called when a message is sent.
115
116
Parameters:
117
- message: The message that was sent
118
"""
119
120
@bot.event
121
async def on_message_edit(before: Message, after: Message):
122
"""
123
Called when a message is edited.
124
125
Parameters:
126
- before: Message before editing
127
- after: Message after editing
128
"""
129
130
@bot.event
131
async def on_message_delete(message: Message):
132
"""
133
Called when a message is deleted.
134
135
Parameters:
136
- message: The deleted message
137
"""
138
139
@bot.event
140
async def on_bulk_message_delete(messages: List[Message]):
141
"""
142
Called when messages are bulk deleted.
143
144
Parameters:
145
- messages: List of deleted messages
146
"""
147
148
@bot.event
149
async def on_raw_message_edit(payload: RawMessageUpdateEvent):
150
"""
151
Called when a message is edited (raw event).
152
153
Parameters:
154
- payload: Raw message update data
155
"""
156
157
@bot.event
158
async def on_raw_message_delete(payload: RawMessageDeleteEvent):
159
"""
160
Called when a message is deleted (raw event).
161
162
Parameters:
163
- payload: Raw message delete data
164
"""
165
166
@bot.event
167
async def on_raw_bulk_message_delete(payload: RawBulkMessageDeleteEvent):
168
"""
169
Called when messages are bulk deleted (raw event).
170
171
Parameters:
172
- payload: Raw bulk delete data
173
"""
174
175
@bot.event
176
async def on_reaction_add(reaction: Reaction, user: Union[Member, User]):
177
"""
178
Called when a reaction is added to a message.
179
180
Parameters:
181
- reaction: The reaction that was added
182
- user: User who added the reaction
183
"""
184
185
@bot.event
186
async def on_reaction_remove(reaction: Reaction, user: Union[Member, User]):
187
"""
188
Called when a reaction is removed from a message.
189
190
Parameters:
191
- reaction: The reaction that was removed
192
- user: User who removed the reaction
193
"""
194
195
@bot.event
196
async def on_reaction_clear(message: Message, reactions: List[Reaction]):
197
"""
198
Called when all reactions are cleared from a message.
199
200
Parameters:
201
- message: Message that had reactions cleared
202
- reactions: List of reactions that were cleared
203
"""
204
205
@bot.event
206
async def on_reaction_clear_emoji(reaction: Reaction):
207
"""
208
Called when all reactions of a specific emoji are cleared.
209
210
Parameters:
211
- reaction: The reaction that was cleared
212
"""
213
214
@bot.event
215
async def on_raw_reaction_add(payload: RawReactionActionEvent):
216
"""
217
Called when a reaction is added (raw event).
218
219
Parameters:
220
- payload: Raw reaction add data
221
"""
222
223
@bot.event
224
async def on_raw_reaction_remove(payload: RawReactionActionEvent):
225
"""
226
Called when a reaction is removed (raw event).
227
228
Parameters:
229
- payload: Raw reaction remove data
230
"""
231
232
@bot.event
233
async def on_raw_reaction_clear(payload: RawReactionClearEvent):
234
"""
235
Called when reactions are cleared (raw event).
236
237
Parameters:
238
- payload: Raw reaction clear data
239
"""
240
241
@bot.event
242
async def on_raw_reaction_clear_emoji(payload: RawReactionClearEmojiEvent):
243
"""
244
Called when emoji reactions are cleared (raw event).
245
246
Parameters:
247
- payload: Raw emoji clear data
248
"""
249
```
250
251
### Member Events
252
253
Events related to guild member changes, presence updates, and member activity.
254
255
```python { .api }
256
@bot.event
257
async def on_member_join(member: Member):
258
"""
259
Called when a member joins a guild.
260
261
Parameters:
262
- member: The member that joined
263
"""
264
265
@bot.event
266
async def on_member_remove(member: Member):
267
"""
268
Called when a member leaves a guild.
269
270
Parameters:
271
- member: The member that left
272
"""
273
274
@bot.event
275
async def on_member_update(before: Member, after: Member):
276
"""
277
Called when a member is updated.
278
279
Parameters:
280
- before: Member before update
281
- after: Member after update
282
"""
283
284
@bot.event
285
async def on_user_update(before: User, after: User):
286
"""
287
Called when a user updates their profile.
288
289
Parameters:
290
- before: User before update
291
- after: User after update
292
"""
293
294
@bot.event
295
async def on_member_ban(guild: Guild, user: Union[User, Member]):
296
"""
297
Called when a member is banned from a guild.
298
299
Parameters:
300
- guild: Guild where the ban occurred
301
- user: User that was banned
302
"""
303
304
@bot.event
305
async def on_member_unban(guild: Guild, user: User):
306
"""
307
Called when a user is unbanned from a guild.
308
309
Parameters:
310
- guild: Guild where the unban occurred
311
- user: User that was unbanned
312
"""
313
314
@bot.event
315
async def on_presence_update(before: Member, after: Member):
316
"""
317
Called when a member's presence updates.
318
319
Parameters:
320
- before: Member presence before update
321
- after: Member presence after update
322
"""
323
324
@bot.event
325
async def on_typing(channel: Messageable, user: Union[User, Member], when: datetime):
326
"""
327
Called when someone starts typing.
328
329
Parameters:
330
- channel: Channel where typing started
331
- user: User who started typing
332
- when: When typing started
333
"""
334
```
335
336
### Guild Events
337
338
Events related to guild changes, channels, roles, and guild-specific features.
339
340
```python { .api }
341
@bot.event
342
async def on_guild_join(guild: Guild):
343
"""
344
Called when the bot joins a guild.
345
346
Parameters:
347
- guild: Guild that was joined
348
"""
349
350
@bot.event
351
async def on_guild_remove(guild: Guild):
352
"""
353
Called when the bot leaves or is removed from a guild.
354
355
Parameters:
356
- guild: Guild that was left
357
"""
358
359
@bot.event
360
async def on_guild_update(before: Guild, after: Guild):
361
"""
362
Called when a guild is updated.
363
364
Parameters:
365
- before: Guild before update
366
- after: Guild after update
367
"""
368
369
@bot.event
370
async def on_guild_available(guild: Guild):
371
"""
372
Called when a guild becomes available.
373
374
Parameters:
375
- guild: Guild that became available
376
"""
377
378
@bot.event
379
async def on_guild_unavailable(guild: Guild):
380
"""
381
Called when a guild becomes unavailable.
382
383
Parameters:
384
- guild: Guild that became unavailable
385
"""
386
387
@bot.event
388
async def on_guild_channel_create(channel: GuildChannel):
389
"""
390
Called when a guild channel is created.
391
392
Parameters:
393
- channel: Channel that was created
394
"""
395
396
@bot.event
397
async def on_guild_channel_delete(channel: GuildChannel):
398
"""
399
Called when a guild channel is deleted.
400
401
Parameters:
402
- channel: Channel that was deleted
403
"""
404
405
@bot.event
406
async def on_guild_channel_update(before: GuildChannel, after: GuildChannel):
407
"""
408
Called when a guild channel is updated.
409
410
Parameters:
411
- before: Channel before update
412
- after: Channel after update
413
"""
414
415
@bot.event
416
async def on_guild_channel_pins_update(channel: Union[TextChannel, NewsChannel], last_pin: Optional[datetime]):
417
"""
418
Called when channel pins are updated.
419
420
Parameters:
421
- channel: Channel with updated pins
422
- last_pin: Time of last pinned message
423
"""
424
425
@bot.event
426
async def on_guild_role_create(role: Role):
427
"""
428
Called when a guild role is created.
429
430
Parameters:
431
- role: Role that was created
432
"""
433
434
@bot.event
435
async def on_guild_role_delete(role: Role):
436
"""
437
Called when a guild role is deleted.
438
439
Parameters:
440
- role: Role that was deleted
441
"""
442
443
@bot.event
444
async def on_guild_role_update(before: Role, after: Role):
445
"""
446
Called when a guild role is updated.
447
448
Parameters:
449
- before: Role before update
450
- after: Role after update
451
"""
452
453
@bot.event
454
async def on_guild_emojis_update(guild: Guild, before: List[Emoji], after: List[Emoji]):
455
"""
456
Called when guild emojis are updated.
457
458
Parameters:
459
- guild: Guild with updated emojis
460
- before: Emojis before update
461
- after: Emojis after update
462
"""
463
464
@bot.event
465
async def on_guild_stickers_update(guild: Guild, before: List[GuildSticker], after: List[GuildSticker]):
466
"""
467
Called when guild stickers are updated.
468
469
Parameters:
470
- guild: Guild with updated stickers
471
- before: Stickers before update
472
- after: Stickers after update
473
"""
474
```
475
476
### Voice Events
477
478
Events related to voice channel activity and voice state changes.
479
480
```python { .api }
481
@bot.event
482
async def on_voice_state_update(member: Member, before: VoiceState, after: VoiceState):
483
"""
484
Called when a member's voice state changes.
485
486
Parameters:
487
- member: Member whose voice state changed
488
- before: Voice state before change
489
- after: Voice state after change
490
"""
491
492
@bot.event
493
async def on_stage_instance_create(stage_instance: StageInstance):
494
"""
495
Called when a stage instance is created.
496
497
Parameters:
498
- stage_instance: Stage instance that was created
499
"""
500
501
@bot.event
502
async def on_stage_instance_delete(stage_instance: StageInstance):
503
"""
504
Called when a stage instance is deleted.
505
506
Parameters:
507
- stage_instance: Stage instance that was deleted
508
"""
509
510
@bot.event
511
async def on_stage_instance_update(before: StageInstance, after: StageInstance):
512
"""
513
Called when a stage instance is updated.
514
515
Parameters:
516
- before: Stage instance before update
517
- after: Stage instance after update
518
"""
519
```
520
521
### Interaction Events
522
523
Events related to application commands, components, and modal interactions.
524
525
```python { .api }
526
@bot.event
527
async def on_interaction(interaction: Interaction):
528
"""
529
Called when any interaction is received.
530
531
Parameters:
532
- interaction: The interaction that was received
533
"""
534
535
@bot.event
536
async def on_application_command(interaction: ApplicationCommandInteraction):
537
"""
538
Called when an application command is used.
539
540
Parameters:
541
- interaction: Application command interaction
542
"""
543
544
@bot.event
545
async def on_message_interaction(interaction: MessageInteraction):
546
"""
547
Called when a message component interaction occurs.
548
549
Parameters:
550
- interaction: Message component interaction
551
"""
552
553
@bot.event
554
async def on_modal_submit(interaction: ModalInteraction):
555
"""
556
Called when a modal is submitted.
557
558
Parameters:
559
- interaction: Modal submission interaction
560
"""
561
562
@bot.event
563
async def on_dropdown(interaction: MessageInteraction):
564
"""
565
Called when a dropdown/select menu is used.
566
567
Parameters:
568
- interaction: Dropdown interaction
569
"""
570
571
@bot.event
572
async def on_button_click(interaction: MessageInteraction):
573
"""
574
Called when a button is clicked.
575
576
Parameters:
577
- interaction: Button click interaction
578
"""
579
580
@bot.event
581
async def on_application_command_error(interaction: ApplicationCommandInteraction, error: Exception):
582
"""
583
Called when an application command raises an error.
584
585
Parameters:
586
- interaction: Command interaction that caused error
587
- error: Exception that was raised
588
"""
589
```
590
591
### Thread Events
592
593
Events related to thread creation, updates, and member management.
594
595
```python { .api }
596
@bot.event
597
async def on_thread_create(thread: Thread):
598
"""
599
Called when a thread is created.
600
601
Parameters:
602
- thread: Thread that was created
603
"""
604
605
@bot.event
606
async def on_thread_delete(thread: Thread):
607
"""
608
Called when a thread is deleted.
609
610
Parameters:
611
- thread: Thread that was deleted
612
"""
613
614
@bot.event
615
async def on_thread_update(before: Thread, after: Thread):
616
"""
617
Called when a thread is updated.
618
619
Parameters:
620
- before: Thread before update
621
- after: Thread after update
622
"""
623
624
@bot.event
625
async def on_thread_member_join(member: ThreadMember):
626
"""
627
Called when a member joins a thread.
628
629
Parameters:
630
- member: Thread member that joined
631
"""
632
633
@bot.event
634
async def on_thread_member_remove(member: ThreadMember):
635
"""
636
Called when a member leaves a thread.
637
638
Parameters:
639
- member: Thread member that left
640
"""
641
642
@bot.event
643
async def on_raw_thread_update(payload: RawThreadUpdateEvent):
644
"""
645
Called when a thread is updated (raw event).
646
647
Parameters:
648
- payload: Raw thread update data
649
"""
650
651
@bot.event
652
async def on_raw_thread_delete(payload: RawThreadDeleteEvent):
653
"""
654
Called when a thread is deleted (raw event).
655
656
Parameters:
657
- payload: Raw thread delete data
658
"""
659
```
660
661
### Scheduled Events
662
663
Events related to guild scheduled events and event management.
664
665
```python { .api }
666
@bot.event
667
async def on_scheduled_event_create(event: GuildScheduledEvent):
668
"""
669
Called when a scheduled event is created.
670
671
Parameters:
672
- event: Scheduled event that was created
673
"""
674
675
@bot.event
676
async def on_scheduled_event_delete(event: GuildScheduledEvent):
677
"""
678
Called when a scheduled event is deleted.
679
680
Parameters:
681
- event: Scheduled event that was deleted
682
"""
683
684
@bot.event
685
async def on_scheduled_event_update(before: GuildScheduledEvent, after: GuildScheduledEvent):
686
"""
687
Called when a scheduled event is updated.
688
689
Parameters:
690
- before: Event before update
691
- after: Event after update
692
"""
693
694
@bot.event
695
async def on_scheduled_event_user_add(event: GuildScheduledEvent, user: User):
696
"""
697
Called when a user subscribes to a scheduled event.
698
699
Parameters:
700
- event: Scheduled event
701
- user: User that subscribed
702
"""
703
704
@bot.event
705
async def on_scheduled_event_user_remove(event: GuildScheduledEvent, user: User):
706
"""
707
Called when a user unsubscribes from a scheduled event.
708
709
Parameters:
710
- event: Scheduled event
711
- user: User that unsubscribed
712
"""
713
```
714
715
### Raw Events
716
717
Raw gateway events for handling events without cached objects.
718
719
```python { .api }
720
class RawMessageUpdateEvent:
721
"""Raw message update event data."""
722
723
message_id: int
724
channel_id: int
725
guild_id: Optional[int]
726
data: Dict[str, Any]
727
728
class RawMessageDeleteEvent:
729
"""Raw message delete event data."""
730
731
message_id: int
732
channel_id: int
733
guild_id: Optional[int]
734
735
class RawBulkMessageDeleteEvent:
736
"""Raw bulk message delete event data."""
737
738
message_ids: List[int]
739
channel_id: int
740
guild_id: Optional[int]
741
742
class RawReactionActionEvent:
743
"""Raw reaction add/remove event data."""
744
745
message_id: int
746
channel_id: int
747
guild_id: Optional[int]
748
user_id: int
749
emoji: PartialEmoji
750
member: Optional[Member]
751
752
class RawReactionClearEvent:
753
"""Raw reaction clear event data."""
754
755
message_id: int
756
channel_id: int
757
guild_id: Optional[int]
758
759
class RawReactionClearEmojiEvent:
760
"""Raw emoji reaction clear event data."""
761
762
message_id: int
763
channel_id: int
764
guild_id: Optional[int]
765
emoji: PartialEmoji
766
767
class RawThreadUpdateEvent:
768
"""Raw thread update event data."""
769
770
thread_id: int
771
guild_id: int
772
parent_id: int
773
data: Dict[str, Any]
774
775
class RawThreadDeleteEvent:
776
"""Raw thread delete event data."""
777
778
thread_id: int
779
guild_id: int
780
parent_id: int
781
thread_type: ChannelType
782
```
783
784
### Gateway Connection
785
786
Gateway connection management and configuration for Discord real-time events.
787
788
```python { .api }
789
class GatewayParams:
790
"""Gateway connection parameters."""
791
792
def __init__(self): ...
793
794
url: str
795
shard_id: Optional[int]
796
shard_count: Optional[int]
797
session_start_limit: SessionStartLimit
798
799
class SessionStartLimit:
800
"""Gateway session start limit information."""
801
802
def __init__(self): ...
803
804
total: int
805
remaining: int
806
reset_after: int
807
max_concurrency: int
808
809
class Intents:
810
"""Gateway intents bitfield."""
811
812
def __init__(self, **kwargs): ...
813
814
@classmethod
815
def default(cls) -> Intents:
816
"""Default intents (recommended for most bots)."""
817
818
@classmethod
819
def all(cls) -> Intents:
820
"""All intents (requires privileged intents approval)."""
821
822
@classmethod
823
def none(cls) -> Intents:
824
"""No intents enabled."""
825
826
# Privileged intents (require approval)
827
@property
828
def presences(self) -> bool:
829
"""Presence update intents."""
830
831
@property
832
def members(self) -> bool:
833
"""Member update intents."""
834
835
@property
836
def message_content(self) -> bool:
837
"""Message content intents."""
838
839
# Non-privileged intents
840
@property
841
def guilds(self) -> bool:
842
"""Guild-related events."""
843
844
@property
845
def guild_messages(self) -> bool:
846
"""Guild message events."""
847
848
@property
849
def guild_reactions(self) -> bool:
850
"""Guild reaction events."""
851
852
@property
853
def guild_typing(self) -> bool:
854
"""Guild typing events."""
855
856
@property
857
def direct_messages(self) -> bool:
858
"""Direct message events."""
859
860
@property
861
def direct_message_reactions(self) -> bool:
862
"""DM reaction events."""
863
864
@property
865
def direct_message_typing(self) -> bool:
866
"""DM typing events."""
867
868
@property
869
def guild_integrations(self) -> bool:
870
"""Guild integration events."""
871
872
@property
873
def guild_webhooks(self) -> bool:
874
"""Guild webhook events."""
875
876
@property
877
def guild_invites(self) -> bool:
878
"""Guild invite events."""
879
880
@property
881
def guild_voice_states(self) -> bool:
882
"""Voice state events."""
883
884
@property
885
def guild_scheduled_events(self) -> bool:
886
"""Scheduled event intents."""
887
888
@property
889
def auto_moderation_configuration(self) -> bool:
890
"""AutoMod configuration events."""
891
892
@property
893
def auto_moderation_execution(self) -> bool:
894
"""AutoMod execution events."""
895
```
896
897
## Usage Examples
898
899
### Basic Event Handling
900
901
```python
902
import disnake
903
from disnake.ext import commands
904
905
# Set up intents
906
intents = disnake.Intents.default()
907
intents.message_content = True
908
intents.members = True
909
intents.presences = True
910
911
bot = commands.Bot(command_prefix='!', intents=intents)
912
913
@bot.event
914
async def on_ready():
915
print(f'Bot is ready! Logged in as {bot.user}')
916
print(f'Connected to {len(bot.guilds)} guilds')
917
print(f'Serving {len(bot.users)} users')
918
919
# Set bot activity
920
await bot.change_presence(
921
status=disnake.Status.online,
922
activity=disnake.Game(name="Managing the server!")
923
)
924
925
@bot.event
926
async def on_guild_join(guild):
927
"""Welcome message when bot joins a server."""
928
print(f'Joined new guild: {guild.name} (ID: {guild.id})')
929
930
# Send welcome message to system channel
931
if guild.system_channel and guild.system_channel.permissions_for(guild.me).send_messages:
932
embed = disnake.Embed(
933
title="Thanks for adding me!",
934
description="Use `!help` to see available commands.",
935
color=0x00ff00
936
)
937
embed.set_thumbnail(url=bot.user.display_avatar.url)
938
await guild.system_channel.send(embed=embed)
939
940
@bot.event
941
async def on_guild_remove(guild):
942
"""Log when bot leaves a server."""
943
print(f'Left guild: {guild.name} (ID: {guild.id})')
944
945
@bot.event
946
async def on_message(message):
947
"""Process messages and auto-responses."""
948
# Ignore bot messages
949
if message.author.bot:
950
return
951
952
# Auto-react to certain messages
953
if 'good bot' in message.content.lower():
954
await message.add_reaction('π')
955
elif 'bad bot' in message.content.lower():
956
await message.add_reaction('π’')
957
958
# Process commands
959
await bot.process_commands(message)
960
961
@bot.event
962
async def on_message_edit(before, after):
963
"""Log message edits."""
964
if before.author.bot or before.content == after.content:
965
return
966
967
print(f'Message edited in {before.channel}:')
968
print(f'Before: {before.content}')
969
print(f'After: {after.content}')
970
971
@bot.event
972
async def on_message_delete(message):
973
"""Log message deletions."""
974
if message.author.bot:
975
return
976
977
print(f'Message deleted in {message.channel}: {message.content}')
978
979
bot.run('YOUR_BOT_TOKEN')
980
```
981
982
### Member Event Handling
983
984
```python
985
@bot.event
986
async def on_member_join(member):
987
"""Welcome new members."""
988
guild = member.guild
989
990
# Create welcome embed
991
embed = disnake.Embed(
992
title=f"Welcome to {guild.name}!",
993
description=f"Hello {member.mention}, welcome to our community!",
994
color=0x00ff00
995
)
996
embed.set_thumbnail(url=member.display_avatar.url)
997
embed.add_field(name="Member Count", value=f"You're member #{guild.member_count}!", inline=False)
998
embed.add_field(name="Account Created", value=f"<t:{int(member.created_at.timestamp())}:F>", inline=True)
999
embed.set_footer(text=f"User ID: {member.id}")
1000
1001
# Send to welcome channel
1002
welcome_channel = disnake.utils.get(guild.channels, name='welcome')
1003
if welcome_channel:
1004
await welcome_channel.send(embed=embed)
1005
1006
# Auto-role assignment
1007
auto_role = disnake.utils.get(guild.roles, name='Member')
1008
if auto_role:
1009
try:
1010
await member.add_roles(auto_role, reason="Auto-role on join")
1011
except disnake.Forbidden:
1012
print(f"Cannot assign auto-role in {guild.name}")
1013
1014
# Send DM welcome message
1015
try:
1016
dm_embed = disnake.Embed(
1017
title=f"Welcome to {guild.name}!",
1018
description="Thanks for joining! Here are some helpful tips:",
1019
color=0x00ff00
1020
)
1021
dm_embed.add_field(
1022
name="Getting Started",
1023
value="β’ Read the rules in #rules\nβ’ Introduce yourself in #introductions\nβ’ Use `!help` to see bot commands",
1024
inline=False
1025
)
1026
await member.send(embed=dm_embed)
1027
except disnake.Forbidden:
1028
pass # User has DMs disabled
1029
1030
@bot.event
1031
async def on_member_remove(member):
1032
"""Log member departures."""
1033
guild = member.guild
1034
1035
# Log to departure channel
1036
log_channel = disnake.utils.get(guild.channels, name='member-logs')
1037
if log_channel:
1038
embed = disnake.Embed(
1039
title="Member Left",
1040
description=f"{member} ({member.id}) has left the server",
1041
color=0xff0000,
1042
timestamp=disnake.utils.utcnow()
1043
)
1044
embed.set_thumbnail(url=member.display_avatar.url)
1045
embed.add_field(name="Joined", value=f"<t:{int(member.joined_at.timestamp())}:F>" if member.joined_at else "Unknown", inline=True)
1046
embed.add_field(name="Member Count", value=f"{guild.member_count} members remaining", inline=True)
1047
1048
if member.roles[1:]: # Exclude @everyone
1049
roles = [role.name for role in member.roles[1:]]
1050
embed.add_field(name="Roles", value=", ".join(roles), inline=False)
1051
1052
await log_channel.send(embed=embed)
1053
1054
@bot.event
1055
async def on_member_update(before, after):
1056
"""Track member changes."""
1057
# Nickname changes
1058
if before.nick != after.nick:
1059
log_channel = disnake.utils.get(after.guild.channels, name='member-logs')
1060
if log_channel:
1061
embed = disnake.Embed(
1062
title="Nickname Changed",
1063
color=0x0099ff,
1064
timestamp=disnake.utils.utcnow()
1065
)
1066
embed.add_field(name="Member", value=after.mention, inline=True)
1067
embed.add_field(name="Before", value=before.display_name, inline=True)
1068
embed.add_field(name="After", value=after.display_name, inline=True)
1069
await log_channel.send(embed=embed)
1070
1071
# Role changes
1072
if before.roles != after.roles:
1073
added_roles = set(after.roles) - set(before.roles)
1074
removed_roles = set(before.roles) - set(after.roles)
1075
1076
if added_roles or removed_roles:
1077
log_channel = disnake.utils.get(after.guild.channels, name='member-logs')
1078
if log_channel:
1079
embed = disnake.Embed(
1080
title="Roles Updated",
1081
color=0x0099ff,
1082
timestamp=disnake.utils.utcnow()
1083
)
1084
embed.add_field(name="Member", value=after.mention, inline=False)
1085
1086
if added_roles:
1087
embed.add_field(name="Roles Added", value=", ".join([role.name for role in added_roles]), inline=False)
1088
if removed_roles:
1089
embed.add_field(name="Roles Removed", value=", ".join([role.name for role in removed_roles]), inline=False)
1090
1091
await log_channel.send(embed=embed)
1092
1093
@bot.event
1094
async def on_member_ban(guild, user):
1095
"""Log member bans."""
1096
log_channel = disnake.utils.get(guild.channels, name='moderation-logs')
1097
if log_channel:
1098
embed = disnake.Embed(
1099
title="Member Banned",
1100
description=f"{user} ({user.id}) was banned",
1101
color=0xff0000,
1102
timestamp=disnake.utils.utcnow()
1103
)
1104
embed.set_thumbnail(url=user.display_avatar.url)
1105
1106
# Try to get ban reason from audit logs
1107
try:
1108
async for entry in guild.audit_logs(limit=1, action=disnake.AuditLogAction.ban):
1109
if entry.target.id == user.id:
1110
embed.add_field(name="Reason", value=entry.reason or "No reason provided", inline=False)
1111
embed.add_field(name="Moderator", value=entry.user.mention, inline=True)
1112
break
1113
except disnake.Forbidden:
1114
pass
1115
1116
await log_channel.send(embed=embed)
1117
1118
@bot.event
1119
async def on_member_unban(guild, user):
1120
"""Log member unbans."""
1121
log_channel = disnake.utils.get(guild.channels, name='moderation-logs')
1122
if log_channel:
1123
embed = disnake.Embed(
1124
title="Member Unbanned",
1125
description=f"{user} ({user.id}) was unbanned",
1126
color=0x00ff00,
1127
timestamp=disnake.utils.utcnow()
1128
)
1129
embed.set_thumbnail(url=user.display_avatar.url)
1130
await log_channel.send(embed=embed)
1131
```
1132
1133
### Voice Event Monitoring
1134
1135
```python
1136
@bot.event
1137
async def on_voice_state_update(member, before, after):
1138
"""Track voice channel activity."""
1139
# Member joined a voice channel
1140
if before.channel is None and after.channel is not None:
1141
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
1142
if log_channel:
1143
embed = disnake.Embed(
1144
title="Voice Channel Joined",
1145
description=f"{member.mention} joined {after.channel.mention}",
1146
color=0x00ff00,
1147
timestamp=disnake.utils.utcnow()
1148
)
1149
await log_channel.send(embed=embed)
1150
1151
# Member left a voice channel
1152
elif before.channel is not None and after.channel is None:
1153
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
1154
if log_channel:
1155
embed = disnake.Embed(
1156
title="Voice Channel Left",
1157
description=f"{member.mention} left {before.channel.mention}",
1158
color=0xff0000,
1159
timestamp=disnake.utils.utcnow()
1160
)
1161
await log_channel.send(embed=embed)
1162
1163
# Member switched voice channels
1164
elif before.channel is not None and after.channel is not None and before.channel != after.channel:
1165
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
1166
if log_channel:
1167
embed = disnake.Embed(
1168
title="Voice Channel Switched",
1169
description=f"{member.mention} moved from {before.channel.mention} to {after.channel.mention}",
1170
color=0x0099ff,
1171
timestamp=disnake.utils.utcnow()
1172
)
1173
await log_channel.send(embed=embed)
1174
1175
# Voice state changes (mute, deafen, etc.)
1176
changes = []
1177
if before.self_mute != after.self_mute:
1178
changes.append(f"Self Mute: {after.self_mute}")
1179
if before.self_deaf != after.self_deaf:
1180
changes.append(f"Self Deafen: {after.self_deaf}")
1181
if before.mute != after.mute:
1182
changes.append(f"Server Mute: {after.mute}")
1183
if before.deaf != after.deaf:
1184
changes.append(f"Server Deafen: {after.deaf}")
1185
1186
if changes and after.channel:
1187
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
1188
if log_channel:
1189
embed = disnake.Embed(
1190
title="Voice State Changed",
1191
description=f"{member.mention} in {after.channel.mention}:\n" + "\n".join(changes),
1192
color=0xffa500,
1193
timestamp=disnake.utils.utcnow()
1194
)
1195
await log_channel.send(embed=embed)
1196
```
1197
1198
### Custom Event System
1199
1200
```python
1201
# Custom events using dispatch
1202
@bot.event
1203
async def on_level_up(member, old_level, new_level):
1204
"""Custom event for level system."""
1205
channel = disnake.utils.get(member.guild.channels, name='general')
1206
if channel:
1207
embed = disnake.Embed(
1208
title="Level Up!",
1209
description=f"{member.mention} reached level {new_level}!",
1210
color=0xffd700
1211
)
1212
embed.set_thumbnail(url=member.display_avatar.url)
1213
await channel.send(embed=embed)
1214
1215
# Dispatch custom events
1216
def check_level_up(member, xp):
1217
old_level = calculate_level(member.old_xp) # Your level calculation
1218
new_level = calculate_level(xp)
1219
1220
if new_level > old_level:
1221
bot.dispatch('level_up', member, old_level, new_level)
1222
1223
# Event filtering and conditions
1224
@bot.event
1225
async def on_message(message):
1226
# Only process messages in specific channels
1227
if message.channel.name not in ['general', 'bot-commands']:
1228
return
1229
1230
# Ignore bot messages
1231
if message.author.bot:
1232
return
1233
1234
# Custom processing
1235
await process_xp(message.author, 10) # Give XP
1236
await bot.process_commands(message)
1237
1238
# Wait for specific events
1239
async def wait_for_confirmation(ctx, timeout=30):
1240
"""Wait for user confirmation."""
1241
def check(reaction, user):
1242
return (user == ctx.author and
1243
str(reaction.emoji) in ['β ', 'β'] and
1244
reaction.message.id == ctx.message.id)
1245
1246
try:
1247
reaction, user = await bot.wait_for('reaction_add', timeout=timeout, check=check)
1248
return str(reaction.emoji) == 'β '
1249
except asyncio.TimeoutError:
1250
return False
1251
1252
# Advanced event handling with error recovery
1253
@bot.event
1254
async def on_error(event, *args, **kwargs):
1255
"""Handle errors in event handlers."""
1256
import traceback
1257
1258
print(f'Error in event {event}:')
1259
traceback.print_exc()
1260
1261
# Log to error channel
1262
error_channel = bot.get_channel(ERROR_CHANNEL_ID)
1263
if error_channel:
1264
error_embed = disnake.Embed(
1265
title=f"Error in {event}",
1266
description=f"```py\n{traceback.format_exc()[:1900]}\n```",
1267
color=0xff0000,
1268
timestamp=disnake.utils.utcnow()
1269
)
1270
await error_channel.send(embed=error_embed)
1271
1272
# Rate limiting and event throttling
1273
from collections import defaultdict, deque
1274
import time
1275
1276
event_buckets = defaultdict(lambda: deque())
1277
1278
async def throttled_event_handler(event_name, handler, *args, **kwargs):
1279
"""Throttle event handlers to prevent spam."""
1280
now = time.time()
1281
bucket = event_buckets[event_name]
1282
1283
# Remove old entries (older than 1 minute)
1284
while bucket and bucket[0] < now - 60:
1285
bucket.popleft()
1286
1287
# Check rate limit (max 10 events per minute)
1288
if len(bucket) >= 10:
1289
print(f"Rate limited event: {event_name}")
1290
return
1291
1292
bucket.append(now)
1293
await handler(*args, **kwargs)
1294
```
1295
1296
### Gateway Connection Management
1297
1298
```python
1299
import disnake
1300
import asyncio
1301
1302
# Custom gateway configuration
1303
class CustomBot(disnake.Client):
1304
def __init__(self, **kwargs):
1305
# Configure intents
1306
intents = disnake.Intents.default()
1307
intents.message_content = True
1308
intents.members = True
1309
intents.presences = True
1310
1311
super().__init__(
1312
intents=intents,
1313
heartbeat_timeout=60.0,
1314
guild_ready_timeout=2.0,
1315
max_messages=1000,
1316
**kwargs
1317
)
1318
1319
async def on_connect(self):
1320
"""Called when bot connects to gateway."""
1321
print("Connected to Discord gateway")
1322
1323
async def on_disconnect(self):
1324
"""Called when bot disconnects from gateway."""
1325
print("Disconnected from Discord gateway")
1326
1327
async def on_resumed(self):
1328
"""Called when connection is resumed."""
1329
print("Connection resumed")
1330
1331
async def setup_hook(self):
1332
"""Called during bot setup."""
1333
print("Setting up bot...")
1334
# Add any async setup code here
1335
1336
# Sync commands on startup
1337
if hasattr(self, 'sync_commands'):
1338
await self.sync_commands()
1339
1340
# Connection retry logic
1341
async def run_bot_with_retry(bot, token, max_retries=5):
1342
"""Run bot with automatic reconnection."""
1343
for attempt in range(max_retries):
1344
try:
1345
await bot.start(token)
1346
break
1347
except (disnake.ConnectionClosed, disnake.GatewayNotFound) as e:
1348
print(f"Connection failed (attempt {attempt + 1}/{max_retries}): {e}")
1349
if attempt < max_retries - 1:
1350
wait_time = 2 ** attempt # Exponential backoff
1351
print(f"Retrying in {wait_time} seconds...")
1352
await asyncio.sleep(wait_time)
1353
else:
1354
print("Max retries exceeded. Bot failed to connect.")
1355
raise
1356
1357
# Shard-aware event handling
1358
class ShardedBot(commands.AutoShardedBot):
1359
def __init__(self, **kwargs):
1360
super().__init__(**kwargs)
1361
1362
async def on_shard_connect(self, shard_id):
1363
print(f"Shard {shard_id} connected")
1364
1365
async def on_shard_disconnect(self, shard_id):
1366
print(f"Shard {shard_id} disconnected")
1367
1368
async def on_shard_ready(self, shard_id):
1369
print(f"Shard {shard_id} is ready")
1370
shard = self.get_shard(shard_id)
1371
print(f"Shard {shard_id} latency: {shard.latency * 1000:.2f}ms")
1372
1373
async def on_shard_resumed(self, shard_id):
1374
print(f"Shard {shard_id} resumed connection")
1375
1376
# Usage
1377
if __name__ == "__main__":
1378
bot = CustomBot()
1379
1380
# Run with retry logic
1381
asyncio.run(run_bot_with_retry(bot, 'YOUR_BOT_TOKEN'))
1382
```