From 4d318356f02624d80262c05b7d3335592f01dcf1 Mon Sep 17 00:00:00 2001 From: Paulo Date: Sat, 23 May 2020 23:58:15 -0300 Subject: [PATCH] Fix Ready and AlwaysDownloadUsers Ready could fire before downloading all guild data and downloading guild users one guild per time without gateway intents is a waste of a gateway request that can support up to 1000. --- .../DiscordSocketClient.Events.cs | 7 ++++- .../DiscordSocketClient.cs | 9 ++++--- .../DiscordSocketConfig.cs | 26 +++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs index 51dea5f9f..4bbeea297 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs @@ -21,7 +21,12 @@ namespace Discord.WebSocket remove { _disconnectedEvent.Remove(value); } } private readonly AsyncEvent> _disconnectedEvent = new AsyncEvent>(); - /// Fired when guild data has finished downloading. + /// + /// Fired when guild data has finished downloading. + /// + /// + /// It is possible that some guilds might be unsynced if was not long enough to receive all GUILD_AVAILABLES before READY. + /// public event Func Ready { add { _readyEvent.Add(value); } diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index b56498061..c7a49436b 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -167,7 +167,7 @@ namespace Discord.WebSocket GuildAvailable += g => { - if (ConnectionState == ConnectionState.Connected && AlwaysDownloadUsers && !g.HasAllMembers) + if (_guildDownloadTask?.IsCompleted == true && ConnectionState == ConnectionState.Connected && AlwaysDownloadUsers && !g.HasAllMembers) { var _ = g.DownloadUsersAsync(); } @@ -368,7 +368,7 @@ namespace Discord.WebSocket { var cachedGuilds = guilds.ToImmutableArray(); - const short batchSize = 50; + const short batchSize = 1000; //TODO: Gateway Intents will limit to a maximum of 1 guild_id ulong[] batchIds = new ulong[Math.Min(batchSize, cachedGuilds.Length)]; Task[] batchTasks = new Task[batchIds.Length]; int batchCount = (cachedGuilds.Length + (batchSize - 1)) / batchSize; @@ -576,6 +576,9 @@ namespace Discord.WebSocket } else if (_connection.CancelToken.IsCancellationRequested) return; + + if (BaseConfig.AlwaysDownloadUsers) + _ = DownloadUsersAsync(Guilds.Where(x => x.IsAvailable && !x.HasAllMembers)); await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false); await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false); @@ -1742,7 +1745,7 @@ namespace Discord.WebSocket try { await logger.DebugAsync("GuildDownloader Started").ConfigureAwait(false); - while ((_unavailableGuildCount != 0) && (Environment.TickCount - _lastGuildAvailableTime < 2000)) + while ((_unavailableGuildCount != 0) && (Environment.TickCount - _lastGuildAvailableTime < BaseConfig.MaxWaitBetweenGuildAvailablesBeforeReady)) await Task.Delay(500, cancelToken).ConfigureAwait(false); await logger.DebugAsync("GuildDownloader Stopped").ConfigureAwait(false); } diff --git a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs index 98ab0ef9b..5b9d68619 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs @@ -124,6 +124,32 @@ namespace Discord.WebSocket /// public bool GuildSubscriptions { get; set; } = true; + /// + /// Gets or sets the maximum wait time in milliseconds between GUILD_AVAILABLE events before firing READY. + /// + /// If zero, READY will fire as soon as it is received and all guilds will be unavailable. + /// + /// + /// This property is measured in milliseconds, negative values will throw an exception. + /// If a guild is not received before READY, it will be unavailable. + /// + /// + /// The maximum wait time in milliseconds between GUILD_AVAILABLE events before firing READY. + /// + /// Value must be at least 0. + public int MaxWaitBetweenGuildAvailablesBeforeReady { + get + { + return _maxWaitForGuildAvailable; + } + set + { + Preconditions.AtLeast(value, 0, nameof(MaxWaitBetweenGuildAvailablesBeforeReady)); + _maxWaitForGuildAvailable = value; + } + } + private int _maxWaitForGuildAvailable = 10000; + /// /// Initializes a default configuration. ///