@@ -20,7 +20,7 @@ namespace Discord.API | |||||
[JsonProperty("afk_channel_id")] | [JsonProperty("afk_channel_id")] | ||||
public string AFKChannelId; | public string AFKChannelId; | ||||
[JsonProperty("afk_timeout")] | [JsonProperty("afk_timeout")] | ||||
public int AFKTimeout; | |||||
public int? AFKTimeout; | |||||
[JsonProperty("embed_channel_id")] | [JsonProperty("embed_channel_id")] | ||||
public string EmbedChannelId; | public string EmbedChannelId; | ||||
[JsonProperty("embed_enabled")] | [JsonProperty("embed_enabled")] | ||||
@@ -7,9 +7,25 @@ namespace Discord | |||||
{ | { | ||||
internal sealed class Roles : AsyncCollection<Role> | internal sealed class Roles : AsyncCollection<Role> | ||||
{ | { | ||||
private const string VirtualEveryoneId = "[Virtual]"; | |||||
public Role VirtualEveryone { get; private set; } | |||||
public Roles(DiscordClient client, object writerLock) | public Roles(DiscordClient client, object writerLock) | ||||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | : 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) | public Role GetOrAdd(string id, string serverId) | ||||
=> GetOrAdd(id, () => new Role(_client, id, serverId)); | => GetOrAdd(id, () => new Role(_client, id, serverId)); | ||||
} | } | ||||
@@ -8,8 +8,6 @@ namespace Discord | |||||
{ | { | ||||
internal sealed class Servers : AsyncCollection<Server> | internal sealed class Servers : AsyncCollection<Server> | ||||
{ | { | ||||
private const string PMServerId = "Private"; | |||||
public Server PMServer { get; private set; } | public Server PMServer { get; private set; } | ||||
public Servers(DiscordClient client, object writerLock) | public Servers(DiscordClient client, object writerLock) | ||||
@@ -17,9 +15,27 @@ namespace Discord | |||||
protected override void Initialize() | 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) | public Server GetOrAdd(string id) | ||||
@@ -42,6 +42,14 @@ namespace Discord | |||||
_roles = new Roles(this, cacheLock); | _roles = new Roles(this, cacheLock); | ||||
_servers = new Servers(this, cacheLock); | _servers = new Servers(this, cacheLock); | ||||
_users = new Users(this, cacheLock); | _users = new Users(this, cacheLock); | ||||
_channels.Clear(); | |||||
_members.Clear(); | |||||
_messages.Clear(); | |||||
_roles.Clear(); | |||||
_servers.Clear(); | |||||
_users.Clear(); | |||||
_status = UserStatus.Online; | _status = UserStatus.Online; | ||||
this.Connected += async (s, e) => | this.Connected += async (s, e) => | ||||
@@ -61,7 +61,6 @@ namespace Discord | |||||
_dictionary = new ConcurrentDictionary<string, TValue>(); | _dictionary = new ConcurrentDictionary<string, TValue>(); | ||||
_onCache = onCache; | _onCache = onCache; | ||||
_onUncache = onUncache; | _onUncache = onUncache; | ||||
Initialize(); | |||||
} | } | ||||
protected virtual void Initialize() { } | protected virtual void Initialize() { } | ||||
@@ -44,7 +44,7 @@ namespace Discord | |||||
/// <summary> Returns the position of this channel in the channel list for this server. </summary> | /// <summary> Returns the position of this channel in the channel list for this server. </summary> | ||||
public int Position { get; private set; } | public int Position { get; private set; } | ||||
/// <summary> Returns false is this is a public chat and true if this is a private chat with another user (see Recipient). </summary> | /// <summary> Returns false is this is a public chat and true if this is a private chat with another user (see Recipient). </summary> | ||||
public bool IsPrivate => ServerId == null; | |||||
public bool IsPrivate => RecipientId != null; | |||||
/// <summary> Returns the type of this channel (see ChannelTypes). </summary> | /// <summary> Returns the type of this channel (see ChannelTypes). </summary> | ||||
public string Type { get; private set; } | public string Type { get; private set; } | ||||
@@ -108,15 +108,31 @@ namespace Discord | |||||
var server = Server; | var server = Server; | ||||
if (server != null) | if (server != null) | ||||
server.AddChannel(Id); | server.AddChannel(Id); | ||||
if (RecipientId != null) | |||||
if (IsPrivate) | |||||
{ | { | ||||
var user = Recipient; | var user = Recipient; | ||||
if (user != null) | if (user != null) | ||||
{ | { | ||||
Name = "@" + user.Name; | |||||
user.PrivateChannelId = Id; | user.PrivateChannelId = Id; | ||||
user.AddRef(); | user.AddRef(); | ||||
_hasRef = true; | _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() | internal void OnUncached() | ||||
@@ -124,7 +140,7 @@ namespace Discord | |||||
var server = Server; | var server = Server; | ||||
if (server != null) | if (server != null) | ||||
server.RemoveChannel(Id); | server.RemoveChannel(Id); | ||||
if (RecipientId != null) | |||||
if (IsPrivate) | |||||
{ | { | ||||
var user = Recipient; | var user = Recipient; | ||||
if (user != null) | if (user != null) | ||||
@@ -133,13 +149,14 @@ namespace Discord | |||||
if (_hasRef) | if (_hasRef) | ||||
user.RemoveRef(); | user.RemoveRef(); | ||||
} | } | ||||
} | |||||
_client.Members.TryRemove(RecipientId, ServerId); | |||||
} | |||||
_hasRef = false; | _hasRef = false; | ||||
} | } | ||||
internal void Update(ChannelReference model) | internal void Update(ChannelReference model) | ||||
{ | { | ||||
if (model.Name != null) | |||||
if (!IsPrivate && model.Name != null) | |||||
Name = model.Name; | Name = model.Name; | ||||
if (model.Type != null) | if (model.Type != null) | ||||
Type = model.Type; | Type = model.Type; | ||||
@@ -217,7 +217,7 @@ namespace Discord | |||||
uint oldPermissions = permissions.RawValue; | uint oldPermissions = permissions.RawValue; | ||||
if (UserId == server.OwnerId) | if (UserId == server.OwnerId) | ||||
newPermissions = ChannelPermissions.All.RawValue; | |||||
newPermissions = ChannelPermissions.All(channel).RawValue; | |||||
else | else | ||||
{ | { | ||||
if (channel == null) return; | if (channel == null) return; | ||||
@@ -240,7 +240,7 @@ namespace Discord | |||||
permissions.SetRawValueInternal(newPermissions); | permissions.SetRawValueInternal(newPermissions); | ||||
if (permissions.General_ManagePermissions) | if (permissions.General_ManagePermissions) | ||||
permissions.SetRawValueInternal(ChannelPermissions.All.RawValue); | |||||
permissions.SetRawValueInternal(ChannelPermissions.All(channel).RawValue); | |||||
/*else if (server.DefaultChannelId == channelId) | /*else if (server.DefaultChannelId == channelId) | ||||
permissions.SetBitInternal(PackedPermissions.Text_ReadMessagesBit, true);*/ | permissions.SetBitInternal(PackedPermissions.Text_ReadMessagesBit, true);*/ | ||||
@@ -4,14 +4,16 @@ namespace Discord | |||||
{ | { | ||||
public sealed class ServerPermissions : Permissions | 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() | 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) { } | public ServerPermissions(uint rawValue = 0) : base(rawValue) { } | ||||
@@ -32,15 +34,38 @@ namespace Discord | |||||
public sealed class ChannelPermissions : Permissions | 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() | 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) { } | public ChannelPermissions(uint rawValue = 0) : base(rawValue) { } | ||||
@@ -126,19 +126,28 @@ namespace Discord | |||||
internal void Update(GuildInfo model) | internal void Update(GuildInfo model) | ||||
{ | { | ||||
//Can be null | |||||
AFKChannelId = model.AFKChannelId; | 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; | 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) | internal void Update(ExtendedGuildInfo model) | ||||