diff --git a/src/Discord.Net/API/Servers.cs b/src/Discord.Net/API/Servers.cs index 8abea6fca..16970b91e 100644 --- a/src/Discord.Net/API/Servers.cs +++ b/src/Discord.Net/API/Servers.cs @@ -20,7 +20,7 @@ namespace Discord.API [JsonProperty("afk_channel_id")] public string AFKChannelId; [JsonProperty("afk_timeout")] - public int AFKTimeout; + public int? AFKTimeout; [JsonProperty("embed_channel_id")] public string EmbedChannelId; [JsonProperty("embed_enabled")] diff --git a/src/Discord.Net/DiscordClient.Roles.cs b/src/Discord.Net/DiscordClient.Roles.cs index eb431c788..45294808c 100644 --- a/src/Discord.Net/DiscordClient.Roles.cs +++ b/src/Discord.Net/DiscordClient.Roles.cs @@ -7,9 +7,25 @@ namespace Discord { internal sealed class Roles : AsyncCollection { + private const string VirtualEveryoneId = "[Virtual]"; + public Role VirtualEveryone { get; private set; } + public Roles(DiscordClient client, object writerLock) : base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } + internal Role CreateVirtualRole(string serverId, string name) + { + var role = new Role(_client, serverId, serverId); + _dictionary[serverId] = role; + role.Update(new API.RoleInfo + { + Id = serverId, + Name = name, + Permissions = ChannelPermissions.None.RawValue + }); + return role; + } + public Role GetOrAdd(string id, string serverId) => GetOrAdd(id, () => new Role(_client, id, serverId)); } diff --git a/src/Discord.Net/DiscordClient.Servers.cs b/src/Discord.Net/DiscordClient.Servers.cs index 5686b2c39..15ac58476 100644 --- a/src/Discord.Net/DiscordClient.Servers.cs +++ b/src/Discord.Net/DiscordClient.Servers.cs @@ -8,8 +8,6 @@ namespace Discord { internal sealed class Servers : AsyncCollection { - private const string PMServerId = "Private"; - public Server PMServer { get; private set; } public Servers(DiscordClient client, object writerLock) @@ -17,9 +15,27 @@ namespace Discord protected override void Initialize() { - PMServer = new Server(_client, PMServerId) { IsVirtual = true }; - PMServer.Update(new API.ExtendedGuildInfo { Id = PMServerId, Name = PMServerId }); - _dictionary[PMServerId] = PMServer; + PMServer = CreateVirtualServer("Private"); + } + + private Server CreateVirtualServer(string name) + { + string id = $"[{name}]"; + var server = new Server(_client, id) { IsVirtual = true }; + _dictionary[id] = server; + + var everyone = _client.Roles.CreateVirtualRole(id, "@everyone"); + server.Update(new API.GuildInfo + { + Id = id, + Name = id, + JoinedAt = DateTime.UtcNow, + Roles = new API.RoleInfo[] { new API.RoleInfo { + Id = everyone.Id, + Name = everyone.Name + } } + }); + return server; } public Server GetOrAdd(string id) diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index e77ff0f33..fed585bd0 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -42,6 +42,14 @@ namespace Discord _roles = new Roles(this, cacheLock); _servers = new Servers(this, cacheLock); _users = new Users(this, cacheLock); + + _channels.Clear(); + _members.Clear(); + _messages.Clear(); + _roles.Clear(); + _servers.Clear(); + _users.Clear(); + _status = UserStatus.Online; this.Connected += async (s, e) => diff --git a/src/Discord.Net/Models/AsyncCollection.cs b/src/Discord.Net/Models/AsyncCollection.cs index 69019f780..3ae26a0a5 100644 --- a/src/Discord.Net/Models/AsyncCollection.cs +++ b/src/Discord.Net/Models/AsyncCollection.cs @@ -61,7 +61,6 @@ namespace Discord _dictionary = new ConcurrentDictionary(); _onCache = onCache; _onUncache = onUncache; - Initialize(); } protected virtual void Initialize() { } diff --git a/src/Discord.Net/Models/Channel.cs b/src/Discord.Net/Models/Channel.cs index 772e8b51e..5d034ff38 100644 --- a/src/Discord.Net/Models/Channel.cs +++ b/src/Discord.Net/Models/Channel.cs @@ -44,7 +44,7 @@ namespace Discord /// Returns the position of this channel in the channel list for this server. 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; + public bool IsPrivate => RecipientId != null; /// Returns the type of this channel (see ChannelTypes). public string Type { get; private set; } @@ -108,15 +108,31 @@ namespace Discord var server = Server; if (server != null) server.AddChannel(Id); - if (RecipientId != null) + if (IsPrivate) { var user = Recipient; if (user != null) { + Name = "@" + user.Name; user.PrivateChannelId = Id; user.AddRef(); _hasRef = true; } + else + Name = "@" + RecipientId; + var member = _client.Members.GetOrAdd(RecipientId, ServerId); + member.Update(new ExtendedMemberInfo + { + GuildId = ServerId, + UserId = RecipientId, + JoinedAt = DateTime.UtcNow, + Roles = new string[0] + }); + _permissionOverwrites = new PermissionOverwrite[] + { + new PermissionOverwrite(PermissionTarget.Member, _client.CurrentUserId, ChannelPermissions.AllPrivate.RawValue, 0), + new PermissionOverwrite(PermissionTarget.Member, RecipientId, ChannelPermissions.AllPrivate.RawValue, 0) + }; } } internal void OnUncached() @@ -124,7 +140,7 @@ namespace Discord var server = Server; if (server != null) server.RemoveChannel(Id); - if (RecipientId != null) + if (IsPrivate) { var user = Recipient; if (user != null) @@ -133,13 +149,14 @@ namespace Discord if (_hasRef) user.RemoveRef(); } - } + _client.Members.TryRemove(RecipientId, ServerId); + } _hasRef = false; } internal void Update(ChannelReference model) { - if (model.Name != null) + if (!IsPrivate && model.Name != null) Name = model.Name; if (model.Type != null) Type = model.Type; diff --git a/src/Discord.Net/Models/Member.cs b/src/Discord.Net/Models/Member.cs index fab2c9c63..8cd7cb182 100644 --- a/src/Discord.Net/Models/Member.cs +++ b/src/Discord.Net/Models/Member.cs @@ -217,7 +217,7 @@ namespace Discord uint oldPermissions = permissions.RawValue; if (UserId == server.OwnerId) - newPermissions = ChannelPermissions.All.RawValue; + newPermissions = ChannelPermissions.All(channel).RawValue; else { if (channel == null) return; @@ -240,7 +240,7 @@ namespace Discord permissions.SetRawValueInternal(newPermissions); if (permissions.General_ManagePermissions) - permissions.SetRawValueInternal(ChannelPermissions.All.RawValue); + permissions.SetRawValueInternal(ChannelPermissions.All(channel).RawValue); /*else if (server.DefaultChannelId == channelId) permissions.SetBitInternal(PackedPermissions.Text_ReadMessagesBit, true);*/ diff --git a/src/Discord.Net/Models/Permissions.cs b/src/Discord.Net/Models/Permissions.cs index 64efeebaf..43acc9f07 100644 --- a/src/Discord.Net/Models/Permissions.cs +++ b/src/Discord.Net/Models/Permissions.cs @@ -4,14 +4,16 @@ namespace Discord { public sealed class ServerPermissions : Permissions { - public static ServerPermissions None { get; } - public static ServerPermissions All { get; } + private static readonly ServerPermissions _none, _all; + public static ServerPermissions None => _none; + public static ServerPermissions All => _all; + static ServerPermissions() { - None = new ServerPermissions(); - None.Lock(); - All = new ServerPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); - All.Lock(); + _none = new ServerPermissions(); + _none.Lock(); + _all = new ServerPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); + _all.Lock(); } public ServerPermissions(uint rawValue = 0) : base(rawValue) { } @@ -32,15 +34,38 @@ namespace Discord public sealed class ChannelPermissions : Permissions { - public static ChannelPermissions None { get; } - public static ChannelPermissions All { get; } + private static readonly ChannelPermissions _none, _all, _allText, _allVoice, _allPM; + public static ChannelPermissions None => _none; + public static ChannelPermissions AllMask => _all; + public static ChannelPermissions AllText => _allText; + public static ChannelPermissions AllVoice => _allVoice; + public static ChannelPermissions AllPrivate => _allPM; + static ChannelPermissions() { - None = new ChannelPermissions(); - None.Lock(); - All = new ChannelPermissions(Convert.ToUInt32("00000011111100111111110000011001", 2)); - All.Lock(); - } + _none = new ChannelPermissions(); + _none.Lock(); + _all = new ChannelPermissions(Convert.ToUInt32("00000011111100111111110000011001", 2)); + _all.Lock(); + _allText = new ChannelPermissions(Convert.ToUInt32("00000000000000111111110000011001", 2)); + _allText.Lock(); + _allVoice = new ChannelPermissions(Convert.ToUInt32("00000011111100000000000000011001", 2)); + _allVoice.Lock(); + _allPM = new ChannelPermissions(Convert.ToUInt32("00000000000000011100110000000000", 2)); + _allPM.Lock(); + } + + public static ChannelPermissions All(Channel channel) + { + if (channel.IsPrivate) + return _allPM; + else if (channel.Type == ChannelTypes.Text) + return _allText; + else if (channel.Type == ChannelTypes.Voice) + return _allText; + else + return _none; + } public ChannelPermissions(uint rawValue = 0) : base(rawValue) { } diff --git a/src/Discord.Net/Models/Server.cs b/src/Discord.Net/Models/Server.cs index c1d50a2e9..e47bd6fef 100644 --- a/src/Discord.Net/Models/Server.cs +++ b/src/Discord.Net/Models/Server.cs @@ -126,19 +126,28 @@ namespace Discord internal void Update(GuildInfo model) { + //Can be null AFKChannelId = model.AFKChannelId; - AFKTimeout = model.AFKTimeout; - if (model.JoinedAt.HasValue) + + if (model.AFKTimeout != null) + AFKTimeout = model.AFKTimeout.Value; + if (model.JoinedAt != null) JoinedAt = model.JoinedAt.Value; - Name = model.Name; - OwnerId = model.OwnerId; - Region = model.Region; + if (model.Name != null) + Name = model.Name; + if (model.OwnerId != null) + OwnerId = model.OwnerId; + if (model.Region != null) + Region = model.Region; - var roles = _client.Roles; - foreach (var subModel in model.Roles) + if (model.Roles != null) { - var role = roles.GetOrAdd(subModel.Id, Id); - role.Update(subModel); + var roles = _client.Roles; + foreach (var subModel in model.Roles) + { + var role = roles.GetOrAdd(subModel.Id, Id); + role.Update(subModel); + } } } internal void Update(ExtendedGuildInfo model)