diff --git a/DiscordLab.Bot/Client.cs b/DiscordLab.Bot/Client.cs index fca8fe8..eb21b2b 100644 --- a/DiscordLab.Bot/Client.cs +++ b/DiscordLab.Bot/Client.cs @@ -1,5 +1,4 @@ // ReSharper disable MemberCanBePrivate.Global - namespace DiscordLab.Bot; using System.Net; @@ -16,7 +15,6 @@ namespace DiscordLab.Bot; using DiscordLab.Bot.API.Features; using LabApi.Features.Console; using NorthwoodLib.Pools; - /// /// The Discord bot client. /// @@ -26,39 +24,25 @@ public static class Client /// Gets the websocket client for the Discord bot. /// public static DiscordSocketClient SocketClient { get; private set; } = null!; - - /// + /// /// Gets a value indicating whether the client is in the ready state. /// public static bool IsClientReady { get; private set; } - /// /// Gets a list of saved text channels listed by their ID. /// public static Dictionary SavedTextChannels { get; private set; } = new(); - /// /// Gets the default guild for the plugin. /// public static SocketGuild? DefaultGuild { get; private set; } private static Config Config => Plugin.Instance.Config; + - /// - /// Gets a cached guild from a ID. - /// - /// The guild ID. - /// If the ID is 0, then the default guild (if it exists), if else then it will return the found guild, or null. public static SocketGuild? GetGuild(ulong id) - { - return id == 0 ? DefaultGuild : SocketClient.GetGuild(id); - } + => id == 0 ? DefaultGuild : SocketClient.GetGuild(id); - /// - /// Gets or adds a channel via its ID. Uses cache. - /// - /// The ID of the channel. - /// The channel, if found. public static SocketTextChannel? GetOrAddChannel(ulong id) { if (id == 0) @@ -67,8 +51,7 @@ public static class Client if (SavedTextChannels.TryGetValue(id, out SocketTextChannel ret)) return ret; - SocketChannel channel = SocketClient.GetChannel(id); - if (channel is not SocketTextChannel text) + if (SocketClient.GetChannel(id) is not SocketTextChannel text) return null; SavedTextChannels.Add(id, text); @@ -76,27 +59,18 @@ public static class Client } #nullable disable - /// - /// Tries to get or add a channel via its ID. Uses cache. - /// - /// The ID of the channel. - /// The channel, if found. - /// Whether the channel was found. public static bool TryGetOrAddChannel(ulong id, out SocketTextChannel channel) { channel = GetOrAddChannel(id); - return channel != null; } #nullable restore - /// - /// Starts the bot. - /// [CallOnLoad] internal static void Start() { DebugLog("Starting the Client"); + DiscordSocketConfig config = new() { GatewayIntents = GatewayIntents.All, @@ -113,42 +87,41 @@ internal static void Start() config.WebSocketProvider = DefaultWebSocketProvider.Create(proxy); } - DebugLog("Done the initial setup..."); - try { SocketClient = new(config); - DebugLog("Client has been created..."); - SocketClient.Log += OnLog; SocketClient.Ready += OnReady; SocketClient.SlashCommandExecuted += SlashCommandHandler; SocketClient.AutocompleteExecuted += AutocompleteHandler; + + // =============================== + // Privileged intent listeners + // =============================== + SocketClient.PresenceUpdated += OnPresenceUpdated; + + SocketClient.GuildScheduledEventCreated += _ => Task.CompletedTask; + SocketClient.GuildScheduledEventUpdated += (_, _) => Task.CompletedTask; + SocketClient.GuildScheduledEventDeleted += _ => Task.CompletedTask; + + SocketClient.InviteCreated += _ => Task.CompletedTask; + SocketClient.InviteDeleted += _ => Task.CompletedTask; } catch (TargetInvocationException ex) when (ex.InnerException is TypeLoadException) { StringBuilder builder = StringBuilderPool.Shared.Rent(); builder.AppendLine("You may have setup DiscordLab incorrectly, or used another Discord bot in the past."); - builder.AppendLine( - "Please ensure you have no conflicting dependencies. This can either be triggered by duplication of the Discord dependencies, or Newtonsoft.Json."); - builder.AppendLine( - "Some plugins might implement either of the 2 listed dependencies above, so if you have no duplications at all, you will manually need to remove plugins to see the culprit."); - builder.AppendLine( - "If you find a plugin that doesn't work with DiscordLab, please join our Discord and report it there with a link to the repository. We can not fix private plugins."); + builder.AppendLine("Please ensure you have no conflicting dependencies (Discord or Newtonsoft.Json)."); + builder.AppendLine("If you find a conflicting plugin, report it with a repository link."); builder.AppendLine("Discord link: https://discord.gg/XBzuGbsNZK"); Logger.Error(StringBuilderPool.Shared.ToStringReturn(builder)); throw; } - DebugLog("Client events subscribed..."); - Task.RunAndLog(StartClient); } - /// - /// Disables the bot. - /// [CallOnUnload] internal static void Disable() { @@ -158,6 +131,8 @@ internal static void Disable() SocketClient.Ready -= OnReady; SocketClient.SlashCommandExecuted -= SlashCommandHandler; SocketClient.AutocompleteExecuted -= AutocompleteHandler; + SocketClient.PresenceUpdated -= OnPresenceUpdated; + Task.RunAndLog(async () => { await SocketClient.LogoutAsync(); @@ -178,29 +153,30 @@ private static Task OnLog(LogMessage msg) switch (msg.Exception) { case WebSocketException { InnerException: WebSocketClosedException { CloseCode: 4014 } }: - Logger.Error("DiscordLab requires that you have all Privileged Gateway Intents enabled, you can do this in the \"Bot\" panel of your application. Restart your server when this is complete."); + Logger.Error("Privileged Gateway Intents are not enabled in the Discord Developer Portal."); return Task.CompletedTask; + case WebSocketException or GatewayReconnectException when !Config.Debug: return Task.CompletedTask; - default: - switch (msg.Severity) - { - case LogSeverity.Error or LogSeverity.Critical: - Logger.Error(msg); - break; - case LogSeverity.Warning: - Logger.Warn(msg); - break; - case LogSeverity.Debug: - DebugLog(msg); - break; - default: - Logger.Info(msg); - break; - } + } - return Task.CompletedTask; + switch (msg.Severity) + { + case LogSeverity.Error or LogSeverity.Critical: + Logger.Error(msg); + break; + case LogSeverity.Warning: + Logger.Warn(msg); + break; + case LogSeverity.Debug: + DebugLog(msg); + break; + default: + Logger.Info(msg); + break; } + + return Task.CompletedTask; } private static Task OnReady() @@ -211,30 +187,20 @@ private static Task OnReady() CallOnReadyAttribute.Ready(); if (Config.Debug) - { DebugLog(string.Join("\n", SocketClient.Guilds.Select(GenerateGuildChannelsMessage))); - } return Task.CompletedTask; } - private static string GenerateGuildChannelsMessage(SocketGuild guild) => - $"Guild {guild.Name} ({guild.Id}) channels: {string.Join("\n", guild.Channels.Where(channel => channel is SocketTextChannel).Select(GenerateChannelMessage))}"; - - private static string GenerateChannelMessage(SocketGuildChannel channel) => $"{channel.Name} ({channel.Id})"; - private static Task SlashCommandHandler(SocketSlashCommand command) { - DebugLog($"{command.Data.Name} requested a response, finding the command..."); SlashCommand? cmd = SlashCommand.Commands.FirstOrDefault(c => c.Data.Name == command.Data.Name); - cmd?.Run(command); return Task.CompletedTask; } private static Task AutocompleteHandler(SocketAutocompleteInteraction autocomplete) { - DebugLog($"{autocomplete.Data.CommandName} requested a response, finding the command..."); AutocompleteCommand? command = SlashCommand.Commands.FirstOrDefault(c => c is AutocompleteCommand cmd && cmd.Data.Name == autocomplete.Data.CommandName) as AutocompleteCommand; @@ -243,8 +209,18 @@ private static Task AutocompleteHandler(SocketAutocompleteInteraction autocomple return Task.CompletedTask; } - private static void DebugLog(object message) + private static Task OnPresenceUpdated( + SocketUser user, + SocketPresence before, + SocketPresence after) { - Logger.Debug(message, Config.Debug); + return Task.CompletedTask; } -} \ No newline at end of file + + private static string GenerateGuildChannelsMessage(SocketGuild guild) => + $"Guild {guild.Name} ({guild.Id}) channels:\n" + + string.Join("\n", guild.Channels.OfType().Select(c => $"{c.Name} ({c.Id})")); + + private static void DebugLog(object message) + => Logger.Debug(message, Config.Debug); +}