From fd72583a75a1c9ccc1f6040c8611d20c58513e4a Mon Sep 17 00:00:00 2001 From: RogueException Date: Sat, 1 Apr 2017 15:05:51 -0300 Subject: [PATCH] Move guild presence updates to GuildMemberUpdated. Filter duplicate UserUpdated events. --- .../API/Common/GuildMember.cs | 6 ++-- .../Entities/Users/RestGuildUser.cs | 9 ++++-- .../DiscordSocketClient.cs | 30 ++++++++++++++----- .../Entities/Guilds/SocketGuild.cs | 6 ++-- .../Entities/Users/SocketGuildUser.cs | 16 ++++++---- .../Entities/Users/SocketSelfUser.cs | 15 ++++++++-- .../Entities/Users/SocketUnknownUser.cs | 13 -------- .../Entities/Users/SocketUser.cs | 30 +++++++++++++++---- .../Entities/Users/SocketWebhookUser.cs | 13 -------- 9 files changed, 81 insertions(+), 57 deletions(-) diff --git a/src/Discord.Net.Rest/API/Common/GuildMember.cs b/src/Discord.Net.Rest/API/Common/GuildMember.cs index daba36d23..24ad17c14 100644 --- a/src/Discord.Net.Rest/API/Common/GuildMember.cs +++ b/src/Discord.Net.Rest/API/Common/GuildMember.cs @@ -11,12 +11,12 @@ namespace Discord.API [JsonProperty("nick")] public Optional Nick { get; set; } [JsonProperty("roles")] - public ulong[] Roles { get; set; } + public Optional Roles { get; set; } [JsonProperty("joined_at")] public Optional JoinedAt { get; set; } [JsonProperty("deaf")] - public bool Deaf { get; set; } + public Optional Deaf { get; set; } [JsonProperty("mute")] - public bool Mute { get; set; } + public Optional Mute { get; set; } } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index 538f6b80f..f6db057f2 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -50,9 +50,12 @@ namespace Discord.Rest _joinedAtTicks = model.JoinedAt.Value.UtcTicks; if (model.Nick.IsSpecified) Nickname = model.Nick.Value; - IsDeafened = model.Deaf; - IsMuted = model.Mute; - UpdateRoles(model.Roles); + if (model.Deaf.IsSpecified) + IsDeafened = model.Deaf.Value; + if (model.Mute.IsSpecified) + IsMuted = model.Mute.Value; + if (model.Roles.IsSpecified) + UpdateRoles(model.Roles.Value); } private void UpdateRoles(ulong[] roleIds) { diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 849a0ad65..64aa2d272 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -1336,14 +1336,30 @@ namespace Discord.WebSocket var user = guild.GetUser(data.User.Id); if (user == null) - guild.AddOrUpdateUser(data); + user = guild.AddOrUpdateUser(data); + else + { + var globalBefore = user.GlobalUser.Clone(); + if (user.GlobalUser.Update(State, data.User)) + { + //Global data was updated, trigger UserUpdated + await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), globalBefore, user).ConfigureAwait(false); + } + } + + var before = user.Clone(); + user.Update(State, data, true); + await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), before, user).ConfigureAwait(false); + } + else + { + //TODO: Add as part of friends list update + /*var globalUser = GetOrCreateUser(State, data.User); + var before = globalUser.Clone(); + globalUser.Update(State, data.User); + globalUser.Update(State, data); + await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), before, globalUser).ConfigureAwait(false);*/ } - - var globalUser = GetOrCreateUser(State, data.User); //TODO: Memory leak, users removed from friends list will never RemoveRef. - var before = globalUser.Clone(); - globalUser.Update(State, data); - - await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), before, globalUser).ConfigureAwait(false); } break; case "TYPING_START": diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index e261d118f..04a94b421 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -163,7 +163,7 @@ namespace Discord.WebSocket { SocketGuildUser member; if (members.TryGetValue(model.Presences[i].User.Id, out member)) - member.Update(state, model.Presences[i]); + member.Update(state, model.Presences[i], true); else Debug.Assert(false); } @@ -249,7 +249,7 @@ namespace Discord.WebSocket { SocketGuildUser member; if (members.TryGetValue(model.Presences[i].User.Id, out member)) - member.Update(state, model.Presences[i]); + member.Update(state, model.Presences[i], true); else Debug.Assert(false); } @@ -392,7 +392,7 @@ namespace Discord.WebSocket { SocketGuildUser member; if (_members.TryGetValue(model.User.Id, out member)) - member.Update(Discord.State, model); + member.Update(Discord.State, model, false); else { member = SocketGuildUser.Create(this, Discord.State, model); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index d20fd0d33..58d2a0b8d 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -26,7 +26,7 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get { return GlobalUser.DiscriminatorValue; } internal set { GlobalUser.DiscriminatorValue = value; } } public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } public GuildPermissions GuildPermissions => new GuildPermissions(Permissions.ResolveGuild(Guild, this)); - internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } + internal override SocketPresence Presence { get; set; } public override bool IsWebhook => false; public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; @@ -78,7 +78,7 @@ namespace Discord.WebSocket internal static SocketGuildUser Create(SocketGuild guild, ClientState state, PresenceModel model) { var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User)); - entity.Update(state, model); + entity.Update(state, model, false); return entity; } internal void Update(ClientState state, Model model) @@ -88,15 +88,19 @@ namespace Discord.WebSocket _joinedAtTicks = model.JoinedAt.Value.UtcTicks; if (model.Nick.IsSpecified) Nickname = model.Nick.Value; - UpdateRoles(model.Roles); + if (model.Roles.IsSpecified) + UpdateRoles(model.Roles.Value); } internal override void Update(ClientState state, PresenceModel model) + => Update(state, model, true); + internal void Update(ClientState state, PresenceModel model, bool updatePresence) { - base.Update(state, model); - if (model.Roles.IsSpecified) - UpdateRoles(model.Roles.Value); + if (updatePresence) + base.Update(state, model); if (model.Nick.IsSpecified) Nickname = model.Nick.Value; + if (model.Roles.IsSpecified) + UpdateRoles(model.Roles.Value); } private void UpdateRoles(ulong[] roleIds) { diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs index c0e483a56..b7c02c2db 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs @@ -33,16 +33,25 @@ namespace Discord.WebSocket entity.Update(state, model); return entity; } - internal override void Update(ClientState state, Model model) + internal override bool Update(ClientState state, Model model) { - base.Update(state, model); - + bool hasGlobalChanges = base.Update(state, model); if (model.Email.IsSpecified) + { Email = model.Email.Value; + hasGlobalChanges = true; + } if (model.Verified.IsSpecified) + { IsVerified = model.Verified.Value; + hasGlobalChanges = true; + } if (model.MfaEnabled.IsSpecified) + { IsMfaEnabled = model.MfaEnabled.Value; + hasGlobalChanges = true; + } + return hasGlobalChanges; } public Task ModifyAsync(Action func, RequestOptions options = null) diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs index 57ff81433..c7f6cb846 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using Model = Discord.API.User; -using PresenceModel = Discord.API.Presence; namespace Discord.WebSocket { @@ -29,18 +28,6 @@ namespace Discord.WebSocket return entity; } - internal override void Update(ClientState state, PresenceModel model) - { - if (model.User.Avatar.IsSpecified) - AvatarId = model.User.Avatar.Value; - if (model.User.Discriminator.IsSpecified) - DiscriminatorValue = ushort.Parse(model.User.Discriminator.Value); - if (model.User.Bot.IsSpecified) - IsBot = model.User.Bot.Value; - if (model.User.Username.IsSpecified) - Username = model.User.Username.Value; - } - internal new SocketUnknownUser Clone() => MemberwiseClone() as SocketUnknownUser; } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs index 6e97d4b31..12f1b2b30 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs @@ -26,21 +26,39 @@ namespace Discord.WebSocket : base(discord, id) { } - internal virtual void Update(ClientState state, Model model) + internal virtual bool Update(ClientState state, Model model) { - if (model.Avatar.IsSpecified) + bool hasChanges = false; + if (model.Avatar.IsSpecified && model.Avatar.Value != AvatarId) + { AvatarId = model.Avatar.Value; + hasChanges = true; + } if (model.Discriminator.IsSpecified) - DiscriminatorValue = ushort.Parse(model.Discriminator.Value); - if (model.Bot.IsSpecified) + { + var newVal = ushort.Parse(model.Discriminator.Value); + if (newVal != DiscriminatorValue) + { + DiscriminatorValue = ushort.Parse(model.Discriminator.Value); + hasChanges = true; + } + } + if (model.Bot.IsSpecified && model.Bot.Value != IsBot) + { IsBot = model.Bot.Value; - if (model.Username.IsSpecified) + hasChanges = true; + } + if (model.Username.IsSpecified && model.Username.Value != Username) + { Username = model.Username.Value; + hasChanges = true; + } + return hasChanges; } internal virtual void Update(ClientState state, PresenceModel model) { Presence = SocketPresence.Create(model); - Update(state, model.User); + //Update(state, model.User); } public Task CreateDMChannelAsync(RequestOptions options = null) diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs index 1193eca8f..c34f866cb 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Threading.Tasks; using Model = Discord.API.User; -using PresenceModel = Discord.API.Presence; namespace Discord.WebSocket { @@ -36,18 +35,6 @@ namespace Discord.WebSocket return entity; } - internal override void Update(ClientState state, PresenceModel model) - { - if (model.User.Avatar.IsSpecified) - AvatarId = model.User.Avatar.Value; - if (model.User.Discriminator.IsSpecified) - DiscriminatorValue = ushort.Parse(model.User.Discriminator.Value); - if (model.User.Bot.IsSpecified) - IsBot = model.User.Bot.Value; - if (model.User.Username.IsSpecified) - Username = model.User.Username.Value; - } - internal new SocketWebhookUser Clone() => MemberwiseClone() as SocketWebhookUser;