diff --git a/src/Discord.Net/API/Common.cs b/src/Discord.Net/API/Common.cs index 4e9723269..0e97c5d70 100644 --- a/src/Discord.Net/API/Common.cs +++ b/src/Discord.Net/API/Common.cs @@ -47,9 +47,9 @@ namespace Discord.API public class ExtendedMemberInfo : MemberInfo { [JsonProperty("mute")] - public bool IsMuted; + public bool? IsMuted; [JsonProperty("deaf")] - public bool IsDeafened; + public bool? IsDeafened; } public class PresenceMemberInfo : MemberReference { @@ -71,9 +71,9 @@ namespace Discord.API [JsonProperty("self_deaf")] public bool? IsSelfDeafened; [JsonProperty("mute")] - public bool IsMuted; + public bool? IsMuted; [JsonProperty("deaf")] - public bool IsDeafened; + public bool? IsDeafened; [JsonProperty("token")] public string Token; } @@ -228,11 +228,11 @@ namespace Discord.API } [JsonProperty("tts")] - public bool IsTextToSpeech; + public bool? IsTextToSpeech; [JsonProperty("mention_everyone")] - public bool IsMentioningEveryone; + public bool? IsMentioningEveryone; [JsonProperty("timestamp")] - public DateTime Timestamp; + public DateTime? Timestamp; [JsonProperty("edited_timestamp")] public DateTime? EditedTimestamp; [JsonProperty("mentions")] @@ -284,16 +284,16 @@ namespace Discord.API public class ExtendedInvite : Invite { [JsonProperty("max_age")] - public int MaxAge; + public int ?MaxAge; [JsonProperty("max_uses")] - public int MaxUses; + public int? MaxUses; [JsonProperty("revoked")] - public bool IsRevoked; + public bool? IsRevoked; [JsonProperty("temporary")] - public bool IsTemporary; + public bool? IsTemporary; [JsonProperty("uses")] - public int Uses; + public int? Uses; [JsonProperty("created_at")] - public DateTime CreatedAt; + public DateTime? CreatedAt; } } diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index 54a8c3118..50fec7cf7 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -368,8 +368,6 @@ namespace Discord } } break; - case "RESUMED": - break; //Servers case "GUILD_CREATE": @@ -678,6 +676,10 @@ namespace Discord } break; + //Internal (handled in DataWebSocket) + case "RESUMED": + break; + //Internal (handled in DiscordSimpleClient) case "VOICE_SERVER_UPDATE": break; diff --git a/src/Discord.Net/Models/Channel.cs b/src/Discord.Net/Models/Channel.cs index f4dbe99f5..491deae11 100644 --- a/src/Discord.Net/Models/Channel.cs +++ b/src/Discord.Net/Models/Channel.cs @@ -9,14 +9,24 @@ namespace Discord { public sealed class PermissionOverwrite { - public string Type { get; internal set; } - public string Id { get; internal set; } - public PackedChannelPermissions Deny { get; internal set; } - public PackedChannelPermissions Allow { get; internal set; } + public string Type { get; } + public string TargetId { get; } + public PackedChannelPermissions Allow { get; } + public PackedChannelPermissions Deny { get; } + + internal PermissionOverwrite(string type, string targetId, uint allow, uint deny) + { + Type = type; + TargetId = targetId; + Allow = new PackedChannelPermissions(allow); + Deny = new PackedChannelPermissions( deny); + Allow.Lock(); + Deny.Lock(); + } } private readonly DiscordClient _client; - private ConcurrentDictionary _messages; + private readonly ConcurrentDictionary _messages; internal bool _areMembersStale; /// Returns the unique identifier for this channel. @@ -27,13 +37,13 @@ namespace Discord public string Name { get { return !IsPrivate ? $"{_name}" : $"@{Recipient.Name}"; } internal set { _name = value; } } /// Returns the topic associated with this channel. - public string Topic { get; internal set; } + public string Topic { get; private set; } /// Returns the position of this channel in the channel list for this server. - public int Position { get; internal set; } + public int Position { get; private set; } /// Returns false is this is a public chat and true if this is a private chat with another user (see Recipient). public bool IsPrivate => ServerId == null; /// Returns the type of this channel (see ChannelTypes). - public string Type { get; internal set; } + public string Type { get; private set; } /// Returns the id of the server containing this channel. public string ServerId { get; } @@ -42,7 +52,7 @@ namespace Discord public Server Server => _client.Servers[ServerId]; /// For private chats, returns the Id of the target user, otherwise null. - public string RecipientId { get; internal set; } + public string RecipientId { get; set; } /// For private chats, returns the target user, otherwise null. [JsonIgnore] public User Recipient => _client.Users[RecipientId]; @@ -74,6 +84,7 @@ namespace Discord public IEnumerable Messages => _messages.Select(x => _client.Messages[x.Key]); /// 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 => _permissionOverwrites; @@ -85,6 +96,7 @@ namespace Discord RecipientId = recipientId; _messages = new ConcurrentDictionary(); _areMembersStale = true; + _permissionOverwrites = _initialPermissionsOverwrites; } internal void Update(API.ChannelReference model) @@ -105,16 +117,10 @@ namespace Discord if (model.PermissionOverwrites != null) { - _permissionOverwrites = model.PermissionOverwrites.Select(x => new PermissionOverwrite - { - Type = x.Type, - Id = x.Id, - Deny = new PackedChannelPermissions(true, x.Deny), - Allow = new PackedChannelPermissions(true, x.Allow) - }).ToArray(); + _permissionOverwrites = model.PermissionOverwrites + .Select(x => new PermissionOverwrite(x.Type, x.Id, x.Allow, x.Deny)) + .ToArray(); } - else - _permissionOverwrites = null; } public override string ToString() => Name; diff --git a/src/Discord.Net/Models/Invite.cs b/src/Discord.Net/Models/Invite.cs index 27c85d93a..1c523fc16 100644 --- a/src/Discord.Net/Models/Invite.cs +++ b/src/Discord.Net/Models/Invite.cs @@ -10,15 +10,15 @@ namespace Discord public string Id { get; } /// Time (in seconds) until the invite expires. Set to 0 to never expire. - public int MaxAge { get; internal set; } + public int MaxAge { get; private set; } /// The amount of times this invite has been used. - public int Uses { get; internal set; } + public int Uses { get; private set; } /// The max amount of times this invite may be used. - public int MaxUses { get; internal set; } + public int MaxUses { get; private set; } /// Returns true if this invite has been destroyed, or you are banned from that server. - public bool IsRevoked { get; internal set; } + public bool IsRevoked { get; private set; } /// If true, a user accepting this invite will be kicked from the server after closing their client. - public bool IsTemporary { get; internal set; } + public bool IsTemporary { get; private set; } /// Returns, if enabled, an alternative human-readable code for URLs. public string XkcdPass { get; } @@ -26,19 +26,19 @@ namespace Discord public string Url => API.Endpoints.InviteUrl(XkcdPass ?? Id); /// Returns the id of the user that created this invite. - public string InviterId { get; internal set; } + public string InviterId { get; private set; } /// Returns the user that created this invite. [JsonIgnore] public User Inviter => _client.Users[InviterId]; /// Returns the id of the server this invite is to. - public string ServerId { get; internal set; } + public string ServerId { get; } /// Returns the server this invite is to. [JsonIgnore] public Server Server => _client.Servers[ServerId]; /// Returns the id of the channel this invite is to. - public string ChannelId { get; internal set; } + public string ChannelId { get; private set; } /// Returns the channel this invite is to. [JsonIgnore] public Channel Channel => _client.Channels[ChannelId]; @@ -55,19 +55,25 @@ namespace Discord internal void Update(API.Invite model) { - ChannelId = model.Channel.Id; - InviterId = model.Inviter?.Id; - ServerId = model.Guild.Id; + if (model.Channel != null) + ChannelId = model.Channel.Id; + if (model.Inviter != null) + InviterId = model.Inviter.Id; } internal void Update(API.ExtendedInvite model) { Update(model as API.Invite); - IsRevoked = model.IsRevoked; - IsTemporary = model.IsTemporary; - MaxAge = model.MaxAge; - MaxUses = model.MaxUses; - Uses = model.Uses; + if (model.IsRevoked != null) + IsRevoked = model.IsRevoked.Value; + if (model.IsTemporary != null) + IsTemporary = model.IsTemporary.Value; + if (model.MaxAge != null) + MaxAge = model.MaxAge.Value; + if (model.MaxUses != null) + MaxUses = model.MaxUses.Value; + if (model.Uses != null) + Uses = model.Uses.Value; } } } diff --git a/src/Discord.Net/Models/Member.cs b/src/Discord.Net/Models/Member.cs index 63dd1ad28..26cf69cc5 100644 --- a/src/Discord.Net/Models/Member.cs +++ b/src/Discord.Net/Models/Member.cs @@ -12,30 +12,30 @@ namespace Discord private ConcurrentDictionary _permissions; /// Returns the name of this user on this server. - public string Name { get; internal set; } + public string Name { get; private set; } /// Returns a by-name unique identifier separating this user from others with the same name. - public string Discriminator { get; internal set; } + public string Discriminator { get; private set; } /// Returns the unique identifier for this user's current avatar. - public string AvatarId { get; internal set; } + public string AvatarId { get; private set; } /// Returns the URL to this user's current avatar. public string AvatarUrl => API.Endpoints.UserAvatar(UserId, AvatarId); /// Returns the datetime that this user joined this server. - public DateTime JoinedAt { get; internal set; } + public DateTime JoinedAt { get; private set; } - public bool IsMuted { get; internal set; } - public bool IsDeafened { get; internal set; } - public bool IsSelfMuted { get; internal set; } - public bool IsSelfDeafened { get; internal set; } - public bool IsSuppressed { get; internal set; } + public bool IsMuted { get; private set; } + public bool IsDeafened { get; private set; } + public bool IsSelfMuted { get; private set; } + public bool IsSelfDeafened { get; private set; } + public bool IsSuppressed { get; private set; } public bool IsSpeaking { get; internal set; } - public string SessionId { get; internal set; } - public string Token { get; internal set; } + public string SessionId { get; private set; } + public string Token { get; private set; } /// Returns the id for the game this user is currently playing. - public string GameId { get; internal set; } + public string GameId { get; private set; } /// Returns the current status for this user. - public string Status { get; internal set; } + public string Status { get; private set; } /// Returns the time this user last sent/edited a message, started typing or sent voice data in this server. public DateTime? LastActivityAt { get; private set; } /// Returns the time this user was last seen online in this server. @@ -50,11 +50,12 @@ namespace Discord [JsonIgnore] public Server Server => _client.Servers[ServerId]; - public string VoiceChannelId { get; internal set; } + public string VoiceChannelId { get; private set; } [JsonIgnore] public Channel VoiceChannel => _client.Channels[VoiceChannelId]; - public string[] RoleIds { get; internal set; } + private static readonly string[] _initialRoleIds = new string[0]; + public string[] RoleIds { get; private set; } [JsonIgnore] public IEnumerable Roles => RoleIds.Select(x => _client.Roles[x]); @@ -67,8 +68,9 @@ namespace Discord UserId = userId; ServerId = serverId; Status = UserStatus.Offline; + RoleIds = _initialRoleIds; _permissions = new ConcurrentDictionary(); - } + } public override string ToString() => UserId; @@ -100,11 +102,14 @@ namespace Discord internal void Update(API.ExtendedMemberInfo model) { Update(model as API.MemberInfo); - IsDeafened = model.IsDeafened; - IsMuted = model.IsMuted; + if (model.IsDeafened != null) + IsDeafened = model.IsDeafened.Value; + if (model.IsMuted != null) + IsMuted = model.IsMuted.Value; } internal void Update(API.PresenceMemberInfo model) { + //Allows null if (Status != model.Status) { Status = model.Status; @@ -115,17 +120,22 @@ namespace Discord } internal void Update(API.VoiceMemberInfo model) { - IsDeafened = model.IsDeafened; - IsMuted = model.IsMuted; - SessionId = model.SessionId; - Token = model.Token; - - VoiceChannelId = model.ChannelId; - if (model.IsSelfDeafened.HasValue) + if (model.IsDeafened != null) + IsDeafened = model.IsDeafened.Value; + if (model.IsMuted != null) + IsMuted = model.IsMuted.Value; + if (model.SessionId != null) + SessionId = model.SessionId; + if (model.Token != null) + Token = model.Token; + + if (model.ChannelId != null) + VoiceChannelId = model.ChannelId; + if (model.IsSelfDeafened != null) IsSelfDeafened = model.IsSelfDeafened.Value; - if (model.IsSelfMuted.HasValue) + if (model.IsSelfMuted != null) IsSelfMuted = model.IsSelfMuted.Value; - if (model.IsSuppressed.HasValue) + if (model.IsSuppressed != null) IsSuppressed = model.IsSuppressed.Value; } @@ -137,7 +147,9 @@ namespace Discord internal void AddChannel(string channelId) { - _permissions.TryAdd(channelId, new PackedChannelPermissions()); + var perms = new PackedChannelPermissions(); + perms.Lock(); + _permissions.TryAdd(channelId, perms); UpdatePermissions(channelId); } internal bool RemoveChannel(string channelId) @@ -171,13 +183,13 @@ namespace Discord foreach (var serverRole in Roles) newPermissions |= serverRole.Permissions.RawValue; - foreach (var denyRole in channelOverwrites.Where(x => x.Type == PermissionTarget.Role && x.Deny.RawValue != 0 && RoleIds.Contains(x.Id))) + foreach (var denyRole in channelOverwrites.Where(x => x.Type == PermissionTarget.Role && x.Deny.RawValue != 0 && RoleIds.Contains(x.TargetId))) newPermissions &= ~denyRole.Deny.RawValue; - foreach (var allowRole in channelOverwrites.Where(x => x.Type == PermissionTarget.Role && x.Allow.RawValue != 0 && RoleIds.Contains(x.Id))) + foreach (var allowRole in channelOverwrites.Where(x => x.Type == PermissionTarget.Role && x.Allow.RawValue != 0 && RoleIds.Contains(x.TargetId))) newPermissions |= allowRole.Allow.RawValue; - foreach (var denyMembers in channelOverwrites.Where(x => x.Type == PermissionTarget.Member && x.Id == UserId && x.Deny.RawValue != 0)) + foreach (var denyMembers in channelOverwrites.Where(x => x.Type == PermissionTarget.Member && x.TargetId == UserId && x.Deny.RawValue != 0)) newPermissions &= ~denyMembers.Deny.RawValue; - foreach (var allowMembers in channelOverwrites.Where(x => x.Type == PermissionTarget.Member && x.Id == UserId && x.Allow.RawValue != 0)) + foreach (var allowMembers in channelOverwrites.Where(x => x.Type == PermissionTarget.Member && x.TargetId == UserId && x.Allow.RawValue != 0)) newPermissions |= allowMembers.Allow.RawValue; if (((newPermissions >> (PackedChannelPermissions.GlobalBit - 1)) & 1) == 1) diff --git a/src/Discord.Net/Models/Message.cs b/src/Discord.Net/Models/Message.cs index 2bd0a7a6b..147b5fb59 100644 --- a/src/Discord.Net/Models/Message.cs +++ b/src/Discord.Net/Models/Message.cs @@ -10,46 +10,84 @@ namespace Discord public sealed class Attachment : File { /// Unique identifier for this file. - public string Id { get; internal set; } + public string Id { get; } /// Size, in bytes, of this file file. - public int Size { get; internal set; } + public int Size { get; } /// Filename of this file. - public string Filename { get; internal set; } + public string Filename { get; } + + internal Attachment(string id, string url, string proxyUrl, + int? width, int? height, int size, string filename) + : base(url, proxyUrl, width, height) + { + Id = id; + Size = size; + Filename = filename; + } } + public sealed class Embed { /// URL of this embed. - public string Url { get; internal set; } + public string Url { get; } /// Type of this embed. - public string Type { get; internal set; } + public string Type { get; } /// Title for this embed. - public string Title { get; internal set; } + public string Title { get; } /// Summary of this embed. - public string Description { get; internal set; } + public string Description { get; } /// Returns information about the author of this embed. - public EmbedReference Author { get; internal set; } + public EmbedReference Author { get; } /// Returns information about the providing website of this embed. - public EmbedReference Provider { get; internal set; } + public EmbedReference Provider { get; } /// Returns the thumbnail of this embed. - public File Thumbnail { get; internal set; } + public File Thumbnail { get; } + + internal Embed(string url, string type, string title, string description, + EmbedReference author, EmbedReference provider, File thumbnail) + { + Url = url; + Type = type; + Title = title; + Description = description; + Author = author; + Provider = provider; + Thumbnail = thumbnail; + } } + public sealed class EmbedReference { /// URL of this embed provider. - public string Url { get; internal set; } + public string Url { get; } /// Name of this embed provider. - public string Name { get; internal set; } + public string Name { get; } + + internal EmbedReference(string url, string name) + { + Url = url; + Name = name; + } } + public class File { /// Download url for this file. - public string Url { get; internal set; } + public string Url { get; } /// Preview url for this file. - public string ProxyUrl { get; internal set; } + public string ProxyUrl { get; } /// Width of the this file, if it is an image. - public int? Width { get; internal set; } + public int? Width { get; } /// Height of this file, if it is an image. - public int? Height { get; internal set; } + public int? Height { get; } + + internal File(string url, string proxyUrl, int? width, int? height) + { + Url = url; + ProxyUrl = proxyUrl; + Width = width; + Height = height; + } } private readonly DiscordClient _client; @@ -62,31 +100,34 @@ 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; internal set; } + public bool IsMentioningMe { get; private set; } /// Returns true if @everyone was mentioned by someone with permissions to do so. - public bool IsMentioningEveryone { get; internal set; } + public bool IsMentioningEveryone { get; private set; } /// Returns true if the message was sent as text-to-speech by someone with permissions to do so. - public bool IsTTS { get; internal set; } + public bool IsTTS { get; private set; } /// Returns true if the message is still in the outgoing message queue. public bool IsQueued { get; internal set; } /// Returns true if the message was rejected by the server. public bool HasFailed { get; internal set; } /// Returns the raw content of this message as it was received from the server.. - public string RawText { get; internal set; } + public string RawText { get; private set; } /// Returns the content of this message with any special references such as mentions converted. /// This value is lazy loaded and only processed on first request. Each subsequent request will pull from cache. public string Text => _cleanText != null ? _cleanText : (_cleanText = _client.Messages.CleanText(RawText)); /// Returns the timestamp for when this message was sent. - public DateTime Timestamp { get; internal set; } + public DateTime Timestamp { get; private set; } /// Returns the timestamp for when this message was last edited. - public DateTime? EditedTimestamp { get; internal set; } + public DateTime? EditedTimestamp { get; private set; } /// Returns the attachments included in this message. - public Attachment[] Attachments { get; internal set; } + public Attachment[] Attachments { get; private set; } + private static readonly Attachment[] _initialAttachments = new Attachment[0]; /// Returns a collection of all embeded content in this message. - public Embed[] Embeds { get; internal set; } + public Embed[] Embeds { get; private set; } + private static readonly Embed[] _initialEmbeds = new Embed[0]; + private static readonly string[] _initialMentions = new string[0]; /// Returns a collection of all user ids mentioned in this message. - public string[] MentionIds { get; internal set; } + public string[] MentionIds { get; private set; } /// Returns a collection of all users mentioned in this message. [JsonIgnore] public IEnumerable Mentions => MentionIds.Select(x => _client.Users[x]).Where(x => x != null); @@ -106,7 +147,7 @@ namespace Discord /// Returns true if the current user created this message. public bool IsAuthor => _client.CurrentUserId == UserId; /// Returns the id of the author of this message. - public string UserId { get; internal set; } + public string UserId { get; } /// Returns the author of this message. [JsonIgnore] public User User => _client.Users[UserId]; @@ -120,77 +161,55 @@ namespace Discord Id = id; ChannelId = channelId; UserId = userId; - } + Attachments = _initialAttachments; + Embeds = _initialEmbeds; + MentionIds = _initialMentions; + } internal void Update(API.Message model) { if (model.Attachments != null) { - Attachments = model.Attachments.Select(x => new Attachment - { - Id = x.Id, - Url = x.Url, - ProxyUrl = x.ProxyUrl, - Size = x.Size, - Filename = x.Filename, - Width = x.Width, - Height = x.Height - }).ToArray(); + Attachments = model.Attachments + .Select(x => new Attachment(x.Id, x.Url, x.ProxyUrl, x.Width, x.Height, x.Size, x.Filename)) + .ToArray(); } - else - Attachments = new Attachment[0]; if (model.Embeds != null) { Embeds = model.Embeds.Select(x => { - var embed = new Embed - { - Url = x.Url, - Type = x.Type, - Description = x.Description, - Title = x.Title - }; - if (x.Provider != null) - { - embed.Provider = new EmbedReference - { - Url = x.Provider.Url, - Name = x.Provider.Name - }; - } + EmbedReference author = null, provider = null; + File thumbnail = null; + if (x.Author != null) - { - embed.Author = new EmbedReference - { - Url = x.Author.Url, - Name = x.Author.Name - }; - } + author = new EmbedReference(x.Author.Url, x.Author.Name); + if (x.Provider != null) + provider = new EmbedReference(x.Provider.Url, x.Provider.Name); if (x.Thumbnail != null) - { - embed.Thumbnail = new File - { - Url = x.Thumbnail.Url, - ProxyUrl = x.Thumbnail.ProxyUrl, - Width = x.Thumbnail.Width, - Height = x.Thumbnail.Height - }; - } - return embed; + thumbnail = new File(x.Thumbnail.Url, x.Thumbnail.ProxyUrl, x.Thumbnail.Width, x.Thumbnail.Height); + + return new Embed(x.Url, x.Type, x.Title, x.Description, author, provider, thumbnail); }).ToArray(); } - else - Embeds = new Embed[0]; - IsMentioningEveryone = model.IsMentioningEveryone; - IsTTS = model.IsTextToSpeech; - MentionIds = model.Mentions?.Select(x => x.Id)?.ToArray() ?? new string[0]; - IsMentioningMe = MentionIds.Contains(_client.CurrentUserId); - RawText = model.Content; - _cleanText = null; - Timestamp = model.Timestamp; - EditedTimestamp = model.EditedTimestamp; - if (model.Author != null) - UserId = model.Author.Id; + + if (model.IsMentioningEveryone != null) + IsMentioningEveryone = model.IsMentioningEveryone.Value; + if (model.IsTextToSpeech != null) + IsTTS = model.IsTextToSpeech.Value; + if (model.Timestamp != null) + Timestamp = model.Timestamp.Value; + if (model.EditedTimestamp != null) + EditedTimestamp = model.EditedTimestamp; + if (model.Mentions != null) + { + MentionIds = model.Mentions.Select(x => x.Id)?.ToArray(); + IsMentioningMe = MentionIds.Contains(_client.CurrentUserId); + } + if (model.Content != null) + { + RawText = model.Content; + _cleanText = null; + } } public override string ToString() => User.ToString() + ": " + RawText; diff --git a/src/Discord.Net/Models/PackedPermissions.cs b/src/Discord.Net/Models/PackedPermissions.cs index 7fcbe5200..8f1ea1e96 100644 --- a/src/Discord.Net/Models/PackedPermissions.cs +++ b/src/Discord.Net/Models/PackedPermissions.cs @@ -7,8 +7,7 @@ namespace Discord internal const int GlobalBit = 4; //ManagePermissions implicitly gives all permissions public static readonly uint Mask = Convert.ToUInt32("00000011111100111111110000111111", 2); - public PackedServerPermissions(uint rawValue = 0) : base(false, rawValue) { } - internal PackedServerPermissions(bool isLocked, uint rawValue) : base(isLocked, rawValue) { } + public PackedServerPermissions(uint rawValue = 0) : base(rawValue) { } /// If True, a user may ban users from the server. public bool General_BanMembers { get { return GetBit(2); } set { SetBit(2, value); } } @@ -21,7 +20,7 @@ namespace Discord /// If True, a user may adjust server properties. public bool General_ManageServer { get { return GetBit(6); } set { SetBit(6, value); } } - public PackedServerPermissions Copy() => new PackedServerPermissions(false, _rawValue); + public PackedServerPermissions Copy() => new PackedServerPermissions(RawValue); } public sealed class PackedChannelPermissions : PackedPermissions @@ -29,21 +28,20 @@ namespace Discord internal const int GlobalBit = 4; //ManagePermissions implicitly gives all permissions public static readonly uint Mask = Convert.ToUInt32("00000011111100111111110000011001", 2); - public PackedChannelPermissions(uint rawValue = 0) : base(false, rawValue) { } - internal PackedChannelPermissions(bool isLocked, uint rawValue) : base(isLocked, rawValue) { } + public PackedChannelPermissions(uint rawValue = 0) : base(rawValue) { } /// If True, a user may adjust permissions. This also implictly grants all other permissions. public bool General_ManagePermissions { get { return GetBit(4); } set { SetBit(4, value); } } /// If True, a user may create, delete and modify this channel. public bool General_ManageChannel { get { return GetBit(5); } set { SetBit(5, value); } } - public PackedChannelPermissions Copy() => new PackedChannelPermissions(false, _rawValue); + public PackedChannelPermissions Copy() => new PackedChannelPermissions(RawValue); } public abstract class PackedPermissions { private bool _isLocked; - protected uint _rawValue; + private uint _rawValue; public uint RawValue { get { return _rawValue; } @@ -55,7 +53,7 @@ namespace Discord } } - protected PackedPermissions(bool isLocked, uint rawValue) { _isLocked = isLocked; _rawValue = rawValue; } + protected PackedPermissions(uint rawValue) { _rawValue = rawValue; } /// If True, a user may create invites. public bool General_CreateInstantInvite { get { return GetBit(1); } set { SetBit(1, value); } } @@ -101,6 +99,7 @@ namespace Discord //6 Unused + internal void Lock() => _isLocked = true; internal void SetRawValue(uint rawValue) { //Bypasses isLocked for API changes. diff --git a/src/Discord.Net/Models/Role.cs b/src/Discord.Net/Models/Role.cs index 4114b4ee7..3fa473f1c 100644 --- a/src/Discord.Net/Models/Role.cs +++ b/src/Discord.Net/Models/Role.cs @@ -11,7 +11,7 @@ namespace Discord /// Returns the unique identifier for this role. public string Id { get; } /// Returns the name of this role. - public string Name { get; internal set; } + public string Name { get; private set; } /// Returns the the permissions contained by this role. public PackedServerPermissions Permissions { get; } @@ -25,16 +25,17 @@ namespace Discord /// Returns true if this is the role representing all users in a server. public bool IsEveryone { get; } /// Returns a list of the ids of all members in this role. - public IEnumerable MemberIds { get { return IsEveryone ? Server.UserIds : Server.Members.Where(x => x.RoleIds.Contains(Id)).Select(x => x.UserId); } } + public IEnumerable MemberIds => IsEveryone ? Server.UserIds : Server.Members.Where(x => x.RoleIds.Contains(Id)).Select(x => x.UserId); /// Returns a list of all members in this role. - public IEnumerable Members { get { return IsEveryone ? Server.Members : Server.Members.Where(x => x.RoleIds.Contains(Id)); } } + public IEnumerable Members => IsEveryone ? Server.Members : Server.Members.Where(x => x.RoleIds.Contains(Id)); internal Role(DiscordClient client, string id, string serverId, bool isEveryone) { _client = client; Id = id; ServerId = serverId; - Permissions = new PackedServerPermissions(true, 0); + Permissions = new PackedServerPermissions(0); + Permissions.Lock(); IsEveryone = isEveryone; } diff --git a/src/Discord.Net/Models/Server.cs b/src/Discord.Net/Models/Server.cs index 80e06a973..2f5de753c 100644 --- a/src/Discord.Net/Models/Server.cs +++ b/src/Discord.Net/Models/Server.cs @@ -9,34 +9,34 @@ namespace Discord public sealed class Server { private readonly DiscordClient _client; - private ConcurrentDictionary _bans, _channels, _invites, _members, _roles; + private readonly ConcurrentDictionary _bans, _channels, _invites, _members, _roles; /// Returns the unique identifier for this server. public string Id { get; } /// Returns the name of this channel. - public string Name { get; internal set; } + public string Name { get; private set; } /// Returns the current logged-in user's data for this server. public Member CurrentMember { get; internal set; } /// Returns the amount of time (in seconds) a user must be inactive for until they are automatically moved to the AFK channel (see AFKChannel). - public int AFKTimeout { get; internal set; } + public int AFKTimeout { get; private set; } /// Returns the date and time your joined this server. - public DateTime JoinedAt { get; internal set; } + public DateTime JoinedAt { get; private set; } /// Returns the region for this server (see Regions). - public string Region { get; internal set; } + public string Region { get; private set; } /*/// Returns the endpoint for this server's voice server. internal string VoiceServer { get; set; }*/ /// Returns true if the current user created this server. public bool IsOwner => _client.CurrentUserId == OwnerId; /// Returns the id of the user that first created this server. - public string OwnerId { get; internal set; } + public string OwnerId { get; private set; } /// Returns the user that first created this server. [JsonIgnore] public User Owner => _client.Users[OwnerId]; /// Returns the id of the AFK voice channel for this server (see AFKTimeout). - public string AFKChannelId { get; internal set; } + public string AFKChannelId { get; private set; } /// Returns the AFK voice channel for this server (see AFKTimeout). [JsonIgnore] public Channel AFKChannel => _client.Channels[AFKChannelId]; diff --git a/src/Discord.Net/Models/User.cs b/src/Discord.Net/Models/User.cs index 348a7ce30..d225c9b6d 100644 --- a/src/Discord.Net/Models/User.cs +++ b/src/Discord.Net/Models/User.cs @@ -10,32 +10,32 @@ namespace Discord public sealed class User { private readonly DiscordClient _client; - private int _refs; + private readonly ConcurrentDictionary _servers; + private int _refCount; private DateTime? _lastPrivateActivity; - private ConcurrentDictionary _servers; /// Returns the unique identifier for this user. public string Id { get; } /// Returns the name of this user on this server. - public string Name { get; internal set; } + public string Name { get; private set; } /// Returns a by-name unique identifier separating this user from others with the same name. - public string Discriminator { get; internal set; } + public string Discriminator { get; private set; } /// Returns the unique identifier for this user's current avatar. - public string AvatarId { get; internal set; } + public string AvatarId { get; private set; } /// Returns the URL to this user's current avatar. public string AvatarUrl => API.Endpoints.UserAvatar(Id, AvatarId); /// Returns the email for this user. /// This field is only ever populated for the current logged in user. [JsonIgnore] - public string Email { get; internal set; } + public string Email { get; private set; } /// Returns if the email for this user has been verified. /// This field is only ever populated for the current logged in user. [JsonIgnore] - public bool? IsVerified { get; internal set; } + public bool? IsVerified { get; private set; } /// Returns the Id of the private messaging channel with this user, if one exists. - public string PrivateChannelId { get; set; } + public string PrivateChannelId { get; internal set; } /// Returns the private messaging channel with this user, if one exists. [JsonIgnore] public Channel PrivateChannel => _client.Channels[PrivateChannelId]; @@ -112,11 +112,11 @@ namespace Discord public void AddRef() { - Interlocked.Increment(ref _refs); + Interlocked.Increment(ref _refCount); } public void RemoveRef() { - if (Interlocked.Decrement(ref _refs) == 0) + if (Interlocked.Decrement(ref _refCount) == 0) _client.Users.TryRemove(Id); } }