@@ -11,12 +11,12 @@ namespace Discord.API | |||
[JsonProperty("nick")] | |||
public Optional<string> Nick { get; set; } | |||
[JsonProperty("roles")] | |||
public ulong[] Roles { get; set; } | |||
public Optional<ulong[]> Roles { get; set; } | |||
[JsonProperty("joined_at")] | |||
public Optional<DateTimeOffset> JoinedAt { get; set; } | |||
[JsonProperty("deaf")] | |||
public bool Deaf { get; set; } | |||
public Optional<bool> Deaf { get; set; } | |||
[JsonProperty("mute")] | |||
public bool Mute { get; set; } | |||
public Optional<bool> Mute { get; set; } | |||
} | |||
} |
@@ -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) | |||
{ | |||
@@ -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": | |||
@@ -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); | |||
@@ -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) | |||
{ | |||
@@ -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<SelfUserProperties> func, RequestOptions options = null) | |||
@@ -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; | |||
} | |||
} |
@@ -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<RestDMChannel> CreateDMChannelAsync(RequestOptions options = null) | |||
@@ -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; | |||