diff --git a/src/Discord.Net/DiscordClient.Channels.cs b/src/Discord.Net/DiscordClient.Channels.cs index d3c83733f..fb7c769a6 100644 --- a/src/Discord.Net/DiscordClient.Channels.cs +++ b/src/Discord.Net/DiscordClient.Channels.cs @@ -132,7 +132,7 @@ namespace Discord Channel channel = null; if (user != null) - channel = user.GlobalUser.PrivateChannel; + channel = user.Global.PrivateChannel; if (channel == null) { var response = await _api.CreatePMChannel(_userId.Value, user.Id).ConfigureAwait(false); diff --git a/src/Discord.Net/DiscordClient.Users.cs b/src/Discord.Net/DiscordClient.Users.cs index dc2b5aa4c..e58fce432 100644 --- a/src/Discord.Net/DiscordClient.Users.cs +++ b/src/Discord.Net/DiscordClient.Users.cs @@ -134,7 +134,7 @@ namespace Discord private User _privateUser; /// Returns information about the currently logged-in account. - public GlobalUser CurrentUser => _privateUser.GlobalUser; + public GlobalUser CurrentUser => _privateUser.Global; /// Returns a collection of all unique users this client can currently see. public IEnumerable AllUsers => _globalUsers; @@ -275,7 +275,7 @@ namespace Discord CheckReady(); return _api.EditUser(currentPassword: currentPassword, - username: username ?? _privateUser?.Name, email: email ?? _privateUser?.GlobalUser.Email, password: password, + username: username ?? _privateUser?.Name, email: email ?? _privateUser?.Global.Email, password: password, avatarType: avatarType, avatar: avatar); } diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index 5742c29fc..253ba5aa7 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -314,7 +314,7 @@ namespace Discord var data = e.Payload.ToObject(_serializer); _privateUser = _users.GetOrAdd(data.User.Id, null); _privateUser.Update(data.User); - _privateUser.GlobalUser.Update(data.User); + _privateUser.Global.Update(data.User); foreach (var model in data.Guilds) { if (model.Unavailable != true) diff --git a/src/Discord.Net/Models/Channel.cs b/src/Discord.Net/Models/Channel.cs index d66d9739b..ce9db815b 100644 --- a/src/Discord.Net/Models/Channel.cs +++ b/src/Discord.Net/Models/Channel.cs @@ -50,13 +50,18 @@ namespace Discord /// Returns the server containing this channel. [JsonIgnore] public Server Server => _server.Value; + [JsonProperty] + private long? ServerId { get { return _server.Id; } set { _server.Id = value; } } private readonly Reference _server; /// For private chats, returns the target user, otherwise null. [JsonIgnore] public User Recipient => _recipient.Value; - private readonly Reference _recipient; - + [JsonProperty] + private long? RecipientId { get { return _recipient.Id; } set { _recipient.Id = value; } } + private readonly Reference _recipient; + + //Collections /// Returns a collection of all users with read access to this channel. [JsonIgnore] public IEnumerable Members @@ -66,20 +71,23 @@ namespace Discord if (Type == ChannelType.Text) return _members.Values.Where(x => x.Permissions.ReadMessages == true).Select(x => x.User); else if (Type == ChannelType.Voice) - return Server.Members.Where(x => x.VoiceChannel == this); + return _members.Values.Select(x => x.User).Where(x => x.VoiceChannel == this); else return Enumerable.Empty(); } } + [JsonProperty] + private IEnumerable MemberIds => Members.Select(x => x.Id); private ConcurrentDictionary _members; /// Returns a collection of all messages the client has seen posted in this channel. This collection does not guarantee any ordering. [JsonIgnore] public IEnumerable Messages => _messages?.Values ?? Enumerable.Empty(); + [JsonProperty] + private IEnumerable MessageIds => Messages.Select(x => x.Id); private readonly ConcurrentDictionary _messages; /// Returns a collection of all custom permissions used for this channel. - private static readonly PermissionOverwrite[] _initialPermissionsOverwrites = new PermissionOverwrite[0]; private PermissionOverwrite[] _permissionOverwrites; public IEnumerable PermissionOverwrites { get { return _permissionOverwrites; } internal set { _permissionOverwrites = value.ToArray(); } } @@ -96,14 +104,14 @@ namespace Discord { Name = "@" + x.Name; if (_server.Id == null) - x.GlobalUser.PrivateChannel = this; + x.Global.PrivateChannel = this; }, x => { if (_server.Id == null) - x.GlobalUser.PrivateChannel = null; + x.Global.PrivateChannel = null; }); - _permissionOverwrites = _initialPermissionsOverwrites; + _permissionOverwrites = new PermissionOverwrite[0]; _members = new ConcurrentDictionary(); if (recipientId != null) diff --git a/src/Discord.Net/Models/GlobalUser.cs b/src/Discord.Net/Models/GlobalUser.cs index bffc837e9..f43fef90b 100644 --- a/src/Discord.Net/Models/GlobalUser.cs +++ b/src/Discord.Net/Models/GlobalUser.cs @@ -8,7 +8,6 @@ namespace Discord { public sealed class GlobalUser : CachedObject { - private readonly ConcurrentDictionary _users; /// Returns the email for this user. Note: this field is only ever populated for the current logged in user. [JsonIgnore] @@ -19,7 +18,7 @@ namespace Discord /// Returns the private messaging channel with this user, if one exists. [JsonIgnore] - internal Channel PrivateChannel + public Channel PrivateChannel { get { return _privateChannel; } set @@ -29,11 +28,16 @@ namespace Discord CheckUser(); } } - private Channel _privateChannel; + [JsonProperty] + private long? PrivateChannelId => _privateChannel?.Id; + private Channel _privateChannel; /// Returns a collection of all server-specific data for every server this user is a member of. [JsonIgnore] public IEnumerable Memberships => _users.Select(x => x.Value); + [JsonProperty] + private IEnumerable ServerIds => _users.Select(x => x.Key); + private readonly ConcurrentDictionary _users; internal GlobalUser(DiscordClient client, long id) : base(client, id) diff --git a/src/Discord.Net/Models/Message.cs b/src/Discord.Net/Models/Message.cs index 5f23ecea6..a478964e2 100644 --- a/src/Discord.Net/Models/Message.cs +++ b/src/Discord.Net/Models/Message.cs @@ -94,6 +94,8 @@ namespace Discord /// Returns true if the logged-in user was mentioned. /// This is not set to true if the user was mentioned with @everyone (see IsMentioningEverone). public bool IsMentioningMe { get; private set; } + /// Returns true if the current user created this message. + public bool IsAuthor => _client.CurrentUserId == _user.Id; /// Returns true if the message was sent as text-to-speech by someone with permissions to do so. public bool IsTTS { get; private set; } /// Returns true if the message is still in the outgoing message queue. @@ -118,28 +120,49 @@ namespace Discord /// Returns a collection of all users mentioned in this message. [JsonIgnore] public IEnumerable MentionedUsers { get; internal set; } + [JsonProperty] + private IEnumerable MentionedUserIds + { + get { return MentionedUsers.Select(x => x.Id); } + set { MentionedUsers = value.Select(x => _client.GetUser(Server, x)).Where(x => x != null); } + } /// Returns a collection of all channels mentioned in this message. [JsonIgnore] public IEnumerable MentionedChannels { get; internal set; } + [JsonProperty] + private IEnumerable MentionedChannelIds + { + get { return MentionedChannels.Select(x => x.Id); } + set { MentionedChannels = value.Select(x => _client.GetChannel(x)).Where(x => x != null); } + } /// Returns a collection of all roles mentioned in this message. [JsonIgnore] public IEnumerable MentionedRoles { get; internal set; } + [JsonProperty] + private IEnumerable MentionedRoleIds + { + get { return MentionedRoles.Select(x => x.Id); } + set { MentionedRoles = value.Select(x => _client.GetRole(x)).Where(x => x != null); } + } /// Returns the server containing the channel this message was sent to. [JsonIgnore] public Server Server => _channel.Value.Server; + /// Returns the channel this message was sent to. [JsonIgnore] public Channel Channel => _channel.Value; + [JsonProperty] + private long? ChannelId { get { return _channel.Id; } set { _channel.Id = value; } } private readonly Reference _channel; - /// Returns true if the current user created this message. - public bool IsAuthor => _client.CurrentUserId == _user.Id; /// Returns the author of this message. [JsonIgnore] public User User => _user.Value; + [JsonProperty] + private long? UserId { get { return _user.Id; } set { _user.Id = value; } } private readonly Reference _user; internal Message(DiscordClient client, long id, long channelId, long userId) diff --git a/src/Discord.Net/Models/Role.cs b/src/Discord.Net/Models/Role.cs index 172317799..420edec27 100644 --- a/src/Discord.Net/Models/Role.cs +++ b/src/Discord.Net/Models/Role.cs @@ -24,13 +24,18 @@ namespace Discord /// Returns the server this role is a member of. [JsonIgnore] public Server Server => _server.Value; + [JsonProperty] + private long? ServerId { get { return _server.Id; } set { _server.Id = value; } } private readonly Reference _server; /// Returns true if this is the role representing all users in a server. public bool IsEveryone => _server.Id == null || Id == _server.Id; + /// Returns a list of all members in this role. [JsonIgnore] public IEnumerable Members => _server.Id != null ? (IsEveryone ? Server.Members : Server.Members.Where(x => x.HasRole(this))) : new User[0]; + [JsonProperty] + private IEnumerable MemberIds => Members.Select(x => x.Id); //TODO: Add local members cache internal Role(DiscordClient client, long id, long serverId) diff --git a/src/Discord.Net/Models/Server.cs b/src/Discord.Net/Models/Server.cs index 771513087..231ce537b 100644 --- a/src/Discord.Net/Models/Server.cs +++ b/src/Discord.Net/Models/Server.cs @@ -35,15 +35,20 @@ namespace Discord public string Region { get; private set; } /// Returns true if the current user created this server. - public bool IsOwner => _client.CurrentUserId == _ownerId; + public bool IsOwner => _client.CurrentUserId == _owner.Id; + /// Returns the user that first created this server. [JsonIgnore] - public User Owner { get; private set; } - private long _ownerId; + public User Owner => _owner.Value; + [JsonProperty] + private long? OwnerId => _owner.Id; + private Reference _owner; /// Returns the AFK voice channel for this server (see AFKTimeout). [JsonIgnore] public Channel AFKChannel => _afkChannel.Value; + [JsonProperty] + private long? AFKChannelId => _afkChannel.Id; private Reference _afkChannel; /// Returns the default channel for this server. @@ -51,8 +56,7 @@ namespace Discord public Channel DefaultChannel { get; private set; } /// Returns a collection of the ids of all users banned on this server. - [JsonIgnore] - public IEnumerable Bans => _bans.Select(x => x.Key); + public IEnumerable BannedUsers => _bans.Select(x => x.Key); private ConcurrentDictionary _bans; /// Returns a collection of all channels within this server. @@ -64,11 +68,15 @@ namespace Discord /// Returns a collection of all voice channels within this server. [JsonIgnore] public IEnumerable VoiceChannels => _channels.Select(x => x.Value).Where(x => x.Type == ChannelType.Voice); + [JsonProperty] + private IEnumerable ChannelIds => Channels.Select(x => x.Id); private ConcurrentDictionary _channels; /// Returns a collection of all users within this server with their server-specific data. [JsonIgnore] public IEnumerable Members => _members.Select(x => x.Value.User); + [JsonProperty] + private IEnumerable MemberIds => Members.Select(x => x.Id); private ConcurrentDictionary _members; /// Return the the role representing all users in a server. @@ -77,11 +85,14 @@ namespace Discord /// Returns a collection of all roles within this server. [JsonIgnore] public IEnumerable Roles => _roles.Select(x => x.Value); + [JsonProperty] + private IEnumerable RoleIds => Roles.Select(x => x.Id); private ConcurrentDictionary _roles; internal Server(DiscordClient client, long id) : base(client, id) { + _owner = new Reference(x => _client.Users[x, Id]); _afkChannel = new Reference(x => _client.Channels[x]); //Global Cache @@ -138,11 +149,8 @@ namespace Discord if (model.AFKChannelId != null) if (model.JoinedAt != null) JoinedAt = model.JoinedAt.Value; - if (model.OwnerId != null && _ownerId != model.OwnerId) - { - _ownerId = model.OwnerId.Value; - Owner = _client.Users[_ownerId, Id]; - } + if (model.OwnerId != null) + _owner.Id = model.OwnerId.Value; if (model.Region != null) Region = model.Region; @@ -216,9 +224,6 @@ namespace Discord { if (_members.TryAdd(user.Id, new ServerMember(user))) { - if (user.Id == _ownerId) - Owner = user; - foreach (var channel in TextChannels) channel.AddMember(user); } @@ -228,9 +233,6 @@ namespace Discord ServerMember ignored; if (_members.TryRemove(user.Id, out ignored)) { - if (user.Id == _ownerId) - Owner = null; - foreach (var channel in Channels) channel.RemoveMember(user); } diff --git a/src/Discord.Net/Models/User.cs b/src/Discord.Net/Models/User.cs index ae6355d01..e3bba75b1 100644 --- a/src/Discord.Net/Models/User.cs +++ b/src/Discord.Net/Models/User.cs @@ -1,7 +1,6 @@ using Discord.API; using Newtonsoft.Json; using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -60,25 +59,29 @@ namespace Discord public DateTime? LastOnlineAt => Status != UserStatus.Offline ? DateTime.UtcNow : _lastOnline; private DateTime? _lastOnline; - /// Returns the private messaging channel with this user, if one exists. + //References [JsonIgnore] - public Channel PrivateChannel => GlobalUser.PrivateChannel; - - [JsonIgnore] - internal GlobalUser GlobalUser => _globalUser.Value; + public GlobalUser Global => _globalUser.Value; private readonly Reference _globalUser; [JsonIgnore] public Server Server => _server.Value; private readonly Reference _server; + [JsonProperty] + private long? ServerId { get { return _server.Id; } set { _server.Id = value; } } [JsonIgnore] public Channel VoiceChannel => _voiceChannel.Value; private Reference _voiceChannel; + [JsonProperty] + private long? VoiceChannelId { get { return _voiceChannel.Id; } set { _voiceChannel.Id = value; } } + //Collections [JsonIgnore] public IEnumerable Roles => _roles.Select(x => x.Value); private Dictionary _roles; + [JsonProperty] + private IEnumerable RoleIds => _roles.Select(x => x.Key); /// Returns a collection of all messages this user has sent on this server that are still in cache. [JsonIgnore] @@ -89,7 +92,7 @@ namespace Discord if (_server.Id != null) return Server.Channels.SelectMany(x => x.Messages.Where(y => y.User.Id == Id)); else - return GlobalUser.PrivateChannel.Messages.Where(x => x.User.Id == Id); + return Global.PrivateChannel.Messages.Where(x => x.User.Id == Id); } } @@ -106,7 +109,7 @@ namespace Discord } else { - var privateChannel = PrivateChannel; + var privateChannel = Global.PrivateChannel; if (privateChannel != null) return new Channel[] { privateChannel }; else